Bug 1035106 - Add new APIs to DOMUtils: colorToRGBA, isValidCSSColor & cssPropertyIsValid r=bz
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Thu, 17 Jul 2014 15:08:07 +0100
changeset 216924 ed168e7e8b0c9b0ece0cc3e36c11d04f85f33e73
parent 216923 85d5040f1ad2bccff75bfeaf6912791bfca527f0
child 216925 fbedb66e0ebf2c70058aa7faed29a57a631c5528
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1035106
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1035106 - Add new APIs to DOMUtils: colorToRGBA, isValidCSSColor & cssPropertyIsValid r=bz
dom/webidl/InspectorUtils.webidl
layout/inspector/inDOMUtils.cpp
layout/inspector/inIDOMUtils.idl
layout/inspector/tests/mochitest.ini
layout/inspector/tests/test_color_to_rgba.html
layout/inspector/tests/test_css_property_is_valid.html
layout/inspector/tests/test_is_valid_css_color.html
layout/style/nsCSSParser.cpp
layout/style/nsCSSParser.h
--- a/dom/webidl/InspectorUtils.webidl
+++ b/dom/webidl/InspectorUtils.webidl
@@ -9,8 +9,21 @@ dictionary InspectorRGBTriple {
    * they can be outside the 0-255 range, but for backwards-compatible
    * named colors (which is what we use this dictionary for) the 0-255
    * assumption is fine.
    */
   octet r = 0;
   octet g = 0;
   octet b = 0;
 };
+
+dictionary InspectorRGBATuple {
+  /*
+   * NOTE: This tuple is in the normal 0-255-sized RGB space but can be
+   * fractional and may extend outside the 0-255 range.
+   *
+   * a is in the range 0 - 1.
+   */
+  double r = 0;
+  double g = 0;
+  double b = 0;
+  double a = 1;
+};
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -34,19 +34,22 @@
 #include "nsContentList.h"
 #include "mozilla/CSSStyleSheet.h"
 #include "mozilla/dom/Element.h"
 #include "nsRuleWalker.h"
 #include "nsRuleProcessorData.h"
 #include "nsCSSRuleProcessor.h"
 #include "mozilla/dom/InspectorUtilsBinding.h"
 #include "mozilla/dom/ToJSValue.h"
+#include "nsCSSParser.h"
 #include "nsCSSProps.h"
+#include "nsCSSValue.h"
 #include "nsColor.h"
 #include "nsStyleSet.h"
+#include "nsStyleUtil.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::dom;
 
 ///////////////////////////////////////////////////////////////////////////////
 
 inDOMUtils::inDOMUtils()
