Bug 1374233 - Part 13: Clamp negatives for Shadow and Filter. draft
authorBoris Chiou <boris.chiou@gmail.com>
Mon, 24 Jul 2017 18:08:27 +0800
changeset 615004 2e2639f238bef340aa2f66db95c7bf4edf4dd0a2
parent 615003 3321c2b8ddb7d5c80c960906e1499fa339788cc6
child 615005 6fc6480b4a35a61d83e3e348be5009d58e8c908f
push id70205
push userbmo:boris.chiou@gmail.com
push dateTue, 25 Jul 2017 08:53:17 +0000
bugs1374233
milestone56.0a1
Bug 1374233 - Part 13: Clamp negatives for Shadow and Filter. MozReview-Commit-ID: Im4KGy1n9IJ
servo/components/style/gecko/values.rs
servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/values/animated/effects.rs
servo/components/style/values/computed/effects.rs
servo/components/style/values/generics/effects.rs
servo/components/style/values/specified/effects.rs
servo/components/style/values/specified/length.rs
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -12,19 +12,19 @@ use cssparser::RGBA;
 use gecko_bindings::structs::{CounterStylePtr, nsStyleCoord};
 use gecko_bindings::structs::{StyleGridTrackBreadth, StyleShapeRadius};
 use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
 use media_queries::Device;
 use nsstring::{nsACString, nsCString};
 use std::cmp::max;
 use values::{Auto, Either, ExtremumLength, None_, Normal};
 use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto};
-use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage, NonNegativeAu};
+use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
 use values::computed::{MaxLength, MozLength, Percentage};
-use values::computed::NonNegativeLengthOrPercentage;
+use values::computed::{NonNegativeAu, NonNegativeLengthOrPercentage, NonNegativeNumber};
 use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
 use values::generics::CounterStyleOrNone;
 use values::generics::basic_shape::ShapeRadius;
 use values::generics::gecko::ScrollSnapPoint;
 use values::generics::grid::{TrackBreadth, TrackKeyword};
 
 /// A trait that defines an interface to convert from and to `nsStyleCoord`s.
 pub trait GeckoStyleCoordConvertible : Sized {
@@ -150,16 +150,26 @@ impl GeckoStyleCoordConvertible for NonN
         self.0.to_gecko_style_coord(coord);
     }
 
     fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
         Au::from_gecko_style_coord(coord).map(NonNegativeAu)
     }
 }
 
+impl GeckoStyleCoordConvertible for NonNegativeNumber {
+    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
+        self.0.to_gecko_style_coord(coord);
+    }
+
+    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
+        Number::from_gecko_style_coord(coord).map(NonNegativeNumber)
+    }
+}
+
 impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
     fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
         let value = match *self {
             LengthOrPercentageOrAuto::Length(au) => CoordDataValue::Coord(au.0),
             LengthOrPercentageOrAuto::Percentage(p) => CoordDataValue::Percent(p.0),
             LengthOrPercentageOrAuto::Auto => CoordDataValue::Auto,
             LengthOrPercentageOrAuto::Calc(calc) => CoordDataValue::Calc(calc.into()),
         };
--- a/servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs
@@ -2,17 +2,17 @@
  * 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_rgba_to_nscolor, convert_nscolor_to_rgba};
 use gecko_bindings::structs::nsCSSShadowItem;
-use values::computed::Color;
+use values::computed::{Color, NonNegativeAu};
 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.0;
