Bug 897392 - Implement parsing of filter:hue-rotate(). r=heycam
authorDirk Schulze <krit@webkit.org>
Fri, 26 Jul 2013 16:02:33 +1000
changeset 140134 6c30d62aa552fab00033b9edc33b35492ebe3056
parent 140133 299df147d0e0cec94161dd9494618f2131bb2ec0
child 140135 44ebfcf61a6cc706084eff19a8f3f70d352cf0c0
push id25016
push userryanvm@gmail.com
push dateSat, 27 Jul 2013 02:25:56 +0000
treeherdermozilla-central@fb48c7d58b8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs897392
milestone25.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 897392 - Implement parsing of filter:hue-rotate(). r=heycam
layout/style/nsCSSKeywordList.h
layout/style/nsCSSParser.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsROCSSPrimitiveValue.cpp
layout/style/nsROCSSPrimitiveValue.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -283,16 +283,17 @@ CSS_KEY(hide, hide)
 CSS_KEY(highlight, highlight)
 CSS_KEY(highlighttext, highlighttext)
 CSS_KEY(hiragana, hiragana)
 CSS_KEY(hiragana-iroha, hiragana_iroha)
 CSS_KEY(historical-forms, historical_forms)
 CSS_KEY(historical-ligatures, historical_ligatures)
 CSS_KEY(horizontal, horizontal)
 CSS_KEY(horizontal-tb, horizontal_tb)
