Bug 877690 - Implement an API for getting CSS property values to be used in auto-completion. r=bz
authorMina Almasry <almasry.mina@gmail.com>
Mon, 15 Jul 2013 17:28:49 -0400
changeset 146166 0cedd434dddb08547acc61ee6329e49c431f2bfa
parent 146165 8d0087957a1d303b26ae59aa7d4659c083cc14fc
child 146167 15f404e6da965a617710271772c14bee39163cbd
push idunknown
push userunknown
push dateunknown
reviewersbz
bugs877690
milestone25.0a1
Bug 877690 - Implement an API for getting CSS property values to be used in auto-completion. r=bz
gfx/src/nsColor.cpp
gfx/src/nsColor.h
layout/inspector/public/inIDOMUtils.idl
layout/inspector/src/inDOMUtils.cpp
layout/inspector/tests/Makefile.in
layout/inspector/tests/test_bug877690.html
layout/style/nsCSSParser.cpp
layout/style/nsCSSProps.h
--- a/gfx/src/nsColor.cpp
+++ b/gfx/src/nsColor.cpp
@@ -212,16 +212,24 @@ NS_GFX_(bool) NS_ColorNameToRGB(const ns
     if (aResult) {
       *aResult = kColors[id];
     }
     return true;
   }
   return false;
 }
 
+// Returns kColorNames, an array of all possible color names, and sets
+// *aSizeArray to the size of that array. Do NOT call free() on this array.
+NS_GFX_(const char * const *) NS_AllColorNames(size_t *aSizeArray)
+{
+  *aSizeArray = ArrayLength(kColorNames);
+  return kColorNames;
+}
+
 // Macro to blend two colors
 //
 // equivalent to target = (bg*(255-fgalpha) + fg*fgalpha)/255
 #define MOZ_BLEND(target, bg, fg, fgalpha)       \
   FAST_DIVIDE_BY_255(target, (bg)*(255-fgalpha) + (fg)*(fgalpha))
 
 NS_GFX_(nscolor)
 NS_ComposeColors(nscolor aBG, nscolor aFG)