@@ -22,29 +22,29 @@ impl nsCSSShadowItem {
     /// Returns this item as a box shadow.
     #[inline]
     pub fn to_box_shadow(&self) -> BoxShadow {
         BoxShadow {
             base: SimpleShadow {
                 color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
                 horizontal: Au(self.mXOffset),
                 vertical: Au(self.mYOffset),
-                blur: Au(self.mRadius),
+                blur: NonNegativeAu(Au(self.mRadius)),
             },
             spread: Au(self.mSpread),
             inset: self.mInset,
         }
     }
 
     /// Sets this item from the given simple shadow.
     #[inline]
     pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) {
         self.mXOffset = shadow.horizontal.0;
         self.mYOffset = shadow.vertical.0;
-        self.mRadius = shadow.blur.0;
+        self.mRadius = shadow.blur.value();
         self.mSpread = 0;
         self.mInset = false;
         if shadow.color.is_currentcolor() {
             // TODO handle currentColor
             // https://bugzilla.mozilla.org/show_bug.cgi?id=760345
             self.mHasColor = false;
             self.mColor = 0;
         } else {
@@ -57,12 +57,12 @@ impl nsCSSShadowItem {
     #[inline]
     pub fn to_simple_shadow(&self) -> SimpleShadow {
         debug_assert_eq!(self.mSpread, 0);
         debug_assert_eq!(self.mInset, false);
         SimpleShadow {
             color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
             horizontal: Au(self.mXOffset),
             vertical: Au(self.mYOffset),
-            blur: Au(self.mRadius),
+            blur: NonNegativeAu(Au(self.mRadius)),
         }
     }
 }
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -3863,21 +3863,21 @@ fn static_assert() {
             Gecko_ResetFilters(&mut self.gecko, v.len());
         }
         debug_assert_eq!(v.len(), self.gecko.mFilters.len());
 
         for (servo, gecko_filter) in v.zip(self.gecko.mFilters.iter_mut()) {
             match servo {
                 % for func in FILTER_FUNCTIONS:
                 ${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()},
-                                               CoordDataValue::Factor(factor),
+                                               CoordDataValue::Factor(factor.0),
                                                gecko_filter),
                 % endfor
                 Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR,
-                                            CoordDataValue::Coord(length.0),
+                                            CoordDataValue::Coord(length.value()),
                                             gecko_filter),
 
                 HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
                                                 CoordDataValue::from(angle),
                                                 gecko_filter),
 
                 DropShadow(shadow) => {
                     gecko_filter.mType = NS_STYLE_FILTER_DROP_SHADOW;
@@ -3931,17 +3931,17 @@ fn static_assert() {
                 % for func in FILTER_FUNCTIONS:
                 NS_STYLE_FILTER_${func.upper()} => {
                     filters.push(Filter::${func}(
                         GeckoStyleCoordConvertible::from_gecko_style_coord(
                             &filter.mFilterParameter).unwrap()));
                 },
                 % endfor
                 NS_STYLE_FILTER_BLUR => {
-                    filters.push(Filter::Blur(Au::from_gecko_style_coord(
+                    filters.push(Filter::Blur(NonNegativeAu::from_gecko_style_coord(
                         &filter.mFilterParameter).unwrap()));
                 },
                 NS_STYLE_FILTER_HUE_ROTATE => {
                     filters.push(Filter::HueRotate(
                         GeckoStyleCoordConvertible::from_gecko_style_coord(
                             &filter.mFilterParameter).unwrap()));
                 },
                 NS_STYLE_FILTER_DROP_SHADOW => {
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -3140,28 +3140,28 @@ fn add_weighted_filter_function_impl(fro
         % endfor
         % for func in [ 'Grayscale', 'Invert', 'Sepia' ]:
             (&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
                 Ok(Filter::${func}(add_weighted_with_initial_val(
                     &from_value,
                     &to_value,
                     self_portion,
                     other_portion,
-                    &0.0,
+                    &NonNegativeNumber(0.0),
                 )?))
             },
         % endfor
         % for func in [ 'Brightness', 'Contrast', 'Opacity', 'Saturate' ]:
             (&Filter::${func}(from_value), &Filter::${func}(to_value)) => {
                 Ok(Filter::${func}(add_weighted_with_initial_val(
                     &from_value,
                     &to_value,
                     self_portion,
                     other_portion,
-                    &1.0,
+                    &NonNegativeNumber(1.0),
                 )?))
                 },
         % endfor
         % if product == "gecko":
         (&Filter::DropShadow(ref from_value), &Filter::DropShadow(ref to_value)) => {
             Ok(Filter::DropShadow(from_value.add_weighted(
                 &to_value,
                 self_portion,
--- a/servo/components/style/values/animated/effects.rs
+++ b/servo/components/style/values/animated/effects.rs
@@ -7,18 +7,18 @@
 use properties::animated_properties::{Animatable, IntermediateColor};
 use properties::longhands::box_shadow::computed_value::T as ComputedBoxShadowList;
 use properties::longhands::filter::computed_value::T as ComputedFilterList;
 use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowList;
 use std::cmp;
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
 use values::animated::{ToAnimatedValue, ToAnimatedZero};
-use values::computed::{Angle, Number};
-use values::computed::length::Length;
+use values::computed::{Angle, NonNegativeNumber};
+use values::computed::length::{Length, NonNegativeLength};
 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 the `box-shadow` property.
 pub type BoxShadowList = ShadowList<BoxShadow>;
 
 /// An animated value for the `text-shadow` property.
@@ -27,33 +27,33 @@ pub type TextShadowList = ShadowList<Sim
 /// An animated value for shadow lists.
 ///
 /// https://drafts.csswg.org/css-transitions/#animtype-shadow-list
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Debug, PartialEq)]
 pub struct ShadowList<Shadow>(Vec<Shadow>);
 
 /// An animated value for a single `box-shadow`.
-pub type BoxShadow = GenericBoxShadow<IntermediateColor, Length, Length>;
+pub type BoxShadow = GenericBoxShadow<IntermediateColor, Length, NonNegativeLength, Length>;
 
 /// An animated value for the `filter` property.
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Debug, PartialEq)]
 pub struct FilterList(pub Vec<Filter>);
 
 /// An animated value for a single `filter`.
 #[cfg(feature = "gecko")]
-pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow>;
+pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow>;
 
 /// An animated value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
-pub type Filter = GenericFilter<Angle, Number, Length, Impossible>;
+pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible>;
 
 /// An animated value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, Length>;
+pub type SimpleShadow = GenericSimpleShadow<IntermediateColor, Length, NonNegativeLength>;
 
 impl ToAnimatedValue for ComputedBoxShadowList {
     type AnimatedValue = BoxShadowList;
 
     #[inline]
     fn to_animated_value(self) -> Self::AnimatedValue {
         ShadowList(self.0.to_animated_value())
     }
--- a/servo/components/style/values/computed/effects.rs
+++ b/servo/components/style/values/computed/effects.rs
@@ -1,28 +1,28 @@
 /* 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/. */
 
 //! Computed types for CSS values related to effects.
 
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
-use values::computed::{Angle, Number};
+use values::computed::{Angle, NonNegativeNumber};
 use values::computed::color::Color;
-use values::computed::length::Length;
+use values::computed::length::{Length, NonNegativeLength};
 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<Color, Length, Length>;
+pub type BoxShadow = GenericBoxShadow<Color, Length, NonNegativeLength, Length>;
 
 /// A computed value for a single `filter`.
 #[cfg(feature = "gecko")]
-pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow>;
+pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, SimpleShadow>;
 
 /// A computed value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
-pub type Filter = GenericFilter<Angle, Number, Length, Impossible>;
+pub type Filter = GenericFilter<Angle, NonNegativeNumber, NonNegativeLength, Impossible>;
 
 /// A computed value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>;
+pub type SimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>;
--- a/servo/components/style/values/generics/effects.rs
+++ b/servo/components/style/values/generics/effects.rs
@@ -7,19 +7,19 @@
 use std::fmt;
 use style_traits::values::{SequenceWriter, ToCss};
 #[cfg(feature = "gecko")]
 use values::specified::url::SpecifiedUrl;
 
 /// A generic value for a single `box-shadow`.
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
-pub struct BoxShadow<Color, SizeLength, ShapeLength> {
+pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
     /// The base shadow.
-    pub base: SimpleShadow<Color, SizeLength, ShapeLength>,
+    pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
     /// The spread radius.
     pub spread: ShapeLength,
     /// Whether this is an inset box shadow.
     pub inset: bool,
 }
 
 /// A generic value for a single `filter`.
 #[cfg_attr(feature = "servo", derive(Deserialize, HeapSizeOf, Serialize))]
@@ -72,20 +72,24 @@ pub struct SimpleShadow<Color, SizeLengt
     /// Horizontal radius.
     pub horizontal: SizeLength,
     /// Vertical radius.
     pub vertical: SizeLength,
     /// Blur radius.
     pub blur: ShapeLength,
 }
 
-impl<Color, SizeLength, ShapeLength> ToCss for BoxShadow<Color, SizeLength, ShapeLength>
+impl<Color, SizeLength, BlurShapeLength, ShapeLength> ToCss for BoxShadow<Color,
+                                                                          SizeLength,
+                                                                          BlurShapeLength,
+                                                                          ShapeLength>
 where
     Color: ToCss,
     SizeLength: ToCss,
+    BlurShapeLength: ToCss,
     ShapeLength: ToCss,
 {
     fn to_css<W>(&self, dest: &mut W) -> fmt::Result
     where
         W: fmt::Write,
     {
         {
             let mut writer = SequenceWriter::new(&mut *dest, " ");
--- a/servo/components/style/values/specified/effects.rs
+++ b/servo/components/style/values/specified/effects.rs
@@ -4,38 +4,38 @@
 
 //! Specified types for CSS values related to effects.
 
 use cssparser::Parser;
 use parser::{Parse, ParserContext};
 use style_traits::{ParseError, StyleParseError};
 #[cfg(not(feature = "gecko"))]
 use values::Impossible;
-use values::computed::{Context, Number as ComputedNumber, ToComputedValue};
+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::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::Color;
-use values::specified::length::Length;
+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<Color>, Length, Option<Length>>;
+pub type BoxShadow = GenericBoxShadow<Option<Color>, Length, Option<NonNegativeLength>, Option<Length>>;
 
 /// A specified value for a single `filter`.
 #[cfg(feature = "gecko")]
-pub type Filter = GenericFilter<Angle, Factor, Length, SimpleShadow>;
+pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, SimpleShadow>;
 
 /// A specified value for a single `filter`.
 #[cfg(not(feature = "gecko"))]
-pub type Filter = GenericFilter<Angle, Factor, Length, Impossible>;
+pub type Filter = GenericFilter<Angle, Factor, NonNegativeLength, Impossible>;
 
 /// A value for the `<factor>` parts in `Filter`.
 #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
 #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
 pub struct Factor(NumberOrPercentage);
 
 impl Parse for Factor {
     #[inline]
@@ -43,35 +43,35 @@ impl Parse for Factor {
         context: &ParserContext,
         input: &mut Parser<'i, 't>
     ) -> Result<Self, ParseError<'i>> {
         NumberOrPercentage::parse_non_negative(context, input).map(Factor)
     }
 }
 
 impl ToComputedValue for Factor {
-    type ComputedValue = ComputedNumber;
+    type ComputedValue = ComputedNonNegativeNumber;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         use values::computed::NumberOrPercentage;
         match self.0.to_computed_value(context) {
-            NumberOrPercentage::Number(n) => n,
-            NumberOrPercentage::Percentage(p) => p.0,
+            NumberOrPercentage::Number(n) => ComputedNonNegativeNumber(n),
+            NumberOrPercentage::Percentage(p) => ComputedNonNegativeNumber(p.0),
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
-        Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(computed)))
+        Factor(NumberOrPercentage::Number(ToComputedValue::from_computed_value(&computed.0)))
     }
 }
 
 /// A specified value for the `drop-shadow()` filter.
-pub type SimpleShadow = GenericSimpleShadow<Option<Color>, Length, Option<Length>>;
+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;
@@ -86,17 +86,17 @@ impl Parse for BoxShadow {
             }
             if lengths.is_none() {
                 let value = input.try::<_, _, ParseError>(|i| {
                     let horizontal = Length::parse(context, i)?;
                     let vertical = Length::parse(context, i)?;
                     let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) {
                         Ok(blur) => {
                             let spread = i.try(|i| Length::parse(context, i)).ok();
-                            (Some(blur), spread)
+                            (Some(NonNegativeLength(blur)), spread)
                         },
                         Err(_) => (None, None),
                     };
                     Ok((horizontal, vertical, blur, spread))
                 });
                 if let Ok(value) = value {
                     lengths = Some(value);
                     continue;
@@ -157,17 +157,17 @@ impl Parse for Filter {
         {
             if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
                 return Ok(GenericFilter::Url(url));
             }
         }
         let function = input.expect_function()?;
         input.parse_nested_block(|i| {
             try_match_ident_ignore_ascii_case! { function,
-                "blur" => Ok(GenericFilter::Blur(Length::parse_non_negative(context, i)?)),
+                "blur" => Ok(GenericFilter::Blur(NonNegativeLength(Length::parse_non_negative(context, i)?))),
                 "brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)),
                 "contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)),
                 "grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)),
                 "hue-rotate" => Ok(GenericFilter::HueRotate(Angle::parse(context, i)?)),
                 "invert" => Ok(GenericFilter::Invert(Factor::parse(context, i)?)),
                 "opacity" => Ok(GenericFilter::Opacity(Factor::parse(context, i)?)),
                 "saturate" => Ok(GenericFilter::Saturate(Factor::parse(context, i)?)),
                 "sepia" => Ok(GenericFilter::Sepia(Factor::parse(context, i)?)),
@@ -187,33 +187,33 @@ impl Parse for SimpleShadow {
         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| Color::parse(context, i)).ok());
         Ok(SimpleShadow {
             color: color,
             horizontal: horizontal,
             vertical: vertical,
-            blur: blur,
+            blur: blur.map(NonNegativeLength),
         })
     }
 }
 
 impl ToComputedValue for SimpleShadow {
     type ComputedValue = ComputedSimpleShadow;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
         ComputedSimpleShadow {
             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(&Length::zero()).to_computed_value(context),
+                self.blur.as_ref().unwrap_or(&NonNegativeLength::zero()).to_computed_value(context),
         }
     }
 
     #[inline]
     fn from_computed_value(computed: &Self::ComputedValue) -> Self {
         SimpleShadow {
             color: Some(ToComputedValue::from_computed_value(&computed.color)),
             horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
--- a/servo/components/style/values/specified/length.rs
+++ b/servo/components/style/values/specified/length.rs
@@ -719,16 +719,24 @@ impl<T: Parse> Parse for Either<NonNegat
         if let Ok(v) = input.try(|input| T::parse(context, input)) {
             return Ok(Either::Second(v));
         }
         Length::parse_internal(context, input, AllowedLengthType::NonNegative, AllowQuirks::No)
             .map(NonNegativeLength).map(Either::First)
     }
 }
 
+impl NonNegativeLength {
+    /// Returns a `zero` length.
+    #[inline]
+    pub fn zero() -> Self {
+        NonNegativeLength(Length::zero())
+    }
+}
+
 /// Either a NonNegativeLength or the `normal` keyword.
 pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;
 
 /// Either a NonNegativeLength or the `auto` keyword.
 pub type NonNegativeLengthOrAuto = Either<NonNegativeLength, Auto>;
 
 /// Either a NonNegativeLength or a NonNegativeNumber value.
 pub type NonNegativeLengthOrNumber = Either<NonNegativeLength, NonNegativeNumber>;