+CSS_KEY(hue-rotate, hue_rotate)
 CSS_KEY(hz, hz)
 CSS_KEY(icon, icon)
 CSS_KEY(ignore, ignore)
 CSS_KEY(in, in)
 CSS_KEY(interlace, interlace)
 CSS_KEY(inactive, inactive)
 CSS_KEY(inactiveborder, inactiveborder)
 CSS_KEY(inactivecaption, inactivecaption)
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -10076,25 +10076,29 @@ CSSParserImpl::ParseSingleFilter(nsCSSVa
   bool clampArgumentToOne = false;
   nsCSSKeyword functionName = nsCSSKeywords::LookupKeyword(mToken.mIdent);
   switch (functionName) {
     case eCSSKeyword_blur:
       variantMask = VARIANT_LCALC | VARIANT_NONNEGATIVE_DIMENSION;
       // VARIANT_NONNEGATIVE_DIMENSION will already reject negative lengths.
       rejectNegativeArgument = false;
       break;
+    case eCSSKeyword_brightness:
+    case eCSSKeyword_contrast:
+    case eCSSKeyword_saturate:
+      break;
     case eCSSKeyword_grayscale:
     case eCSSKeyword_invert:
     case eCSSKeyword_sepia:
     case eCSSKeyword_opacity:
       clampArgumentToOne = true;
       break;
-    case eCSSKeyword_brightness:
-    case eCSSKeyword_contrast:
-    case eCSSKeyword_saturate:
+    case eCSSKeyword_hue_rotate:
+      variantMask = VARIANT_ANGLE;
+      rejectNegativeArgument = false;
       break;
     default:
       // Unrecognized filter function.
       REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURLOrFilterFunction);
       SkipUntil(')');
       return false;
   }
 
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1705,26 +1705,18 @@ nsComputedDOMStyle::GetCSSGradientString
       needSep = true;
     }
   }
   if (aGradient->mAngle.GetUnit() != eStyleUnit_None) {
     MOZ_ASSERT(!isRadial || aGradient->mLegacySyntax);
     if (needSep) {
       aString.AppendLiteral(" ");
     }
-    tmpVal->SetNumber(aGradient->mAngle.GetAngleValue());
-    tmpVal->GetCssText(tokenString);
+    SetCssTextToCoord(tokenString, aGradient->mAngle);
     aString.Append(tokenString);
-    switch (aGradient->mAngle.GetUnit()) {
-    case eStyleUnit_Degree: aString.AppendLiteral("deg"); break;
-    case eStyleUnit_Grad: aString.AppendLiteral("grad"); break;
-    case eStyleUnit_Radian: aString.AppendLiteral("rad"); break;
-    case eStyleUnit_Turn: aString.AppendLiteral("turn"); break;
-    default: NS_NOTREACHED("unrecognized angle unit");
-    }
     needSep = true;
   }
 
   if (isRadial && aGradient->mLegacySyntax &&
       (aGradient->mShape == NS_STYLE_GRADIENT_SHAPE_CIRCULAR ||
        aGradient->mSize != NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)) {
     MOZ_ASSERT(aGradient->mSize != NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE);
     if (needSep) {
@@ -4002,16 +3994,33 @@ nsComputedDOMStyle::SetValueToCoord(nsRO
           val = 0;
         }
         aValue->SetAppUnits(std::max(aMinAppUnits, std::min(val, aMaxAppUnits)));
       } else {
         nsStyleCoord::Calc *calc = aCoord.GetCalcValue();
         SetValueToCalc(calc, aValue);
       }
       break;
+
+    case eStyleUnit_Degree:
+      aValue->SetDegree(aCoord.GetAngleValue());
+      break;
+
+    case eStyleUnit_Grad:
+      aValue->SetGrad(aCoord.GetAngleValue());
+      break;
+
+    case eStyleUnit_Radian:
+      aValue->SetRadian(aCoord.GetAngleValue());
+      break;
+
+    case eStyleUnit_Turn:
+      aValue->SetTurn(aCoord.GetAngleValue());
+      break;
+
     default:
       NS_ERROR("Can't handle this unit");
       break;
   }
 }
 
 nscoord
 nsComputedDOMStyle::StyleCoordToNSCoord(const nsStyleCoord& aCoord,
@@ -4490,16 +4499,19 @@ GetFilterFunctionName(nsAString& aString
       aString.AssignLiteral("brightness(");
       break;
     case nsStyleFilter::Type::eContrast:
       aString.AssignLiteral("contrast(");
       break;
     case nsStyleFilter::Type::eGrayscale:
       aString.AssignLiteral("grayscale(");
       break;
+    case nsStyleFilter::Type::eHueRotate:
+      aString.AssignLiteral("hue-rotate(");
+      break;
     case nsStyleFilter::Type::eInvert:
       aString.AssignLiteral("invert(");
       break;
     case nsStyleFilter::Type::eOpacity:
       aString.AssignLiteral("opacity(");
       break;
     case nsStyleFilter::Type::eSaturate:
       aString.AssignLiteral("saturate(");
@@ -4525,17 +4537,17 @@ nsComputedDOMStyle::CreatePrimitiveValue
   }
 
   // Filter function name and opening parenthesis.
   nsAutoString filterFunctionString;
   GetFilterFunctionName(filterFunctionString, aStyleFilter.mType);
 
   // Filter function argument.
   nsAutoString argumentString;
-  SetCssTextToCoord(argumentString, aStyleFilter.mCoord);
+  SetCssTextToCoord(argumentString, aStyleFilter.mFilterParameter);
   filterFunctionString.Append(argumentString);
 
   // Filter function closing parenthesis.
   filterFunctionString.AppendLiteral(")");
 
   value->SetString(filterFunctionString);
   return value;
 }
--- a/layout/style/nsROCSSPrimitiveValue.cpp
+++ b/layout/style/nsROCSSPrimitiveValue.cpp
@@ -13,16 +13,23 @@
 #include "nsStyleUtil.h"
 #include "nsDOMCSSRGBColor.h"
 #include "nsDOMCSSRect.h"
 #include "nsIURI.h"
 #include "nsError.h"
 
 using namespace mozilla;
 
+// There is no CSS_TURN constant on the CSSPrimitiveValue interface,
+// since that unit is newer than DOM Level 2 Style, and CSS OM will
+// probably expose CSS values in some other way in the future.  We
+// use this value in mType for "turn"-unit angles, but we define it
+// here to avoid exposing it to content.
+#define CSS_TURN 30U
+
 nsROCSSPrimitiveValue::nsROCSSPrimitiveValue()
   : CSSValue(), mType(CSS_PX)
 {
   mValue.mAppUnits = 0;
   SetIsDOMBinding();
 }
 
 
