Bug 1467621 - P1: nsCSSShadowItem - Change nscolor to StyleComplexColor. r?xidorn draft
authorDan Glastonbury <dan.glastonbury@gmail.com>
Tue, 19 Jun 2018 14:18:33 +1000
changeset 810057 34521578e9f89addaaf98288ce57ccdf18ec7eef
parent 809071 d231a32316809f8c9efa43ed6f74484ff552c115
child 810058 e8270e46f3811b4ef9aca4c5a983dd089375c892
push id113874
push userbmo:dglastonbury@mozilla.com
push dateMon, 25 Jun 2018 04:15:24 +0000
reviewersxidorn
bugs1467621
milestone62.0a1
Bug 1467621 - P1: nsCSSShadowItem - Change nscolor to StyleComplexColor. r?xidorn MozReview-Commit-ID: moE2CI7fT8
layout/base/nsLayoutUtils.cpp
layout/generic/nsTextFrame.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsDisplayList.cpp
layout/style/StyleComplexColor.cpp
layout/style/StyleComplexColor.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsStyleStruct.h
layout/style/test/test_transitions_per_property.html
layout/svg/nsCSSFilterInstance.cpp
servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
servo/components/style/values/animated/color.rs
servo/components/style/values/animated/effects.rs
servo/components/style/values/computed/effects.rs
servo/components/style/values/specified/effects.rs
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6116,21 +6116,17 @@ nsLayoutUtils::PaintTextShadow(const nsI
     nscoord blurRadius = std::max(shadowDetails->mRadius, 0);
 
     nsRect shadowRect(aTextRect);
     shadowRect.MoveBy(shadowOffset);
 
     nsPresContext* presCtx = aFrame->PresContext();
     nsContextBoxBlur contextBoxBlur;
 
-    nscolor shadowColor;
-    if (shadowDetails->mHasColor)
-      shadowColor = shadowDetails->mColor;
-    else
-      shadowColor = aForegroundColor;
+    nscolor shadowColor = shadowDetails->mColor.CalcColor(aForegroundColor);
 
     // Webrender just needs the shadow details
     if (auto* textDrawer = aContext->GetTextDrawer()) {
       wr::Shadow wrShadow;
 
       wrShadow.offset = {
         presCtx->AppUnitsToFloatDevPixels(shadowDetails->mXOffset),
         presCtx->AppUnitsToFloatDevPixels(shadowDetails->mYOffset)
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -6241,18 +6241,18 @@ nsTextFrame::PaintOneShadow(const PaintS
                             nsCSSShadowItem* aShadowDetails,
                             gfxRect& aBoundingBox, uint32_t aBlurFlags)
 {
   AUTO_PROFILER_LABEL("nsTextFrame::PaintOneShadow", GRAPHICS);
 
   gfx::Point shadowOffset(aShadowDetails->mXOffset, aShadowDetails->mYOffset);
   nscoord blurRadius = std::max(aShadowDetails->mRadius, 0);
 
-  nscolor shadowColor = aShadowDetails->mHasColor ? aShadowDetails->mColor
-                                                  : aParams.foregroundColor;
+  nscolor shadowColor =
+    aShadowDetails->mColor.CalcColor(aParams.foregroundColor);
 
   if (auto* textDrawer = aParams.context->GetTextDrawer()) {
     wr::Shadow wrShadow;
 
     wrShadow.offset = {
       PresContext()->AppUnitsToFloatDevPixels(aShadowDetails->mXOffset),
       PresContext()->AppUnitsToFloatDevPixels(aShadowDetails->mYOffset)
     };
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -1515,22 +1515,17 @@ nsCSSRendering::HasBoxShadowNativeTheme(
 }
 
 gfx::Color
 nsCSSRendering::GetShadowColor(nsCSSShadowItem* aShadow,
                                nsIFrame* aFrame,
                                float aOpacity)
 {
   // Get the shadow color; if not specified, use the foreground color
-  nscolor shadowColor;
-  if (aShadow->mHasColor)
-    shadowColor = aShadow->mColor;
-  else
-    shadowColor = aFrame->StyleColor()->mColor;
-
+  nscolor shadowColor = aShadow->mColor.CalcColor(aFrame);
   Color color = Color::FromABGR(shadowColor);
   color.a *= aOpacity;
   return color;
 }
 
 nsRect
 nsCSSRendering::GetShadowRect(const nsRect aFrameArea,
                               bool aNativeTheme,
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -9839,20 +9839,17 @@ nsDisplayFilter::CreateWebRenderCommands
         float appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
         nsCSSShadowArray* shadows = filter.GetDropShadow();
         if (!shadows || shadows->Length() != 1) {
           NS_NOTREACHED("Exactly one drop shadow should have been parsed.");
           return false;
         }
 
         nsCSSShadowItem* shadow = shadows->ShadowAt(0);
-        nscolor color = shadow->mColor;
-        if (!shadow->mHasColor) {
-          color = mFrame->StyleColor()->mColor;
-        }
+        nscolor color = shadow->mColor.CalcColor(mFrame);
 
         mozilla::wr::WrFilterOp filterOp = {
           wr::ToWrFilterOpType(filter.GetType()),
           NSAppUnitsToFloatPixels(shadow->mRadius, appUnitsPerDevPixel),
           {
             NSAppUnitsToFloatPixels(shadow->mXOffset, appUnitsPerDevPixel),
             NSAppUnitsToFloatPixels(shadow->mYOffset, appUnitsPerDevPixel),
           },
--- a/layout/style/StyleComplexColor.cpp
+++ b/layout/style/StyleComplexColor.cpp
@@ -52,30 +52,41 @@ StyleComplexColor::MaybeTransparent() co
   // We know that the color is opaque when it's a numeric color with
   // alpha == 255.
   // TODO(djg): Should we extend this to check Complex with bgRatio =
   // 0, and fgRatio * alpha >= 255?
   return mTag != eNumeric || NS_GET_A(mColor) != 255;
 }
 
 nscolor
+StyleComplexColor::CalcColor(nscolor aForegroundColor) const {
+  switch (mTag) {
+  case eNumeric:
+    return mColor;
+  case eForeground:
+  case eAuto:
+    return aForegroundColor;
+  case eComplex:
+    return LinearBlendColors(mColor, mBgRatio, aForegroundColor, mFgRatio);
+  default:
+    MOZ_ASSERT_UNREACHABLE("StyleComplexColor has invalid mTag");
+    return mColor;
+  }
+}
+
+nscolor
 StyleComplexColor::CalcColor(mozilla::ComputedStyle* aStyle) const {
   // Common case that is numeric color, which is pure background, we
   // can skip resolving StyleColor().
+  // TODO(djg): Is this optimization worth it?
   if (mTag == eNumeric) {
     return mColor;
   }
 
   MOZ_ASSERT(aStyle);
   auto fgColor = aStyle->StyleColor()->mColor;
-
-  if (mTag == eComplex) {
-    return LinearBlendColors(mColor, mBgRatio, fgColor, mFgRatio);
-  }
-
-  // eForeground and eAuto return the currentcolor.
-  return fgColor;
+  return CalcColor(fgColor);
 }
 
 nscolor
 StyleComplexColor::CalcColor(const nsIFrame* aFrame) const {
   return CalcColor(aFrame->Style());
 }
--- a/layout/style/StyleComplexColor.h
+++ b/layout/style/StyleComplexColor.h
@@ -69,16 +69,22 @@ public:
 
   /**
    * Is it possible that this StyleComplexColor is transparent?
    */
   bool MaybeTransparent() const;
 
   /**
    * Compute the color for this StyleComplexColor, taking into account
+   * the foreground color, aForegroundColor.
+   */
+  nscolor CalcColor(nscolor aForegroundColor) const;
+
+  /**
+   * Compute the color for this StyleComplexColor, taking into account
    * the foreground color from aStyle.
    */
   nscolor CalcColor(mozilla::ComputedStyle* aStyle) const;
 
   /**
    * Compute the color for this StyleComplexColor, taking into account
    * the foreground color from aFrame's ComputedStyle.
    */
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3896,17 +3896,16 @@ nsComputedDOMStyle::GetEllipseRadii(cons
   valueList->AppendCSSValue(valX.forget());
   valueList->AppendCSSValue(valY.forget());
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::GetCSSShadowArray(nsCSSShadowArray* aArray,
-                                      const nscolor& aDefaultColor,
                                       bool aIsBoxShadow)
 {
   if (!aArray) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_none);
     return val.forget();
   }
 
@@ -3937,23 +3936,17 @@ nsComputedDOMStyle::GetCSSShadowArray(ns
 
   for (nsCSSShadowItem *item = aArray->ShadowAt(0),
                    *item_end = item + aArray->Length();
        item < item_end; ++item) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
 
     // Color is either the specified shadow color or the foreground color
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    nscolor shadowColor;
-    if (item->mHasColor) {
-      shadowColor = item->mColor;
-    } else {
-      shadowColor = aDefaultColor;
-    }
-    SetToRGBAColor(val, shadowColor);
+    SetValueFromComplexColor(val, item->mColor);
     itemList->AppendCSSValue(val.forget());
 
     // Set the offsets, blur radius, and spread if available
     for (uint32_t i = 0; i < shadowValuesLength; ++i) {
       val = new nsROCSSPrimitiveValue;
       val->SetAppUnits(item->*(shadowValues[i]));
       itemList->AppendCSSValue(val.forget());
     }
@@ -3981,19 +3974,17 @@ nsComputedDOMStyle::DoGetBoxDecorationBr
     nsCSSProps::ValueToKeywordEnum(StyleBorder()->mBoxDecorationBreak,
                                    nsCSSProps::kBoxDecorationBreakKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetBoxShadow()
 {
-  return GetCSSShadowArray(StyleEffects()->mBoxShadow,
-                           StyleColor()->mColor,
-                           true);
+  return GetCSSShadowArray(StyleEffects()->mBoxShadow, true);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetZIndex()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetValueToCoord(val, StylePosition()->mZIndex, false);
   return val.forget();
@@ -4374,19 +4365,17 @@ nsComputedDOMStyle::DoGetTextOverflow()
   valueList->AppendCSSValue(first.forget());
   valueList->AppendCSSValue(second.forget());
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextShadow()
 {
-  return GetCSSShadowArray(StyleText()->mTextShadow,
-                           StyleColor()->mColor,
-                           false);
+  return GetCSSShadowArray(StyleText()->mTextShadow, false);
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextSizeAdjust()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleText()->mTextSizeAdjust,
                                                nsCSSProps::kTextSizeAdjustKTable));
@@ -6664,19 +6653,17 @@ nsComputedDOMStyle::CreatePrimitiveValue
                                nsCSSProps::kFilterFunctionKTable),
                                filterFunctionString);
   filterFunctionString.Append('(');
 
   nsAutoString argumentString;
   if (aStyleFilter.GetType() == NS_STYLE_FILTER_DROP_SHADOW) {
     // Handle drop-shadow()
     RefPtr<CSSValue> shadowValue =
-      GetCSSShadowArray(aStyleFilter.GetDropShadow(),
-                        StyleColor()->mColor,
-                        false);
+      GetCSSShadowArray(aStyleFilter.GetDropShadow(), false);
     ErrorResult dummy;
     shadowValue->GetCssText(argumentString, dummy);
   } else {
     // Filter function argument.
     SetCssTextToCoord(argumentString, aStyleFilter.GetFilterParameter(), true);
   }
   filterFunctionString.Append(argumentString);
 
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -220,17 +220,16 @@ private:
   already_AddRefed<CSSValue> GetGridTemplateColumnsRows(
     const nsStyleGridTemplate& aTrackList,
     const mozilla::ComputedGridTrackInfo* aTrackInfo);
   already_AddRefed<CSSValue> GetGridLine(const nsStyleGridLine& aGridLine);
 
   bool GetLineHeightCoord(nscoord& aCoord);
 
   already_AddRefed<CSSValue> GetCSSShadowArray(nsCSSShadowArray* aArray,
-                                               const nscolor& aDefaultColor,
                                                bool aIsBoxShadow);
 
   void GetCSSGradientString(const nsStyleGradient* aGradient,
                             nsAString& aString);
   void GetImageRectString(nsIURI* aURI,
                           const nsStyleSides& aCropRect,
                           nsString& aString);
   already_AddRefed<CSSValue> GetScrollSnapPoints(const nsStyleCoord& aCoord);
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -863,43 +863,40 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
 struct nsCSSShadowItem
 {
   nscoord mXOffset;
   nscoord mYOffset;
   nscoord mRadius;
   nscoord mSpread;
 
-  nscolor      mColor;
-  bool mHasColor; // Whether mColor should be used
+  mozilla::StyleComplexColor mColor;
   bool mInset;
 
   nsCSSShadowItem()
     : mXOffset(0)
     , mYOffset(0)
     , mRadius(0)
     , mSpread(0)
-    , mColor(NS_RGB(0, 0, 0))
-    , mHasColor(false)
+    , mColor(mozilla::StyleComplexColor::CurrentColor())
     , mInset(false)
   {
     MOZ_COUNT_CTOR(nsCSSShadowItem);
   }
   ~nsCSSShadowItem() {
     MOZ_COUNT_DTOR(nsCSSShadowItem);
   }
 
   bool operator==(const nsCSSShadowItem& aOther) const {
     return (mXOffset == aOther.mXOffset &&
             mYOffset == aOther.mYOffset &&
             mRadius == aOther.mRadius &&
-            mHasColor == aOther.mHasColor &&
             mSpread == aOther.mSpread &&
             mInset == aOther.mInset &&
-            (!mHasColor || mColor == aOther.mColor));
+            mColor == aOther.mColor);
   }
   bool operator!=(const nsCSSShadowItem& aOther) const {
     return !(*this == aOther);
   }
 };
 
 class nsCSSShadowArray final
 {
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -929,20 +929,20 @@ var filterTests = [
   { start: "drop-shadow(rgb(0, 0, 0) 0px 0px 0px)",
     end: "drop-shadow(rgb(0, 0, 0) 4px 4px 0px)",
     expected: ["drop-shadow", "rgb(0, 0, 0) 1px 1px 0px"] },
   { start: "drop-shadow(#038000 4px 4px)",
     end: "drop-shadow(8px 8px 8px red)",
     expected: ["drop-shadow", "rgb(66, 96, 0) 5px 5px 2px"] },
   { start: "blur(25px) drop-shadow(8px 8px)",
     end: "blur(75px)",
-    expected: ["blur", 37.5, "drop-shadow", "rgb(0, 0, 0) 6px 6px 0px"] },
+    expected: ["blur", 37.5, "drop-shadow", "rgba(0, 0, 0, 0.75) 6px 6px 0px"] },
   { start: "blur(75px)",
     end: "blur(25px) drop-shadow(8px 8px)",
-    expected: ["blur", 62.5, "drop-shadow", "rgb(0, 0, 0) 2px 2px 0px"] },
+    expected: ["blur", 62.5, "drop-shadow", "rgba(0, 0, 0, 0.25) 2px 2px 0px"] },
   { start: "drop-shadow(2px 2px blue)",
     end: "none",
     expected: ["drop-shadow", "rgba(0, 0, 255, 0.75) 1.5px 1.5px 0px"] },
 ];
 
 var prop;
 for (prop in supported_properties) {
   // Test that prop is in the property database.
@@ -1711,22 +1711,19 @@ function test_shadow_transition(prop) {
   // Transition beween values with color and without color.
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty("color", "rgb(3, 0, 0)", "");
   div.style.setProperty(prop, "2px 2px 2px", "");
   is(cs.getPropertyValue(prop), "rgb(3, 0, 0) 2px 2px 2px" + spreadStr,
      "shadow-valued property " + prop + ": computed value before transition");
   div.style.setProperty("transition-property", prop, "");
   div.style.setProperty(prop, "8px 8px 8px red", "");
-  // Bug 726550 for gecko (can't transition), bug 1390697 for servo (doesn't
-  // work currentColor animation for {text,box}-shadow).
-  todo_is(cs.getPropertyValue(prop),
-          "rgb(66, 0, 0) 3.5px 3.5px 3.5px" + spreadStr,
-          "shadow-valued property " + prop +
-          ": interpolation values with/without color");
+  is(cs.getPropertyValue(prop), "rgb(66, 0, 0) 3.5px 3.5px 3.5px" + spreadStr,
+     "shadow-valued property " + prop +
+     ": interpolation values with/without color");
 
   // Transition beween values without color.
   var defaultColor = cs.getPropertyValue("color") + " ";
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "2px 2px 2px", "");
   is(cs.getPropertyValue(prop), defaultColor + "2px 2px 2px" + spreadStr,
      "shadow-valued property " + prop + ": computed value before transition");
   div.style.setProperty("transition-property", prop, "");
--- a/layout/svg/nsCSSFilterInstance.cpp
+++ b/layout/svg/nsCSSFilterInstance.cpp
@@ -219,17 +219,17 @@ nsCSSFilterInstance::SetAttributesForDro
   Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
   aDescr.Attributes().Set(eDropShadowStdDeviation, radiusInFilterSpace);
 
   // Set offset.
   IntPoint offsetInFilterSpace = OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
   aDescr.Attributes().Set(eDropShadowOffset, offsetInFilterSpace);
 
   // Set color. If unspecified, use the CSS color property.
-  nscolor shadowColor = shadow->mHasColor ? shadow->mColor : mShadowFallbackColor;
+  nscolor shadowColor = shadow->mColor.CalcColor(mShadowFallbackColor);
   aDescr.Attributes().Set(eDropShadowColor, ToAttributeColor(shadowColor));
 
   return NS_OK;
 }
 
 nsresult
 nsCSSFilterInstance::SetAttributesForGrayscale(FilterPrimitiveDescription& aDescr)
 {
--- a/servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
@@ -1,18 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Rust helpers for Gecko's `nsCSSShadowItem`.
 
 use app_units::Au;
-use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
 use gecko_bindings::structs::nsCSSShadowItem;
-use values::computed::RGBAColor;
 use values::computed::effects::{BoxShadow, SimpleShadow};
 
 impl nsCSSShadowItem {
     /// Sets this item from the given box shadow.
     #[inline]
     pub fn set_from_box_shadow(&mut self, shadow: BoxShadow) {
         self.set_from_simple_shadow(shadow.base);
         self.mSpread = shadow.spread.to_i32_au();
@@ -32,41 +30,24 @@ impl nsCSSShadowItem {
     /// Sets this item from the given simple shadow.
     #[inline]
     pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) {
         self.mXOffset = shadow.horizontal.to_i32_au();
         self.mYOffset = shadow.vertical.to_i32_au();
         self.mRadius = shadow.blur.0.to_i32_au();
         self.mSpread = 0;
         self.mInset = false;
-        if let Some(color) = shadow.color {
-            self.mHasColor = true;
-            self.mColor = convert_rgba_to_nscolor(&color);
-        } else {
-            // TODO handle currentColor
-            // https://bugzilla.mozilla.org/show_bug.cgi?id=760345
-            self.mHasColor = false;
-            self.mColor = 0;
-        }
-    }
-
-    #[inline]
-    fn extract_color(&self) -> Option<RGBAColor> {
-        if self.mHasColor {
-            Some(convert_nscolor_to_rgba(self.mColor))
-        } else {
-            None
-        }
+        self.mColor = shadow.color.into();
     }
 
     /// Gets a simple shadow from this item.
     #[inline]
     fn extract_simple_shadow(&self) -> SimpleShadow {
         SimpleShadow {
-            color: self.extract_color(),
+            color: self.mColor.into(),
             horizontal: Au(self.mXOffset).into(),
             vertical: Au(self.mYOffset).into(),
             blur: Au(self.mRadius).into(),
         }
     }
 
     /// Returns this item as a simple shadow.
     #[inline]
--- a/servo/components/style/values/animated/color.rs
+++ b/servo/components/style/values/animated/color.rs
@@ -181,17 +181,17 @@ impl ComputeSquaredDistance for Color {
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
         use self::GenericColor::*;
 
         // All comments from the Animate impl also applies here.
         Ok(match (*self, *other) {
             (Foreground, Foreground) => SquaredDistance::from_sqrt(0.),
             (Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?,
             (Foreground, Numeric(color)) | (Numeric(color), Foreground) => {
-                // `computed_squared_distance` is symmetic.
+                // `computed_squared_distance` is symmetric.
                 color.compute_squared_distance(&RGBA::transparent())?
                     + SquaredDistance::from_sqrt(1.)
             }
             (_, _) => {
                 let self_color = self.effective_intermediate_rgba();
                 let other_color = other.effective_intermediate_rgba();
                 let self_ratios = self.effective_ratios();
                 let other_ratios = other.effective_ratios();
@@ -202,12 +202,11 @@ impl ComputeSquaredDistance for Color {
             }
         })
     }
 }
 
 impl ToAnimatedZero for Color {
     #[inline]
     fn to_animated_zero(&self) -> Result<Self, ()> {
-        // FIXME(nox): This does not look correct to me.
-        Err(())
+        Ok(RGBA::transparent().into())
     }
 }
--- a/servo/components/style/values/animated/effects.rs
+++ b/servo/components/style/values/animated/effects.rs
@@ -1,39 +1,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Animated types for CSS values related to effects.
 
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
-use values::animated::color::RGBA;
+use values::animated::color::Color;
 use values::computed::{Angle, Number};
 use values::computed::length::Length;
 #[cfg(feature = "gecko")]
 use values::computed::url::ComputedUrl;
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 use values::generics::effects::BoxShadow as GenericBoxShadow;
 use values::generics::effects::Filter as GenericFilter;
 use values::generics::effects::SimpleShadow as GenericSimpleShadow;
 
 /// An animated value for a single `box-shadow`.
-pub type BoxShadow = GenericBoxShadow<Option<RGBA>, Length, Length, Length>;
+pub type BoxShadow = GenericBoxShadow<Color, Length, Length, Length>;
 
 /// An animated value for a single `filter`.
 #[cfg(feature = "gecko")]
 pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
 
 /// An animated value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
 pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
 
 /// An animated value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<Option<RGBA>, Length, Length>;
+pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>;
 
 impl ComputeSquaredDistance for BoxShadow {
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
         if self.inset != other.inset {
             return Err(());
         }
         Ok(self.base.compute_squared_distance(&other.base)? +
--- a/servo/components/style/values/computed/effects.rs
+++ b/servo/components/style/values/computed/effects.rs
@@ -2,29 +2,29 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 //! Computed types for CSS values related to effects.
 
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
 use values::computed::{Angle, NonNegativeNumber};
-use values::computed::color::RGBAColor;
+use values::computed::color::Color;
 use values::computed::length::{Length, NonNegativeLength};
 #[cfg(feature = "gecko")]
 use values::computed::url::ComputedUrl;
 use values::generics::effects::BoxShadow as GenericBoxShadow;
 use values::generics::effects::Filter as GenericFilter;
 use values::generics::effects::SimpleShadow as GenericSimpleShadow;
 
 /// A computed value for a single shadow of the `box-shadow` property.
-pub type BoxShadow = GenericBoxShadow<Option<RGBAColor>, Length, NonNegativeLength, Length>;
+pub type BoxShadow = GenericBoxShadow<Color, Length, NonNegativeLength, Length>;
 
 /// A computed value for a single `filter`.
 #[cfg(feature = "gecko")]
 pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow, ComputedUrl>;
 
 /// A computed value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
 pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible, Impossible>;
 
 /// A computed value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<Option<RGBAColor>, Length, NonNegativeLength>;
+pub type SimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>;
--- a/servo/components/style/values/specified/effects.rs
+++ b/servo/components/style/values/specified/effects.rs
@@ -12,24 +12,24 @@ use values::Impossible;
 use values::computed::{Context, NonNegativeNumber as ComputedNonNegativeNumber, ToComputedValue};
 use values::computed::effects::BoxShadow as ComputedBoxShadow;
 use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
 use values::generics::NonNegative;
 use values::generics::effects::BoxShadow as GenericBoxShadow;
 use values::generics::effects::Filter as GenericFilter;
 use values::generics::effects::SimpleShadow as GenericSimpleShadow;
 use values::specified::{Angle, NumberOrPercentage};
-use values::specified::color::RGBAColor;
+use values::specified::color::Color;
 use values::specified::length::{Length, NonNegativeLength};
 #[cfg(feature = "gecko")]
 use values::specified::url::SpecifiedUrl;
 
 /// A specified value for a single shadow of the `box-shadow` property.
 pub type BoxShadow =
-    GenericBoxShadow<Option<RGBAColor>, Length, Option<NonNegativeLength>, Option<Length>>;
+    GenericBoxShadow<Option<Color>, Length, Option<NonNegativeLength>, Option<Length>>;
 
 /// A specified value for a single `filter`.
 #[cfg(feature = "gecko")]
 pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow, SpecifiedUrl>;
 
 /// A specified value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
 pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible, Impossible>;
@@ -88,17 +88,17 @@ impl ToComputedValue for Factor {
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         Factor(NumberOrPercentage::Number(
             ToComputedValue::from_computed_value(&computed.0),
         ))
     }
 }
 
 /// A specified value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<Option<RGBAColor>, Length, Option<NonNegativeLength>>;
+pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<NonNegativeLength>>;
 
 impl Parse for BoxShadow {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         let mut lengths = None;
         let mut color = None;
@@ -130,17 +130,17 @@ impl Parse for BoxShadow {
                     Ok((horizontal, vertical, blur, spread))
                 });
                 if let Ok(value) = value {
                     lengths = Some(value);
                     continue;
                 }
             }
             if color.is_none() {
-                if let Ok(value) = input.try(|i| RGBAColor::parse(context, i)) {
+                if let Ok(value) = input.try(|i| Color::parse(context, i)) {
                     color = Some(value);
                     continue;
                 }
             }
             break;
         }
 
         let lengths = lengths.ok_or(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))?;
@@ -244,48 +244,53 @@ impl Parse for Filter {
 }
 
 impl Parse for SimpleShadow {
     #[inline]
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
-        let color = input.try(|i| RGBAColor::parse(context, i)).ok();
+        let color = input.try(|i| Color::parse(context, i)).ok();
         let horizontal = Length::parse(context, input)?;
         let vertical = Length::parse(context, input)?;
         let blur = input.try(|i| Length::parse_non_negative(context, i)).ok();
-        let color = color.or_else(|| input.try(|i| RGBAColor::parse(context, i)).ok());
+        let blur = blur.map(NonNegative::<Length>);
+        let color = color.or_else(|| input.try(|i| Color::parse(context, i)).ok());
+
         Ok(SimpleShadow {
-            color: color,
-            horizontal: horizontal,
-            vertical: vertical,
-            blur: blur.map(NonNegative::<Length>),
+            color,
+            horizontal,
+            vertical,
+            blur,
         })
     }
 }
 
 impl ToComputedValue for SimpleShadow {
     type ComputedValue = ComputedSimpleShadow;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         ComputedSimpleShadow {
-            color: self.color.to_computed_value(context),
+            color: self.color
+                .as_ref()
+                .unwrap_or(&Color::currentcolor())
+                .to_computed_value(context),
             horizontal: self.horizontal.to_computed_value(context),
             vertical: self.vertical.to_computed_value(context),
             blur: self.blur
                 .as_ref()
                 .unwrap_or(&NonNegativeLength::zero())
                 .to_computed_value(context),
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         SimpleShadow {
-            color: ToComputedValue::from_computed_value(&computed.color),
+            color: Some(ToComputedValue::from_computed_value(&computed.color)),
             horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
             vertical: ToComputedValue::from_computed_value(&computed.vertical),
             blur: Some(ToComputedValue::from_computed_value(&computed.blur)),
         }
     }
 }