--- a/gfx/src/nsColor.h
+++ b/gfx/src/nsColor.h
@@ -61,16 +61,20 @@ NS_GFX_(bool) NS_LooseHexToRGB(const nsS
 
 // There is no function to translate a color to a hex string, because
 // the hex-string syntax does not support transparency.
 
 // Translate a color name to a color. Return true if it parses ok,
 // otherwise return false.
 NS_GFX_(bool) NS_ColorNameToRGB(const nsAString& aBuf, nscolor* aResult);
 
+// Returns an array of all possible color names, and sets
+// *aSizeArray to the size of that array. Do NOT call |free()| on this array.
+NS_GFX_(const char * const *) NS_AllColorNames(size_t *aSizeArray);
+
 // function to convert from HSL color space to RGB color space
 // the float parameters are all expected to be in the range 0-1
 NS_GFX_(nscolor) NS_HSL2RGB(float h, float s, float l);
 
 // Return a color name for the given nscolor.  If there is no color
 // name for it, returns null.  If there are multiple possible color
 // names for the given color, the first one in nsColorNameList.h
 // (which is generally the first one in alphabetical order) will be
--- a/layout/inspector/public/inIDOMUtils.idl
+++ b/layout/inspector/public/inIDOMUtils.idl
@@ -11,17 +11,17 @@ interface nsIDOMElement;
 interface nsIDOMDocument;
 interface nsIDOMCSSStyleRule;
 interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMFontFaceList;
 interface nsIDOMRange;
 interface nsIDOMCSSStyleSheet;
 
-[scriptable, uuid(c10e5142-e936-45d7-ad5b-21a32ce739a3)]
+[scriptable, uuid(8705a686-d081-476c-89fa-cb6b70e9bb2e)]
 interface inIDOMUtils : nsISupports
 {
   // CSS utilities
   nsISupportsArray getCSSStyleRules(in nsIDOMElement aElement, [optional] in DOMString aPseudo);
   unsigned long getRuleLine(in nsIDOMCSSStyleRule aRule);
   unsigned long getRuleColumn(in nsIDOMCSSStyleRule aRule);
 
   // Utilities for working with selectors.  We don't have a JS OM representation
@@ -50,16 +50,21 @@ interface inIDOMUtils : nsISupports
   // Get a list of all our supported property names.  Optionally
   // shorthands can be excluded or property aliases included.
   const unsigned long EXCLUDE_SHORTHANDS = (1<<0);
   const unsigned long INCLUDE_ALIASES = (1<<1);
   void getCSSPropertyNames([optional] in unsigned long aFlags,
 			   [optional] out unsigned long aCount,
 			   [retval, array, size_is(aCount)] out wstring aProps);
 
+  // Get a list of all valid keywords and colors for aProperty.
+  void getCSSValuesForProperty(in AString aProperty,
+                               [optional] out unsigned long aLength,
+                               [array, size_is(aLength), retval] out wstring aValues);
+
   // Utilities for working with CSS colors
   [implicit_jscontext]
   jsval colorNameToRGB(in DOMString aColorName);
   AString rgbToColorName(in octet aR, in octet aG, in octet aB);
 
   // DOM Node utilities
   boolean isIgnorableWhitespace(in nsIDOMCharacterData aDataNode);
   // Returns the "parent" of a node.  The parent of a document node is the
--- a/layout/inspector/src/inDOMUtils.cpp
+++ b/layout/inspector/src/inDOMUtils.cpp
@@ -29,16 +29,18 @@
 #include "nsRange.h"
 #include "nsContentList.h"
 #include "mozilla/dom/Element.h"
 #include "nsCSSStyleSheet.h"
 #include "nsRuleWalker.h"
 #include "nsRuleProcessorData.h"
 #include "nsCSSRuleProcessor.h"
 #include "mozilla/dom/InspectorUtilsBinding.h"
+#include "nsCSSProps.h"
+#include "nsColor.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 
 ///////////////////////////////////////////////////////////////////////////////
 
 inDOMUtils::inDOMUtils()
@@ -417,16 +419,88 @@ inDOMUtils::GetCSSPropertyNames(uint32_t
 #undef DO_PROP
 
   *aCount = propCount;
   *aProps = props;
 
   return NS_OK;
 }
 
+static void GetKeywordsForProperty(const nsCSSProperty aProperty,
+                                   nsTArray<nsString>& aArray)
+{
+  if (nsCSSProps::IsShorthand(aProperty)) {
+    // Shorthand props have no keywords.
+    return;
+  }
+  const int32_t *keywordTable = nsCSSProps::kKeywordTableTable[aProperty];
+  if (keywordTable) {
+    size_t i = 0;
+    while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) {
+      nsCSSKeyword word = nsCSSKeyword(keywordTable[i]);
+      CopyASCIItoUTF16(nsCSSKeywords::GetStringValue(word),
+          *aArray.AppendElement());
+      // Increment counter by 2, because in this table every second
+      // element is a nsCSSKeyword.
+      i += 2;
+    }
+  }
+}
+
+static void GetColorsForProperty(const nsCSSProperty propertyID,
+                                 nsTArray<nsString>& aArray)
+{
+  uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID);
+  if (propertyParserVariant & VARIANT_COLOR) {
+    size_t size;
+    const char * const *allColorNames = NS_AllColorNames(&size);
+    for (size_t i = 0; i < size; i++) {
+      CopyASCIItoUTF16(allColorNames[i], *aArray.AppendElement());
+    }
+  }
+  return;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty,
+                                    uint32_t* aLength,
+                                    PRUnichar*** aValues)
+{
+  nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty,
+                                                        nsCSSProps::eEnabled);
+  if (propertyID == eCSSProperty_UNKNOWN) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsTArray<nsString> array;
+  // All CSS properties take initial and inherit.
+  array.AppendElement(NS_LITERAL_STRING("-moz-initial"));
+  array.AppendElement(NS_LITERAL_STRING("inherit"));
+  if (!nsCSSProps::IsShorthand(propertyID)) {
+    // Property is longhand.
+    GetKeywordsForProperty(propertyID, array);
+    GetColorsForProperty(propertyID, array);
+  } else {
+    // Property is shorthand.
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
+      GetKeywordsForProperty(*subproperty, array);
+      GetColorsForProperty(*subproperty, array);
+    }
+  }
+
+  *aLength = array.Length();
+  PRUnichar** ret =
+    static_cast<PRUnichar**>(NS_Alloc(*aLength * sizeof(PRUnichar*)));
+  for (uint32_t i = 0; i < *aLength; ++i) {
+    ret[i] = ToNewUnicode(array[i]);
+  }
+  *aValues = ret;
+  return NS_OK;
+}
+
 NS_IMETHODIMP
 inDOMUtils::ColorNameToRGB(const nsAString& aColorName, JSContext* aCx,
                            JS::Value* aValue)
 {
   nscolor color;
   if (!NS_ColorNameToRGB(aColorName, &color)) {
     return NS_ERROR_INVALID_ARG;
   }
--- a/layout/inspector/tests/Makefile.in
+++ b/layout/inspector/tests/Makefile.in
@@ -18,11 +18,12 @@ MOCHITEST_FILES =\
 		test_bug536379.html \
 		test_bug536379-2.html \
 		test_bug557726.html \
 		test_bug609549.xhtml \
 		test_bug806192.html \
 		test_bug856317.html \
 		bug856317.css \
 		test_isinheritableproperty.html \
+		test_bug877690.html \
 		$(NULL)
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/layout/inspector/tests/test_bug877690.html
@@ -0,0 +1,172 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=877690
+-->
+<head>
+<meta charset="utf-8">
+<title>Test for Bug 877690</title>
+<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+<script type="application/javascript">
+
+/** Test for Bug 877690 **/
+
+// Returns true if array contains item. False otherwise. Raises an exception if
+// array is not an Array object. If the item is found in array, remove item.
+function contains(array, item) {
+  if (!array.indexOf) {
+    throw new "First argument is not an array";
+  }
+  var index = array.indexOf(item);
+  if (index == -1) {
+    return false;
+  }
+  array.splice(index, 1);
+  return true;
+}
+
+// Returns true if values contains all and only the expected values. False otherwise.
+function testValues(values, expected) {
+  expected.forEach(function (expectedValue) {
+      if (!contains(values, expectedValue)) {
+        return false;
+      }
+  });
+  return values.length === 0;
+}
+
+function do_test() {
+  var utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
+    .getService(SpecialPowers.Ci.inIDOMUtils);
+
+  // test a property with keywords and colors
+  var prop = "color";
+  var values = utils.getCSSValuesForProperty(prop);
+  var expected = [ "-moz-initial", "inherit", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
+      "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood",
+      "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson",
+      "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey",
+      "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred",
+      "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey",
+      "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue",
+      "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold",
+      "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred",
+      "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
+      "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey",
+      "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey",
+      "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
+      "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen",
+      "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite",
+      "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen",
+      "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
+      "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen",
+      "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen",
+      "steelblue", "tan", "teal", "thistle", "tomato", "transparent", "turquoise", "violet", "wheat",
+      "white", "whitesmoke", "yellow", "yellowgreen" ];
+  ok(testValues(values, expected), "property color's values.");
+
+  // test a shorthand property
+  var prop = "background";
+  var values = utils.getCSSValuesForProperty(prop);
+  var expected = [ "-moz-initial", "inherit", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
+      "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue",
+      "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue",
+      "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
+      "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue",
+      "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray",
+      "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
+      "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred",
+      "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
+      "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink",
+      "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue",
+      "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue",
+      "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen",
+      "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
+      "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod",
+      "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum",
+      "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown",
+      "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey",
+      "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "transparent", "turquoise",
+      "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen", "no-repeat", "repeat",
+      "repeat-x", "repeat-y", "fixed", "scroll", "center", "top", "bottom", "left", "right",
+      "border-box", "padding-box", "content-box", "border-box", "padding-box", "content-box", "contain",
+      "cover" ];
+  ok(testValues(values, expected), "Shorthand proprety values.");
+
+  // test keywords only
+  var prop = "border-top";
+  var values = utils.getCSSValuesForProperty(prop);
+  var expected = [ "-moz-initial", "inherit", "thin", "medium", "thick", "none", "hidden", "dotted",
+      "dashed", "solid", "double", "groove", "ridge", "inset", "outset", "-moz-use-text-color",
+      "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black",
+      "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse",
+      "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
+      "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen",
+      "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
+      "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey",
+      "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
+      "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred",
+      "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
+      "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey",
+      "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey",
+      "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
+      "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen",
+      "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite",
+      "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen",
+      "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
+      "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell",
+      "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue",
+      "tan", "teal", "thistle", "tomato", "transparent", "turquoise", "violet", "wheat", "white", "whitesmoke",
+      "yellow", "yellowgreen" ];
+  ok(testValues(values, expected), "property border-top's values.");
+
+  // tests no keywords or colors
+  var prop = "padding-bottom";
+  var values = utils.getCSSValuesForProperty(prop);
+  var expected = [ "-moz-initial", "inherit" ];
+  ok(testValues(values, expected), "property padding-bottom's values.");
+
+  // test proprety
+  var prop = "display";
+  var values = utils.getCSSValuesForProperty(prop);
+  var expected = [ "-moz-initial", "inherit", "none", "inline", "block", "inline-block", "list-item",
+      "table", "inline-table", "table-row-group", "table-header-group", "table-footer-group", "table-row",
+      "table-column-group", "table-column", "table-cell", "table-caption", "-moz-box", "-moz-inline-box",
+      "-moz-grid", "-moz-inline-grid", "-moz-grid-group", "-moz-grid-line", "-moz-stack", "-moz-inline-stack",
+      "-moz-deck", "-moz-popup", "-moz-groupbox", "flex", "inline-flex" ];
+  ok(testValues(values, expected), "property display's values.");
+
+  // test property
+  var prop = "float";
+  var values = utils.getCSSValuesForProperty(prop);
+  var expected = [ "-moz-initial", "inherit", "none", "left", "right" ];
+  ok(testValues(values, expected), "proprety float values");
+
+  // test invalid property
+  var prop = "invalidProperty";
+  try {
+    utils.getCSSValuesForProperty(prop);
+    ok(false, "invalid property should throw an exception");
+  }
+  catch(e) {
+    // test passed
+  }
+
+  SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(do_test);
+
+</script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877690">Mozilla Bug 877690</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -40,106 +40,25 @@
 #include "nsContentUtils.h"
 #include "nsAutoPtr.h"
 #include "CSSCalc.h"
 #include "nsMediaFeatures.h"
 #include "nsLayoutUtils.h"
 
 using namespace mozilla;
 
-// Flags for ParseVariant method
-#define VARIANT_KEYWORD         0x000001  // K
-#define VARIANT_LENGTH          0x000002  // L
-#define VARIANT_PERCENT         0x000004  // P
-#define VARIANT_COLOR           0x000008  // C eCSSUnit_Color, eCSSUnit_Ident (e.g.  "red")
-#define VARIANT_URL             0x000010  // U
-#define VARIANT_NUMBER          0x000020  // N
-#define VARIANT_INTEGER         0x000040  // I
-#define VARIANT_ANGLE           0x000080  // G
-#define VARIANT_FREQUENCY       0x000100  // F
-#define VARIANT_TIME            0x000200  // T
-#define VARIANT_STRING          0x000400  // S
-#define VARIANT_COUNTER         0x000800  //
-#define VARIANT_ATTR            0x001000  //
-#define VARIANT_IDENTIFIER      0x002000  // D
-#define VARIANT_IDENTIFIER_NO_INHERIT 0x004000 // like above, but excluding
-                                               // 'inherit' and 'initial'
-#define VARIANT_AUTO            0x010000  // A
-#define VARIANT_INHERIT         0x020000  // H eCSSUnit_Initial, eCSSUnit_Inherit
-#define VARIANT_NONE            0x040000  // O
-#define VARIANT_NORMAL          0x080000  // M
-#define VARIANT_SYSFONT         0x100000  // eCSSUnit_System_Font
-#define VARIANT_GRADIENT        0x200000  // eCSSUnit_Gradient
-#define VARIANT_TIMING_FUNCTION 0x400000  // cubic-bezier() and steps()
-#define VARIANT_ALL             0x800000  //
-#define VARIANT_IMAGE_RECT    0x01000000  // eCSSUnit_Function
-// This is an extra bit that says that a VARIANT_ANGLE allows unitless zero:
-#define VARIANT_ZERO_ANGLE    0x02000000  // unitless zero for angles
-#define VARIANT_CALC          0x04000000  // eCSSUnit_Calc
-#define VARIANT_ELEMENT       0x08000000  // eCSSUnit_Element
-#define VARIANT_POSITIVE_DIMENSION 0x10000000 // Only lengths greater than 0.0
-#define VARIANT_NONNEGATIVE_DIMENSION 0x20000000 // Only lengths greater than or equal to 0.0
-
-// Common combinations of variants
-#define VARIANT_AL   (VARIANT_AUTO | VARIANT_LENGTH)
-#define VARIANT_LP   (VARIANT_LENGTH | VARIANT_PERCENT)
-#define VARIANT_LN   (VARIANT_LENGTH | VARIANT_NUMBER)
-#define VARIANT_AH   (VARIANT_AUTO | VARIANT_INHERIT)
-#define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
-#define VARIANT_AHI  (VARIANT_AH | VARIANT_INTEGER)
-#define VARIANT_AHK  (VARIANT_AH | VARIANT_KEYWORD)
-#define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
-#define VARIANT_AHL  (VARIANT_AH | VARIANT_LENGTH)
-#define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
-#define VARIANT_HK   (VARIANT_INHERIT | VARIANT_KEYWORD)
-#define VARIANT_HKF  (VARIANT_HK | VARIANT_FREQUENCY)
-#define VARIANT_HKI  (VARIANT_HK | VARIANT_INTEGER)
-#define VARIANT_HKL  (VARIANT_HK | VARIANT_LENGTH)
-#define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
-#define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
-#define VARIANT_HL   (VARIANT_INHERIT | VARIANT_LENGTH)
-#define VARIANT_HI   (VARIANT_INHERIT | VARIANT_INTEGER)
-#define VARIANT_HLP  (VARIANT_HL | VARIANT_PERCENT)
-#define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
-#define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
-#define VARIANT_HTP  (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
-#define VARIANT_HMK  (VARIANT_HK | VARIANT_NORMAL)
-#define VARIANT_HC   (VARIANT_INHERIT | VARIANT_COLOR)
-#define VARIANT_HCK  (VARIANT_HK | VARIANT_COLOR)
-#define VARIANT_HUK  (VARIANT_HK | VARIANT_URL)
-#define VARIANT_HUO  (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
-#define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
-#define VARIANT_HPN  (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
-#define VARIANT_PN   (VARIANT_PERCENT | VARIANT_NUMBER)
-#define VARIANT_ALPN (VARIANT_AL | VARIANT_PN)
-#define VARIANT_HN   (VARIANT_INHERIT | VARIANT_NUMBER)
-#define VARIANT_HON  (VARIANT_HN | VARIANT_NONE)
-#define VARIANT_HOS  (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
-#define VARIANT_LPN  (VARIANT_LP | VARIANT_NUMBER)
-#define VARIANT_UK   (VARIANT_URL | VARIANT_KEYWORD)
-#define VARIANT_UO   (VARIANT_URL | VARIANT_NONE)
-#define VARIANT_ANGLE_OR_ZERO (VARIANT_ANGLE | VARIANT_ZERO_ANGLE)
-#define VARIANT_LPCALC (VARIANT_LENGTH | VARIANT_CALC | VARIANT_PERCENT)
-#define VARIANT_LNCALC (VARIANT_LENGTH | VARIANT_CALC | VARIANT_NUMBER)
-#define VARIANT_LPNCALC (VARIANT_LNCALC | VARIANT_PERCENT)
-#define VARIANT_IMAGE (VARIANT_URL | VARIANT_NONE | VARIANT_GRADIENT | \
-                       VARIANT_IMAGE_RECT | VARIANT_ELEMENT)
-
-// This lives here because it depends on the above macros.
 const uint32_t
 nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
 #define CSS_PROP(name_, id_, method_, flags_, pref_, parsevariant_, kwtable_, \
                  stylestruct_, stylestructoffset_, animtype_)                 \
   parsevariant_,
 #include "nsCSSPropList.h"
 #undef CSS_PROP
 };
 