@@ -129,16 +136,40 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
         tmpStr.Append(PRUnichar('%'));
         break;
       }
     case CSS_NUMBER :
       {
         tmpStr.AppendFloat(mValue.mFloat);
         break;
       }
+    case CSS_DEG :
+      {
+        tmpStr.AppendFloat(mValue.mFloat);
+        tmpStr.AppendLiteral("deg");
+        break;
+      }
+    case CSS_GRAD :
+      {
+        tmpStr.AppendFloat(mValue.mFloat);
+        tmpStr.AppendLiteral("grad");
+        break;
+      }
+    case CSS_RAD :
+      {
+        tmpStr.AppendFloat(mValue.mFloat);
+        tmpStr.AppendLiteral("rad");
+        break;
+      }
+    case CSS_TURN :
+      {
+        tmpStr.AppendFloat(mValue.mFloat);
+        tmpStr.AppendLiteral("turn");
+        break;
+      }
     case CSS_RECT :
       {
         NS_ASSERTION(mValue.mRect, "mValue.mRect should never be null");
         NS_NAMED_LITERAL_STRING(comma, ", ");
         nsCOMPtr<nsIDOMCSSPrimitiveValue> sideCSSValue;
         nsAutoString sideValue;
         tmpStr.AssignLiteral("rect(");
         // get the top
@@ -225,19 +256,16 @@ nsROCSSPrimitiveValue::GetCssText(nsAStr
     case CSS_CM :
     case CSS_MM :
     case CSS_IN :
     case CSS_PT :
     case CSS_PC :
     case CSS_UNKNOWN :
     case CSS_EMS :
     case CSS_EXS :
-    case CSS_DEG :
-    case CSS_RAD :
-    case CSS_GRAD :
     case CSS_MS :
     case CSS_HZ :
     case CSS_KHZ :
     case CSS_DIMENSION :
       NS_ERROR("We have a bogus value set.  This should not happen");
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
   }
 
@@ -516,16 +544,48 @@ void
 nsROCSSPrimitiveValue::SetPercent(float aValue)
 {
   Reset();
   mValue.mFloat = aValue;
   mType = CSS_PERCENTAGE;
 }
 
 void
+nsROCSSPrimitiveValue::SetDegree(float aValue)
+{
+  Reset();
+  mValue.mFloat = aValue;
+  mType = CSS_DEG;
+}
+
+void
+nsROCSSPrimitiveValue::SetGrad(float aValue)
+{
+  Reset();
+  mValue.mFloat = aValue;
+  mType = CSS_GRAD;
+}
+
+void
+nsROCSSPrimitiveValue::SetRadian(float aValue)
+{
+  Reset();
+  mValue.mFloat = aValue;
+  mType = CSS_RAD;
+}
+
+void
+nsROCSSPrimitiveValue::SetTurn(float aValue)
+{
+  Reset();
+  mValue.mFloat = aValue;
+  mType = CSS_TURN;
+}
+
+void
 nsROCSSPrimitiveValue::SetAppUnits(nscoord aValue)
 {
   Reset();
   mValue.mAppUnits = aValue;
   mType = CSS_PX;
 }
 
 void
--- a/layout/style/nsROCSSPrimitiveValue.h
+++ b/layout/style/nsROCSSPrimitiveValue.h
@@ -39,16 +39,21 @@ public:
   // CSSValue
   virtual void GetCssText(nsString& aText, mozilla::ErrorResult& aRv) MOZ_OVERRIDE MOZ_FINAL;
   virtual void SetCssText(const nsAString& aText, mozilla::ErrorResult& aRv) MOZ_OVERRIDE MOZ_FINAL;
   virtual uint16_t CssValueType() const MOZ_OVERRIDE MOZ_FINAL;
 
   // CSSPrimitiveValue
   uint16_t PrimitiveType()
   {
+    // New value types were introduced but not added to CSS OM.
+    // Return CSS_UNKNOWN to avoid exposing CSS_TURN to content.
+    if (mType > CSS_RGBCOLOR) {
+      return CSS_UNKNOWN;
+    }
     return mType;
   }
   void SetFloatValue(uint16_t aUnitType, float aValue,
                      mozilla::ErrorResult& aRv);
   float GetFloatValue(uint16_t aUnitType, mozilla::ErrorResult& aRv);
   void GetStringValue(nsString& aString, mozilla::ErrorResult& aRv);
   void SetStringValue(uint16_t aUnitType, const nsAString& aString,
                       mozilla::ErrorResult& aRv);
@@ -59,16 +64,20 @@ public:
   // nsROCSSPrimitiveValue
   nsROCSSPrimitiveValue();
   ~nsROCSSPrimitiveValue();
 
   void SetNumber(float aValue);
   void SetNumber(int32_t aValue);
   void SetNumber(uint32_t aValue);
   void SetPercent(float aValue);
+  void SetDegree(float aValue);
+  void SetGrad(float aValue);
+  void SetRadian(float aValue);
+  void SetTurn(float aValue);
   void SetAppUnits(nscoord aValue);
   void SetAppUnits(float aValue);
   void SetIdent(nsCSSKeyword aKeyword);
   // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
   void SetString(const nsACString& aString, uint16_t aType = CSS_STRING);
   // FIXME: CSS_STRING should imply a string with "" and a need for escaping.
   void SetString(const nsAString& aString, uint16_t aType = CSS_STRING);
   void SetURI(nsIURI *aURI);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -648,16 +648,17 @@ GetFloatFromBoxPosition(int32_t aEnumVal
 #define SETCOORD_INITIAL_HALF           0x2000
 #define SETCOORD_INITIAL_HUNDRED_PCT    0x00004000
 #define SETCOORD_INITIAL_FACTOR_ONE     0x00008000
 #define SETCOORD_INITIAL_FACTOR_ZERO    0x00010000
 #define SETCOORD_CALC_LENGTH_ONLY       0x00020000
 #define SETCOORD_CALC_CLAMP_NONNEGATIVE 0x00040000 // modifier for CALC_LENGTH_ONLY
 #define SETCOORD_STORE_CALC             0x00080000
 #define SETCOORD_BOX_POSITION           0x00100000 // exclusive with _ENUMERATED
+#define SETCOORD_ANGLE                  0x00200000
 
 #define SETCOORD_LP     (SETCOORD_LENGTH | SETCOORD_PERCENT)
 #define SETCOORD_LH     (SETCOORD_LENGTH | SETCOORD_INHERIT)
 #define SETCOORD_AH     (SETCOORD_AUTO | SETCOORD_INHERIT)
 #define SETCOORD_LAH    (SETCOORD_AUTO | SETCOORD_LENGTH | SETCOORD_INHERIT)
 #define SETCOORD_LPH    (SETCOORD_LP | SETCOORD_INHERIT)
 #define SETCOORD_LPAH   (SETCOORD_LP | SETCOORD_AH)
 #define SETCOORD_LPEH   (SETCOORD_LP | SETCOORD_ENUMERATED | SETCOORD_INHERIT)
@@ -760,16 +761,29 @@ static bool SetCoord(const nsCSSValue& a
     }
     else if ((aMask & SETCOORD_INITIAL_FACTOR_ONE) != 0) {
       aCoord.SetFactorValue(1.0f);
     }
     else {
       result = false;  // didn't set anything
     }
   }
+  else if ((aMask & SETCOORD_ANGLE) != 0 &&
+           (aValue.IsAngularUnit())) {
+    nsStyleUnit unit;
+    switch (aValue.GetUnit()) {
+      case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
+      case eCSSUnit_Grad:   unit = eStyleUnit_Grad; break;
+      case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
+      case eCSSUnit_Turn:   unit = eStyleUnit_Turn; break;
+      default: NS_NOTREACHED("unrecognized angular unit");
+        unit = eStyleUnit_Degree;
+    }
+    aCoord.SetAngleValue(aValue.GetAngleValue(), unit);
+  }
   else {
     result = false;  // didn't set anything
   }
   return result;
 }
 
 // This inline function offers a shortcut for SetCoord() by refusing to accept
 // SETCOORD_LENGTH and SETCOORD_INHERIT masks.