@@ -791,16 +794,76 @@ inDOMUtils::RgbToColorName(uint8_t aR, u
     return NS_ERROR_INVALID_ARG;
   }
 
   aColorName.AssignASCII(color);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+inDOMUtils::ColorToRGBA(const nsAString& aColorString, JSContext* aCx,
+                        JS::MutableHandle<JS::Value> aValue)
+{
+  nscolor color = 0;
+  nsCSSParser cssParser;
+  nsCSSValue cssValue;
+
+  bool isColor = cssParser.ParseColorString(aColorString, nullptr, 0,
+                                            cssValue, true);
+
+  if (!isColor) {
+    aValue.setNull();
+    return NS_OK;
+  }
+
+  nsRuleNode::ComputeColor(cssValue, nullptr, nullptr, color);
+
+  InspectorRGBATuple tuple;
+  tuple.mR = NS_GET_R(color);
+  tuple.mG = NS_GET_G(color);
+  tuple.mB = NS_GET_B(color);
+  tuple.mA = nsStyleUtil::ColorComponentToFloat(NS_GET_A(color));
+
+  if (!ToJSValue(aCx, tuple, aValue)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::IsValidCSSColor(const nsAString& aColorString, bool *_retval)
+{
+  nsCSSParser cssParser;
+  nsCSSValue cssValue;
+  *_retval = cssParser.ParseColorString(aColorString, nullptr, 0, cssValue, true);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::CssPropertyIsValid(const nsAString& aPropertyName,
+                               const nsAString& aPropertyValue,
+                               bool *_retval)
+{
+  nsCSSProperty propertyID =
+    nsCSSProps::LookupProperty(aPropertyName, nsCSSProps::eIgnoreEnabledState);
+
+  if (propertyID == eCSSProperty_UNKNOWN) {
+    *_retval = false;
+    return NS_OK;
+  }
+
+  // Get a parser, parse the property.
+  nsCSSParser parser;
+  *_retval = parser.IsValueValidForProperty(propertyID, aPropertyValue);
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval)
 {
   NS_ENSURE_ARG_POINTER(aElement);
 
   *_retval = nullptr;
 
   nsCOMPtr<nsIMutableArray> urls = do_CreateInstance(NS_ARRAY_CONTRACTID);
   if (!urls)
--- a/layout/inspector/inIDOMUtils.idl
+++ b/layout/inspector/inIDOMUtils.idl
@@ -12,17 +12,17 @@ interface nsIDOMDocument;
 interface nsIDOMCSSRule;
 interface nsIDOMCSSStyleRule;
 interface nsIDOMNode;
 interface nsIDOMNodeList;
 interface nsIDOMFontFaceList;
 interface nsIDOMRange;
 interface nsIDOMCSSStyleSheet;
 
-[scriptable, uuid(fd529e53-f734-4d15-83ce-d545a631d668)]
+[scriptable, uuid(bd6b3dee-b8dd-40c7-a40a-ad8455b49917)]
 interface inIDOMUtils : nsISupports
 {
   // CSS utilities
   void getAllStyleSheets (in nsIDOMDocument aDoc,
                           [optional] out unsigned long aLength,
                           [array, size_is (aLength), retval] out nsISupports aSheets);
   nsISupportsArray getCSSStyleRules(in nsIDOMElement aElement, [optional] in DOMString aPseudo);
   unsigned long getRuleLine(in nsIDOMCSSRule aRule);
@@ -64,18 +64,35 @@ interface inIDOMUtils : nsISupports
                                [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);
 
+  // Convert a given CSS color string to rgba. Returns null on failure or an
+  // InspectorRGBATuple on success.
+  //
+  // NOTE: Converting a color to RGBA may be lossy when converting from some
+  // formats e.g. CMYK.
+  [implicit_jscontext]
+  jsval colorToRGBA(in DOMString aColorString);
+
+  // Check whether a given color is a valid CSS color.
+  bool isValidCSSColor(in AString aColorString);
+
   // Utilities for obtaining information about a CSS property.
 
+  // Check whether a CSS property and value are a valid combination. If the
+  // property is pref-disabled it will still be processed.
+  // aPropertyName: A property name e.g. "color"
+  // aPropertyValue: A property value e.g. "red" or "red !important"
+  bool cssPropertyIsValid(in AString aPropertyName, in AString aPropertyValue);
+
   // Get a list of the longhands corresponding to the given CSS property.  If
   // the property is a longhand already, just returns the property itself.
   // Throws on unsupported property names.
   void getSubpropertiesForCSSProperty(in AString aProperty,
                                       [optional] out unsigned long aLength,
                                       [array, size_is(aLength), retval] out wstring aValues);
   // Check whether a given CSS property is a shorthand.  Throws on unsupported
   // property names.
--- a/layout/inspector/tests/mochitest.ini
+++ b/layout/inspector/tests/mochitest.ini
@@ -7,10 +7,13 @@ support-files = bug856317.css
 [test_bug536379-2.html]
 [test_bug536379.html]
 [test_bug557726.html]
 [test_bug609549.xhtml]
 [test_bug806192.html]
 [test_bug856317.html]
 [test_bug877690.html]
 [test_bug1006595.html]
+[test_color_to_rgba.html]
+[test_is_valid_css_color.html]
+[test_css_property_is_valid.html]
 [test_get_all_style_sheets.html]
 [test_isinheritableproperty.html]
new file mode 100644
--- /dev/null
+++ b/layout/inspector/tests/test_color_to_rgba.html
@@ -0,0 +1,50 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test inDOMUtils::ColorToRGBA</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;version=1.8">
+  let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
+                           .getService(SpecialPowers.Ci.inIDOMUtils);
+
+  testColor("red", {r:255, g:0, b:0, a:1});
+  testColor("#f00", {r:255, g:0, b:0, a:1});
+  testColor("#ff0000", {r:255, g:0, b:0, a:1});
+  testColor("ff0000", null);
+  testColor("rgb(255,0,0)", {r:255, g:0, b:0, a:1});
+  testColor("rgba(255,0,0,0.7)", {r:255, g:0, b:0, a:0.7});
+  testColor("rgb(255,0,0,0.7)", null);
+  testColor("rgb(50%,75%,60%)", {r:128, g:191, b:153, a:1});
+  testColor("rgba(100%,50%,25%,0.7)", {r:255, g:128, b:64, a:0.7});
+  testColor("hsl(320,30%,10%)", {r:33, g:17, b:28, a:1});
+  testColor("hsla(170,60%,40%,0.9)", {r:40, g:163, b:142, a:0.9});
+
+  function testColor(color, expected) {
+    let rgb = utils.colorToRGBA(color);
+
+    if (rgb === null) {
+      ok(expected === null, "color: " + color + " returns null");
+      return;
+    }
+
+    let {r, g, b, a} = rgb;
+
+    is(r, expected.r, "color: " + color + ", red component is converted correctly");
+    is(g, expected.g, "color: " + color + ", green component is converted correctly");
+    is(b, expected.b, "color: " + color + ", blue component is converted correctly");
+    is(Math.round(a * 10) / 10, expected.a, "color: " + color + ", alpha component is a converted correctly");
+  }
+  </script>
+</head>
+<body>
+<h1>Test inDOMUtils::ColorToRGBA</h1>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/inspector/tests/test_css_property_is_valid.html
@@ -0,0 +1,100 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test inDOMUtils::CssPropertyIsValid</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;version=1.8">
+  let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
+                           .getService(SpecialPowers.Ci.inIDOMUtils);
+
+  let tests = [
+    {
+      property: "color",
+      value: "red",
+      expected: true
+    },
+    {
+      property: "display",
+      value: "none",
+      expected: true
+    },
+    {
+      property: "display",
+      value: "red",
+      expected: false
+    },
+    {
+      property: "displayx",
+      value: "none",
+      expected: false
+    },
+    {
+      property: "border",
+      value: "1px solid blue",
+      expected: true
+    },
+    {
+      property: "border",
+      value: "1 solid blue",
+      expected: false
+    },
+    {
+      property: "border",
+      value: "1px underline blue",
+      expected: false
+    },
+    {
+      property: "border",
+      value: "1px solid",
+      expected: true
+    },
+    {
+      property: "color",
+      value: "blue !important",
+      expected: true
+    },
+    {
+      property: "color",
+      value: "blue ! important",
+      expected: true
+    },
+    {
+      property: "color",
+      value: "blue !impoxxxrtant",
+      expected: false
+    },
+    {
+      property: "color",
+      value: "red; background:green;",
+      expected: false
+    },
+    {
+      property: "content",
+      value: "\"hello\"",
+      expected: true
+    }
+  ];
+
+  for (let {property, value, expected} of tests) {
+    let valid = utils.cssPropertyIsValid(property, value);
+
+    if (expected) {
+      ok(valid, property + ":" + value + " is valid");
+    } else {
+      ok(!valid, property + ":" + value + " is not valid");
+    }
+  }
+  </script>
+</head>
+<body>
+<h1>Test inDOMUtils::CssPropertyIsValid</h1>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/inspector/tests/test_is_valid_css_color.html
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test inDOMUtils::isValidCSSColor</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;version=1.8">
+  let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
+                           .getService(SpecialPowers.Ci.inIDOMUtils);
+
+  // Color names
+  let colors = utils.getCSSValuesForProperty("color");
+  let notColor = ["hsl", "hsla", "inherit", "initial", "rgb", "rgba", "unset"];
+  for (let color of colors) {
+    if (notColor.indexOf(color) !== -1) {
+      continue;
+    }
+    ok(utils.isValidCSSColor(color), color + " is a valid color");
+    ok(!utils.isValidCSSColor("xxx" + color), "xxx" + color + " is not a valid color");
+  }
+
+  // rgb(a)
+  for (let i = 0; i <= 265; i++) {
+    ok(utils.isValidCSSColor("rgb(" + i + ",0,0)"), "rgb(" + i + ",0,0) is a valid color");
+    ok(utils.isValidCSSColor("rgb(0," + i + ",0)"), "rgb(0," + i + ",0) is a valid color");
+    ok(utils.isValidCSSColor("rgb(0,0," + i + ")"), "rgb(0,0," + i + ") is a valid color");
+    ok(utils.isValidCSSColor("rgba(" + i + ",0,0,0.2)"), "rgba(" + i + ",0,0,0.2) is a valid color");
+    ok(utils.isValidCSSColor("rgba(0," + i + ",0,0.5)"), "rgba(0," + i + ",0,0.5) is a valid color");
+    ok(utils.isValidCSSColor("rgba(0,0," + i + ",0.7)"), "rgba(0,0," + i + ",0.7) is a valid color");
+
+    ok(!utils.isValidCSSColor("rgbxxx(" + i + ",0,0)"), "rgbxxx(" + i + ",0,0) is not a valid color");
+    ok(!utils.isValidCSSColor("rgbxxx(0," + i + ",0)"), "rgbxxx(0," + i + ",0) is not a valid color");
+    ok(!utils.isValidCSSColor("rgbxxx(0,0," + i + ")"), "rgbxxx(0,0," + i + ") is not a valid color");
+  }
+
+  // rgb(a) (%)
+  for (let i = 0; i <= 110; i++) {
+    ok(utils.isValidCSSColor("rgb(" + i + "%,0%,0%)"), "rgb(" + i + "%,0%,0%) is a valid color");
+    ok(utils.isValidCSSColor("rgb(0%," + i + "%,0%)"), "rgb(0%," + i + "%,0%) is a valid color");
+    ok(utils.isValidCSSColor("rgb(0%,0%," + i + "%)"), "rgb(0%,0%," + i + "%) is a valid color");
+    ok(utils.isValidCSSColor("rgba(" + i + "%,0%,0%,0.2)"), "rgba(" + i + "%,0%,0%,0.2) is a valid color");
+    ok(utils.isValidCSSColor("rgba(0%," + i + "%,0%,0.5)"), "rgba(0%," + i + "%,0%,0.5) is a valid color");
+    ok(utils.isValidCSSColor("rgba(0%,0%," + i + "%,0.7)"), "rgba(0%,0%," + i + "%,0.7) is a valid color");
+
+    ok(!utils.isValidCSSColor("rgbaxxx(" + i + "%,0%,0%,0.2)"), "rgbaxxx(" + i + "%,0%,0%,0.2) is not a valid color");
+    ok(!utils.isValidCSSColor("rgbaxxx(0%," + i + "%,0%,0.5)"), "rgbaxxx(0%," + i + "%,0%,0.5) is not a valid color");
+    ok(!utils.isValidCSSColor("rgbaxxx(0%,0%," + i + "%,0.7)"), "rgbaxxx(0%,0%," + i + "%,0.7) is not a valid color");
+  }
+
+  // hsl(a)
+  for (let i = 0; i <= 370; i++) {
+    ok(utils.isValidCSSColor("hsl(" + i + ",30%,10%)"), "rgb(" + i + ",30%,10%) is a valid color");
+    ok(utils.isValidCSSColor("hsla(" + i + ",60%,70%,0.2)"), "rgba(" + i + ",60%,70%,0.2) is a valid color");
+  }
+  for (let i = 0; i <= 110; i++) {
+    ok(utils.isValidCSSColor("hsl(100," + i + "%,20%)"), "hsl(100," + i + "%,20%) is a valid color");
+    ok(utils.isValidCSSColor("hsla(100,20%," + i + "%,0.6)"), "hsla(100,20%," + i + "%,0.6) is a valid color");
+  }
+
+  // hex
+  for (let i = 0; i <= 255; i++) {
+    let hex = (i).toString(16);
+    if (hex.length === 1) {
+      hex = 0 + hex;
+    }
+    ok(utils.isValidCSSColor("#" + hex + "7777"), "#" + hex + "7777 is a valid color");
+    ok(utils.isValidCSSColor("#77" + hex + "77"), "#77" + hex + "77 is a valid color");
+    ok(utils.isValidCSSColor("#7777" + hex), "#7777" + hex + " is a valid color");
+  }
+  ok(!utils.isValidCSSColor("#kkkkkk"), "#kkkkkk is not a valid color");
+
+  // short hex
+  for (let i = 0; i <= 16; i++) {
+    let hex = (i).toString(16);
+    ok(utils.isValidCSSColor("#" + hex + hex + hex), "#" + hex + hex + hex + " is a valid color");
+  }
+  ok(!utils.isValidCSSColor("#ggg"), "#ggg is not a valid color");
+  </script>
+</head>
+<body>
+<h1>Test inDOMUtils::isValidCSSColor</h1>
+<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
@@ -172,17 +172,18 @@ public:
   bool ParseFontFamilyListString(const nsSubstring& aBuffer,
                                  nsIURI* aURL, // for error reporting
                                  uint32_t aLineNumber, // for error reporting
                                  nsCSSValue& aValue);
 
   bool ParseColorString(const nsSubstring& aBuffer,
                         nsIURI* aURL, // for error reporting
                         uint32_t aLineNumber, // for error reporting
-                        nsCSSValue& aValue);
+                        nsCSSValue& aValue,
+                        bool aSuppressErrors /* false */);
 
   nsresult ParseSelectorString(const nsSubstring& aSelectorString,
                                nsIURI* aURL, // for error reporting
                                uint32_t aLineNumber, // for error reporting
                                nsCSSSelectorList **aSelectorList);
 
   already_AddRefed<nsCSSKeyframeRule>
   ParseKeyframeRule(const nsSubstring& aBuffer,
@@ -211,16 +212,18 @@ public:
 
   bool ParseCounterDescriptor(nsCSSCounterDesc aDescID,
                               const nsAString& aBuffer,
                               nsIURI* aSheetURL,
                               nsIURI* aBaseURL,
                               nsIPrincipal* aSheetPrincipal,
                               nsCSSValue& aValue);
 
+  bool IsValueValidForProperty(const nsCSSProperty aPropID,
+                               const nsAString& aPropValue);
 
   typedef nsCSSParser::VariableEnumFunc VariableEnumFunc;
 
   /**
    * Parses a CSS token stream value and invokes a callback function for each
    * variable reference that is encountered.
    *
    * @param aPropertyValue The CSS token stream value.
@@ -1702,25 +1705,34 @@ CSSParserImpl::ParseSourceSizeList(const
 
   return !hitError;
 }
 
 bool
 CSSParserImpl::ParseColorString(const nsSubstring& aBuffer,
                                 nsIURI* aURI, // for error reporting
                                 uint32_t aLineNumber, // for error reporting
-                                nsCSSValue& aValue)
+                                nsCSSValue& aValue,
+                                bool aSuppressErrors /* false */)
 {
   nsCSSScanner scanner(aBuffer, aLineNumber);
   css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aURI);
   InitScanner(scanner, reporter, aURI, aURI, nullptr);
 
+  nsAutoSuppressErrors suppressErrors(this, aSuppressErrors);
+
   // Parse a color, and check that there's nothing else after it.
   bool colorParsed = ParseColor(aValue) && !GetToken(true);
-  OUTPUT_ERROR();
+
+  if (aSuppressErrors) {
+    CLEAR_ERROR();
+  } else {
+    OUTPUT_ERROR();
+  }
+
   ReleaseScanner();
   return colorParsed;
 }
 
 bool
 CSSParserImpl::ParseFontFamilyListString(const nsSubstring& aBuffer,
                                          nsIURI* aURI, // for error reporting
                                          uint32_t aLineNumber, // for error reporting
@@ -14663,16 +14675,57 @@ CSSParserImpl::ParseValueWithVariables(C
   while (i--) {
     aImpliedCharacters.Append(stack[i]);
   }
 
   *aType = type;
   return true;
 }
 
+bool
+CSSParserImpl::IsValueValidForProperty(const nsCSSProperty aPropID,
+                                       const nsAString& aPropValue)
+{
+  mData.AssertInitialState();
+  mTempData.AssertInitialState();
+
+  nsCSSScanner scanner(aPropValue, 0);
+  css::ErrorReporter reporter(scanner, mSheet, mChildLoader, nullptr);
+  InitScanner(scanner, reporter, nullptr, nullptr, nullptr);
+
+  nsAutoSuppressErrors suppressErrors(this);
+
+  mSection = eCSSSection_General;
+  scanner.SetSVGMode(false);
+
+  // Check for unknown properties
+  if (eCSSProperty_UNKNOWN == aPropID) {
+    ReleaseScanner();
+    return false;
+  }
+
+  // Check that the property and value parse successfully
+  bool parsedOK = ParseProperty(aPropID);
+
+  // Check for priority
+  parsedOK = parsedOK && ParsePriority() != ePriority_Error;
+
+  // We should now be at EOF
+  parsedOK = parsedOK && !GetToken(true);
+
+  mTempData.ClearProperty(aPropID);
+  mTempData.AssertInitialState();
+  mData.AssertInitialState();
+
+  CLEAR_ERROR();
+  ReleaseScanner();
+
+  return parsedOK;
+}
+
 } // anonymous namespace
 
 // Recycling of parser implementation objects
 
 static CSSParserImpl* gFreeList = nullptr;
 
 nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
                          CSSStyleSheet* aSheet)
@@ -14855,20 +14908,21 @@ nsCSSParser::ParseFontFamilyListString(c
   return static_cast<CSSParserImpl*>(mImpl)->
     ParseFontFamilyListString(aBuffer, aURI, aLineNumber, aValue);
 }
 
 bool
 nsCSSParser::ParseColorString(const nsSubstring& aBuffer,
                               nsIURI*            aURI,
                               uint32_t           aLineNumber,
-                              nsCSSValue&        aValue)
+                              nsCSSValue&        aValue,
+                              bool               aSuppressErrors /* false */)
 {
   return static_cast<CSSParserImpl*>(mImpl)->
-    ParseColorString(aBuffer, aURI, aLineNumber, aValue);
+    ParseColorString(aBuffer, aURI, aLineNumber, aValue, aSuppressErrors);
 }
 
 nsresult
 nsCSSParser::ParseSelectorString(const nsSubstring&  aSelectorString,
                                  nsIURI*             aURI,
                                  uint32_t            aLineNumber,
                                  nsCSSSelectorList** aSelectorList)
 {
@@ -14976,8 +15030,17 @@ nsCSSParser::ParseCounterDescriptor(nsCS
                                     nsIURI* aBaseURL,
                                     nsIPrincipal* aSheetPrincipal,
                                     nsCSSValue& aValue)
 {
   return static_cast<CSSParserImpl*>(mImpl)->
     ParseCounterDescriptor(aDescID, aBuffer,
                            aSheetURL, aBaseURL, aSheetPrincipal, aValue);
 }
+
+bool
+nsCSSParser::IsValueValidForProperty(const nsCSSProperty aPropID,
+                                     const nsAString&    aPropValue)
+{
+  return static_cast<CSSParserImpl*>(mImpl)->
+    IsValueValidForProperty(aPropID, aPropValue);
+}
+
--- a/layout/style/nsCSSParser.h
+++ b/layout/style/nsCSSParser.h
@@ -186,17 +186,18 @@ public:
    * Parse aBuffer into a nsCSSValue |aValue|. Will return false
    * if aBuffer is not a valid CSS color specification.
    * One can use nsRuleNode::ComputeColor to compute an nscolor from
    * the returned nsCSSValue.
    */
   bool ParseColorString(const nsSubstring& aBuffer,
                         nsIURI*            aURL,
                         uint32_t           aLineNumber,
-                        nsCSSValue&        aValue);
+                        nsCSSValue&        aValue,
+                        bool               aSuppressErrors = false);
 
   /**
    * Parse aBuffer into a selector list.  On success, caller must
    * delete *aSelectorList when done with it.
    */
   nsresult ParseSelectorString(const nsSubstring&  aSelectorString,
                                nsIURI*             aURL,
                                uint32_t            aLineNumber,
@@ -291,16 +292,20 @@ public:
 
   bool ParseCounterDescriptor(nsCSSCounterDesc aDescID,
                               const nsAString& aBuffer,
                               nsIURI* aSheetURL,
                               nsIURI* aBaseURL,
                               nsIPrincipal* aSheetPrincipal,
                               nsCSSValue& aValue);
 
+  // Check whether a given value can be applied to a property.
+  bool IsValueValidForProperty(const nsCSSProperty aPropID,
+                               const nsAString&    aPropValue);
+
 protected:
   // This is a CSSParserImpl*, but if we expose that type name in this
   // header, we can't put the type definition (in nsCSSParser.cpp) in
   // the anonymous namespace.
   void* mImpl;
 };
 
 #endif /* nsCSSParser_h___ */