-//----------------------------------------------------------------------
-
 namespace {
 
 // Rule processing function
 typedef void (* RuleAppendFunc) (css::Rule* aRule, void* aData);
 static void AssignRuleToPointer(css::Rule* aRule, void* aPointer);
 static void AppendRuleToSheet(css::Rule* aRule, void* aParser);
 
 // Your basic top-down recursive descent style parser
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -12,16 +12,94 @@
 #define nsCSSProps_h___
 
 #include "nsString.h"
 #include "nsChangeHint.h"
 #include "nsCSSProperty.h"
 #include "nsStyleStruct.h"
 #include "nsCSSKeywords.h"
 
+// Flags for ParseVariant method
+#define VARIANT_KEYWORD         0x000001  // K
+#define VARIANT_LENGTH          0x000002  // L
+#define VARIANT_PERCENT         0x000004  // P
+#define VARIANT_COLOR           0x000008  // C eCSSUnit_Color, eCSSUnit_Ident (e.g.  "red")
+#define VARIANT_URL             0x000010  // U
+#define VARIANT_NUMBER          0x000020  // N
+#define VARIANT_INTEGER         0x000040  // I
+#define VARIANT_ANGLE           0x000080  // G
+#define VARIANT_FREQUENCY       0x000100  // F
+#define VARIANT_TIME            0x000200  // T
+#define VARIANT_STRING          0x000400  // S
+#define VARIANT_COUNTER         0x000800  //
+#define VARIANT_ATTR            0x001000  //
+#define VARIANT_IDENTIFIER      0x002000  // D
+#define VARIANT_IDENTIFIER_NO_INHERIT 0x004000 // like above, but excluding
+// 'inherit' and 'initial'
+#define VARIANT_AUTO            0x010000  // A
+#define VARIANT_INHERIT         0x020000  // H eCSSUnit_Initial, eCSSUnit_Inherit
+#define VARIANT_NONE            0x040000  // O
+#define VARIANT_NORMAL          0x080000  // M
+#define VARIANT_SYSFONT         0x100000  // eCSSUnit_System_Font
+#define VARIANT_GRADIENT        0x200000  // eCSSUnit_Gradient
+#define VARIANT_TIMING_FUNCTION 0x400000  // cubic-bezier() and steps()
+#define VARIANT_ALL             0x800000  //
+#define VARIANT_IMAGE_RECT    0x01000000  // eCSSUnit_Function
+// This is an extra bit that says that a VARIANT_ANGLE allows unitless zero:
+#define VARIANT_ZERO_ANGLE    0x02000000  // unitless zero for angles
+#define VARIANT_CALC          0x04000000  // eCSSUnit_Calc
+#define VARIANT_ELEMENT       0x08000000  // eCSSUnit_Element
+#define VARIANT_POSITIVE_DIMENSION 0x10000000 // Only lengths greater than 0.0
+#define VARIANT_NONNEGATIVE_DIMENSION 0x20000000 // Only lengths greater than or equal to 0.0
+
+// Common combinations of variants
+#define VARIANT_AL   (VARIANT_AUTO | VARIANT_LENGTH)
+#define VARIANT_LP   (VARIANT_LENGTH | VARIANT_PERCENT)
+#define VARIANT_LN   (VARIANT_LENGTH | VARIANT_NUMBER)
+#define VARIANT_AH   (VARIANT_AUTO | VARIANT_INHERIT)
+#define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
+#define VARIANT_AHI  (VARIANT_AH | VARIANT_INTEGER)
+#define VARIANT_AHK  (VARIANT_AH | VARIANT_KEYWORD)
+#define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
+#define VARIANT_AHL  (VARIANT_AH | VARIANT_LENGTH)
+#define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
+#define VARIANT_HK   (VARIANT_INHERIT | VARIANT_KEYWORD)
+#define VARIANT_HKF  (VARIANT_HK | VARIANT_FREQUENCY)
+#define VARIANT_HKI  (VARIANT_HK | VARIANT_INTEGER)
+#define VARIANT_HKL  (VARIANT_HK | VARIANT_LENGTH)
+#define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
+#define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
+#define VARIANT_HL   (VARIANT_INHERIT | VARIANT_LENGTH)
+#define VARIANT_HI   (VARIANT_INHERIT | VARIANT_INTEGER)
+#define VARIANT_HLP  (VARIANT_HL | VARIANT_PERCENT)
+#define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
+#define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
+#define VARIANT_HTP  (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
+#define VARIANT_HMK  (VARIANT_HK | VARIANT_NORMAL)
+#define VARIANT_HC   (VARIANT_INHERIT | VARIANT_COLOR)
+#define VARIANT_HCK  (VARIANT_HK | VARIANT_COLOR)
+#define VARIANT_HUK  (VARIANT_HK | VARIANT_URL)
+#define VARIANT_HUO  (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
+#define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
+#define VARIANT_HPN  (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
+#define VARIANT_PN   (VARIANT_PERCENT | VARIANT_NUMBER)
+#define VARIANT_ALPN (VARIANT_AL | VARIANT_PN)
+#define VARIANT_HN   (VARIANT_INHERIT | VARIANT_NUMBER)
+#define VARIANT_HON  (VARIANT_HN | VARIANT_NONE)
+#define VARIANT_HOS  (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
+#define VARIANT_LPN  (VARIANT_LP | VARIANT_NUMBER)
+#define VARIANT_UK   (VARIANT_URL | VARIANT_KEYWORD)
+#define VARIANT_UO   (VARIANT_URL | VARIANT_NONE)
+#define VARIANT_ANGLE_OR_ZERO (VARIANT_ANGLE | VARIANT_ZERO_ANGLE)
+#define VARIANT_LPCALC  (VARIANT_LENGTH | VARIANT_CALC | VARIANT_PERCENT)
+#define VARIANT_LNCALC  (VARIANT_LENGTH | VARIANT_CALC | VARIANT_NUMBER)
+#define VARIANT_LPNCALC (VARIANT_LNCALC | VARIANT_PERCENT)
+#define VARIANT_IMAGE   (VARIANT_URL | VARIANT_NONE | VARIANT_GRADIENT | \
+                        VARIANT_IMAGE_RECT | VARIANT_ELEMENT)
+
 // Flags for the kFlagsTable bitfield (flags_ in nsCSSPropList.h)
 
 // A property that is a *-ltr-source or *-rtl-source property for one of
 // the directional pseudo-shorthand properties.
 #define CSS_PROPERTY_DIRECTIONAL_SOURCE           (1<<0)
 
 #define CSS_PROPERTY_VALUE_LIST_USES_COMMAS       (1<<1) /* otherwise spaces */