@@ -982,28 +996,19 @@ static void SetGradient(const nsCSSValue
                    aResult.mBgPosX, aCanStoreInRuleTree);
 
   SetGradientCoord(gradient->mBgPos.mYValue, aPresContext, aContext,
                    aResult.mBgPosY, aCanStoreInRuleTree);
 
   aResult.mRepeating = gradient->mIsRepeating;
 
   // angle
-  if (gradient->mAngle.IsAngularUnit()) {
-    nsStyleUnit unit;
-    switch (gradient->mAngle.GetUnit()) {
-    case eCSSUnit_Degree: unit = eStyleUnit_Degree; break;
-    case eCSSUnit_Grad:   unit = eStyleUnit_Grad; break;
-    case eCSSUnit_Radian: unit = eStyleUnit_Radian; break;
-    case eCSSUnit_Turn:   unit = eStyleUnit_Turn; break;
-    default: NS_NOTREACHED("unrecognized angular unit");
-      unit = eStyleUnit_Degree;
-    }
-    aResult.mAngle.SetAngleValue(gradient->mAngle.GetAngleValue(), unit);
-  } else {
+  const nsStyleCoord dummyParentCoord;
+  if (!SetCoord(gradient->mAngle, aResult.mAngle, dummyParentCoord, SETCOORD_ANGLE,
+                aContext, aPresContext, aCanStoreInRuleTree)) {
     NS_ASSERTION(gradient->mAngle.GetUnit() == eCSSUnit_None,
                  "bad unit for gradient angle");
     aResult.mAngle.SetNoneValue();
   }
 
   // stops
   for (uint32_t i = 0; i < gradient->mStops.Length(); i++) {
     nsStyleGradientStop stop;
@@ -7715,16 +7720,18 @@ StyleFilterTypeForFunctionName(nsCSSKeyw
     case eCSSKeyword_blur:
       return nsStyleFilter::Type::eBlur;
     case eCSSKeyword_brightness:
       return nsStyleFilter::Type::eBrightness;
     case eCSSKeyword_contrast:
       return nsStyleFilter::Type::eContrast;
     case eCSSKeyword_grayscale:
       return nsStyleFilter::Type::eGrayscale;
+    case eCSSKeyword_hue_rotate:
+      return nsStyleFilter::Type::eHueRotate;
     case eCSSKeyword_invert:
       return nsStyleFilter::Type::eInvert;
     case eCSSKeyword_opacity:
       return nsStyleFilter::Type::eOpacity;
     case eCSSKeyword_saturate:
       return nsStyleFilter::Type::eSaturate;
     case eCSSKeyword_sepia:
       return nsStyleFilter::Type::eSepia;
@@ -7751,26 +7758,30 @@ SetStyleFilterToCSSValue(nsStyleFilter* 
   NS_ABORT_IF_FALSE(unit == eCSSUnit_Function, "expected a filter function");
 
   nsCSSValue::Array* filterFunction = aValue.GetArrayValue();
   nsCSSKeyword functionName =
     (nsCSSKeyword)filterFunction->Item(0).GetIntValue();
   aStyleFilter->mType = StyleFilterTypeForFunctionName(functionName);
 
   int32_t mask = SETCOORD_PERCENT | SETCOORD_FACTOR;
-  if (aStyleFilter->mType == nsStyleFilter::Type::eBlur)
+  if (aStyleFilter->mType == nsStyleFilter::Type::eBlur) {
     mask = SETCOORD_LENGTH | SETCOORD_STORE_CALC;
+  } else if (aStyleFilter->mType == nsStyleFilter::Type::eHueRotate) {
+    mask = SETCOORD_ANGLE;
+  }
 
   NS_ABORT_IF_FALSE(filterFunction->Count() == 2,
                     "all filter functions except drop-shadow should have "
                     "exactly one argument");
 
   nsCSSValue& arg = filterFunction->Item(1);
-  DebugOnly<bool> success = SetCoord(arg, aStyleFilter->mCoord, nsStyleCoord(),
-                                     mask, aStyleContext, aPresContext,
+  DebugOnly<bool> success = SetCoord(arg, aStyleFilter->mFilterParameter,
+                                     nsStyleCoord(), mask,
+                                     aStyleContext, aPresContext,
                                      aCanStoreInRuleTree);
   NS_ABORT_IF_FALSE(success, "unexpected unit");
 }
 
 const void*
 nsRuleNode::ComputeSVGResetData(void* aStartStruct,
                                 const nsRuleData* aRuleData,
                                 nsStyleContext* aContext,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1012,17 +1012,17 @@ nsStyleFilter::nsStyleFilter()
 nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
   : mType(aSource.mType)
 {
   MOZ_COUNT_CTOR(nsStyleFilter);
 
   if (mType == eURL) {
     mURL = aSource.mURL;
   } else if (mType != eNull) {
-    mCoord = aSource.mCoord;
+    mFilterParameter = aSource.mFilterParameter;
   }
 }
 
 nsStyleFilter::~nsStyleFilter()
 {
   MOZ_COUNT_DTOR(nsStyleFilter);
 }
 
@@ -1031,17 +1031,17 @@ nsStyleFilter::operator==(const nsStyleF
 {
   if (mType != aOther.mType) {
       return false;
   }
 
   if (mType == eURL) {
     return EqualURIs(mURL, aOther.mURL);
   } else if (mType != eNull) {
-    return mCoord == aOther.mCoord;
+    return mFilterParameter == aOther.mFilterParameter;
   }
 
   return true;
 }
 
 // --------------------
 // nsStyleSVGReset
 //
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2276,26 +2276,27 @@ struct nsStyleFilter {
   bool operator==(const nsStyleFilter& aOther) const;
 
   enum Type {
     eNull,
     eURL,
     eBlur,
     eBrightness,
     eContrast,
+    eHueRotate,
     eInvert,
     eOpacity,
     eGrayscale,
     eSaturate,
     eSepia,
   };
 
   Type mType;
   nsIURI* mURL;
-  nsStyleCoord mCoord;
+  nsStyleCoord mFilterParameter; // coord, percent, factor, angle
   // FIXME: Add a nsCSSShadowItem when we implement drop shadow.
 };
 
 struct nsStyleSVGReset {
   nsStyleSVGReset();
   nsStyleSVGReset(const nsStyleSVGReset& aSource);
   ~nsStyleSVGReset();
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4461,16 +4461,26 @@ if (SpecialPowers.getBoolPref("layout.cs
 			"grayscale(0)",
 			"grayscale(50%)",
 			"grayscale(1)",
 			"grayscale(1.0)",
 			"grayscale(2)",
 			"grayscale(350%)",
 			"grayscale(4.567)",
 
+			"hue-rotate(0deg)",
+			"hue-rotate(90deg)",
+			"hue-rotate(540deg)",
+			"hue-rotate(-90deg)",
+			"hue-rotate(10grad)",
+			"hue-rotate(1.6rad)",
+			"hue-rotate(-1.6rad)",
+			"hue-rotate(0.5turn)",
+			"hue-rotate(-2turn)",
+
 			"invert(0)",
 			"invert(50%)",
 			"invert(1)",
 			"invert(1.0)",
 			"invert(2)",
 			"invert(350%)",
 			"invert(4.567)",
 
@@ -4549,16 +4559,26 @@ if (SpecialPowers.getBoolPref("layout.cs
 			"grayscale()",
 			"grayscale(0.5 0.5)",
 			"grayscale(0.5,)",
 			"grayscale(0.5, 0.5)",
 			"grayscale(#my-filter)",
 			"grayscale(10px)",
 			"grayscale(-1)",
 
+			"hue-rotate()",
+			"hue-rotate(0)",
+			"hue-rotate(0.5 0.5)",
+			"hue-rotate(0.5,)",
+			"hue-rotate(0.5, 0.5)",
+			"hue-rotate(#my-filter)",
+			"hue-rotate(10px)",
+			"hue-rotate(-1)",
+			"hue-rotate(45deg,)",
+
 			"invert()",
 			"invert(0.5 0.5)",
 			"invert(0.5,)",
 			"invert(0.5, 0.5)",
 			"invert(#my-filter)",
 			"invert(10px)",
 			"invert(-1)",