Bug 1374233 - Part 13: Use NonNegative{*} types for components of Shadow and Filter.

MozReview-Commit-ID: Im4KGy1n9IJ
This commit is contained in:
Boris Chiou 2017-07-24 18:08:27 +08:00
parent 6dd8b159d7
commit 8651acd94c
13 changed files with 84 additions and 53 deletions

View file

@ -1388,7 +1388,7 @@ impl FragmentDisplayListBuilding for Fragment {
box_shadow.base.horizontal, box_shadow.base.horizontal,
box_shadow.base.vertical, box_shadow.base.vertical,
)), )),
box_shadow.base.blur, box_shadow.base.blur.0,
box_shadow.spread, box_shadow.spread,
); );
@ -1403,7 +1403,7 @@ impl FragmentDisplayListBuilding for Fragment {
box_bounds: *absolute_bounds, box_bounds: *absolute_bounds,
color: style.resolve_color(box_shadow.base.color).to_gfx_color(), color: style.resolve_color(box_shadow.base.color).to_gfx_color(),
offset: Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical), offset: Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical),
blur_radius: box_shadow.base.blur, blur_radius: box_shadow.base.blur.0,
spread_radius: box_shadow.spread, spread_radius: box_shadow.spread,
border_radius: model::specified_border_radius(style.get_border() border_radius: model::specified_border_radius(style.get_border()
.border_top_left_radius, .border_top_left_radius,
@ -2049,7 +2049,7 @@ impl FragmentDisplayListBuilding for Fragment {
let effects = self.style().get_effects(); let effects = self.style().get_effects();
let mut filters = effects.filter.0.clone(); let mut filters = effects.filter.0.clone();
if effects.opacity != 1.0 { if effects.opacity != 1.0 {
filters.push(Filter::Opacity(effects.opacity)) filters.push(Filter::Opacity(effects.opacity.into()))
} }
let context_type = match mode { let context_type = match mode {
@ -2124,7 +2124,7 @@ impl FragmentDisplayListBuilding for Fragment {
for shadow in text_shadows.iter().rev() { for shadow in text_shadows.iter().rev() {
state.add_display_item(DisplayItem::PushTextShadow(box PushTextShadowDisplayItem { state.add_display_item(DisplayItem::PushTextShadow(box PushTextShadowDisplayItem {
base: base.clone(), base: base.clone(),
blur_radius: shadow.blur, blur_radius: shadow.blur.0,
offset: Vector2D::new(shadow.horizontal, shadow.vertical), offset: Vector2D::new(shadow.horizontal, shadow.vertical),
color: self.style().resolve_color(shadow.color).to_gfx_color(), color: self.style().resolve_color(shadow.color).to_gfx_color(),
})); }));

View file

@ -2570,7 +2570,7 @@ impl Fragment {
// Box shadows cause us to draw outside our border box. // Box shadows cause us to draw outside our border box.
for box_shadow in &self.style().get_effects().box_shadow.0 { for box_shadow in &self.style().get_effects().box_shadow.0 {
let offset = Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical); let offset = Vector2D::new(box_shadow.base.horizontal, box_shadow.base.vertical);
let inflation = box_shadow.spread + box_shadow.base.blur * BLUR_INFLATION_FACTOR; let inflation = box_shadow.spread + box_shadow.base.blur.0 * BLUR_INFLATION_FACTOR;
overflow.paint = overflow.paint.union(&border_box.translate(&offset) overflow.paint = overflow.paint.union(&border_box.translate(&offset)
.inflate(inflation, inflation)) .inflate(inflation, inflation))
} }

View file

@ -190,15 +190,15 @@ impl ToFilterOps for Vec<Filter> {
let mut result = Vec::with_capacity(self.len()); let mut result = Vec::with_capacity(self.len());
for filter in self.iter() { for filter in self.iter() {
match *filter { match *filter {
GenericFilter::Blur(radius) => result.push(webrender_api::FilterOp::Blur(radius.to_f32_px())), GenericFilter::Blur(radius) => result.push(webrender_api::FilterOp::Blur(radius.0.to_f32_px())),
GenericFilter::Brightness(amount) => result.push(webrender_api::FilterOp::Brightness(amount)), GenericFilter::Brightness(amount) => result.push(webrender_api::FilterOp::Brightness(amount.0)),
GenericFilter::Contrast(amount) => result.push(webrender_api::FilterOp::Contrast(amount)), GenericFilter::Contrast(amount) => result.push(webrender_api::FilterOp::Contrast(amount.0)),
GenericFilter::Grayscale(amount) => result.push(webrender_api::FilterOp::Grayscale(amount)), GenericFilter::Grayscale(amount) => result.push(webrender_api::FilterOp::Grayscale(amount.0)),
GenericFilter::HueRotate(angle) => result.push(webrender_api::FilterOp::HueRotate(angle.radians())), GenericFilter::HueRotate(angle) => result.push(webrender_api::FilterOp::HueRotate(angle.radians())),
GenericFilter::Invert(amount) => result.push(webrender_api::FilterOp::Invert(amount)), GenericFilter::Invert(amount) => result.push(webrender_api::FilterOp::Invert(amount.0)),
GenericFilter::Opacity(amount) => result.push(webrender_api::FilterOp::Opacity(amount.into())), GenericFilter::Opacity(amount) => result.push(webrender_api::FilterOp::Opacity(amount.0.into())),
GenericFilter::Saturate(amount) => result.push(webrender_api::FilterOp::Saturate(amount)), GenericFilter::Saturate(amount) => result.push(webrender_api::FilterOp::Saturate(amount.0)),
GenericFilter::Sepia(amount) => result.push(webrender_api::FilterOp::Sepia(amount)), GenericFilter::Sepia(amount) => result.push(webrender_api::FilterOp::Sepia(amount.0)),
GenericFilter::DropShadow(ref shadow) => match *shadow {}, GenericFilter::DropShadow(ref shadow) => match *shadow {},
} }
} }

View file

@ -17,9 +17,9 @@ use nsstring::{nsACString, nsCString};
use std::cmp::max; use std::cmp::max;
use values::{Auto, Either, ExtremumLength, None_, Normal}; use values::{Auto, Either, ExtremumLength, None_, Normal};
use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto}; 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::{MaxLength, MozLength, Percentage};
use values::computed::NonNegativeLengthOrPercentage; use values::computed::{NonNegativeAu, NonNegativeLengthOrPercentage, NonNegativeNumber};
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius; use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
use values::generics::{CounterStyleOrNone, NonNegative}; use values::generics::{CounterStyleOrNone, NonNegative};
use values::generics::basic_shape::ShapeRadius; use values::generics::basic_shape::ShapeRadius;
@ -155,6 +155,16 @@ impl GeckoStyleCoordConvertible for 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(NonNegative::<Number>)
}
}
impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto { impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto {
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) { fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
let value = match *self { let value = match *self {

View file

@ -27,7 +27,7 @@ impl nsCSSShadowItem {
color: Color::rgba(convert_nscolor_to_rgba(self.mColor)), color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
horizontal: Au(self.mXOffset), horizontal: Au(self.mXOffset),
vertical: Au(self.mYOffset), vertical: Au(self.mYOffset),
blur: Au(self.mRadius), blur: Au(self.mRadius).into(),
}, },
spread: Au(self.mSpread), spread: Au(self.mSpread),
inset: self.mInset, inset: self.mInset,
@ -39,7 +39,7 @@ impl nsCSSShadowItem {
pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) { pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) {
self.mXOffset = shadow.horizontal.0; self.mXOffset = shadow.horizontal.0;
self.mYOffset = shadow.vertical.0; self.mYOffset = shadow.vertical.0;
self.mRadius = shadow.blur.0; self.mRadius = shadow.blur.value();
self.mSpread = 0; self.mSpread = 0;
self.mInset = false; self.mInset = false;
if shadow.color.is_currentcolor() { if shadow.color.is_currentcolor() {
@ -62,7 +62,7 @@ impl nsCSSShadowItem {
color: Color::rgba(convert_nscolor_to_rgba(self.mColor)), color: Color::rgba(convert_nscolor_to_rgba(self.mColor)),
horizontal: Au(self.mXOffset), horizontal: Au(self.mXOffset),
vertical: Au(self.mYOffset), vertical: Au(self.mYOffset),
blur: Au(self.mRadius), blur: Au(self.mRadius).into(),
} }
} }
} }

View file

@ -4420,11 +4420,11 @@ fn static_assert() {
match servo { match servo {
% for func in FILTER_FUNCTIONS: % for func in FILTER_FUNCTIONS:
${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()}, ${func}(factor) => fill_filter(NS_STYLE_FILTER_${func.upper()},
CoordDataValue::Factor(factor), CoordDataValue::Factor(factor.0),
gecko_filter), gecko_filter),
% endfor % endfor
Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR, Blur(length) => fill_filter(NS_STYLE_FILTER_BLUR,
CoordDataValue::Coord(length.0), CoordDataValue::Coord(length.value()),
gecko_filter), gecko_filter),
HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE, HueRotate(angle) => fill_filter(NS_STYLE_FILTER_HUE_ROTATE,
@ -4492,7 +4492,7 @@ fn static_assert() {
}, },
% endfor % endfor
NS_STYLE_FILTER_BLUR => { 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())); &filter.mFilterParameter).unwrap()));
}, },
NS_STYLE_FILTER_HUE_ROTATE => { NS_STYLE_FILTER_HUE_ROTATE => {

View file

@ -3192,7 +3192,7 @@ fn add_weighted_filter_function_impl(from: &AnimatedFilter,
&to_value, &to_value,
self_portion, self_portion,
other_portion, other_portion,
&0.0, &NonNegative::<CSSFloat>(0.0),
)?)) )?))
}, },
% endfor % endfor
@ -3203,7 +3203,7 @@ fn add_weighted_filter_function_impl(from: &AnimatedFilter,
&to_value, &to_value,
self_portion, self_portion,
other_portion, other_portion,
&1.0, &NonNegative::<CSSFloat>(1.0),
)?)) )?))
}, },
% endfor % endfor

View file

@ -12,8 +12,8 @@ use std::cmp;
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; use values::Impossible;
use values::animated::{ToAnimatedValue, ToAnimatedZero}; use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::{Angle, Number}; use values::computed::{Angle, NonNegativeNumber};
use values::computed::length::Length; use values::computed::length::{Length, NonNegativeLength};
use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter; use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
@ -32,7 +32,7 @@ pub type TextShadowList = ShadowList<SimpleShadow>;
pub struct ShadowList<Shadow>(Vec<Shadow>); pub struct ShadowList<Shadow>(Vec<Shadow>);
/// An animated value for a single `box-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. /// An animated value for the `filter` property.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
@ -41,14 +41,14 @@ pub struct FilterList(pub Vec<Filter>);
/// An animated value for a single `filter`. /// An animated value for a single `filter`.
#[cfg(feature = "gecko")] #[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`. /// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[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. /// 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 { impl ToAnimatedValue for ComputedBoxShadowList {
type AnimatedValue = BoxShadowList; type AnimatedValue = BoxShadowList;

View file

@ -6,23 +6,23 @@
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; use values::Impossible;
use values::computed::{Angle, Number}; use values::computed::{Angle, NonNegativeNumber};
use values::computed::color::Color; 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::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter; use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
/// A computed value for a single shadow of the `box-shadow` property. /// 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`. /// A computed value for a single `filter`.
#[cfg(feature = "gecko")] #[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`. /// A computed value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[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. /// A computed value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>; pub type SimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>;

View file

@ -12,9 +12,9 @@ use values::specified::url::SpecifiedUrl;
/// A generic value for a single `box-shadow`. /// A generic value for a single `box-shadow`.
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)] #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToAnimatedValue)]
pub struct BoxShadow<Color, SizeLength, ShapeLength> { pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow. /// The base shadow.
pub base: SimpleShadow<Color, SizeLength, ShapeLength>, pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
/// The spread radius. /// The spread radius.
pub spread: ShapeLength, pub spread: ShapeLength,
/// Whether this is an inset box shadow. /// Whether this is an inset box shadow.
@ -77,10 +77,14 @@ pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
pub blur: ShapeLength, 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 where
Color: ToCss, Color: ToCss,
SizeLength: ToCss, SizeLength: ToCss,
BlurShapeLength: ToCss,
ShapeLength: ToCss, ShapeLength: ToCss,
{ {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result fn to_css<W>(&self, dest: &mut W) -> fmt::Result

View file

@ -9,28 +9,29 @@ use parser::{Parse, ParserContext};
use style_traits::{ParseError, StyleParseError}; use style_traits::{ParseError, StyleParseError};
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
use values::Impossible; 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::BoxShadow as ComputedBoxShadow;
use values::computed::effects::SimpleShadow as ComputedSimpleShadow; use values::computed::effects::SimpleShadow as ComputedSimpleShadow;
use values::generics::NonNegative;
use values::generics::effects::BoxShadow as GenericBoxShadow; use values::generics::effects::BoxShadow as GenericBoxShadow;
use values::generics::effects::Filter as GenericFilter; use values::generics::effects::Filter as GenericFilter;
use values::generics::effects::SimpleShadow as GenericSimpleShadow; use values::generics::effects::SimpleShadow as GenericSimpleShadow;
use values::specified::{Angle, NumberOrPercentage}; use values::specified::{Angle, NumberOrPercentage};
use values::specified::color::Color; use values::specified::color::Color;
use values::specified::length::Length; use values::specified::length::{Length, NonNegativeLength};
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
use values::specified::url::SpecifiedUrl; use values::specified::url::SpecifiedUrl;
/// A specified value for a single shadow of the `box-shadow` property. /// 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`. /// A specified value for a single `filter`.
#[cfg(feature = "gecko")] #[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`. /// A specified value for a single `filter`.
#[cfg(not(feature = "gecko"))] #[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`. /// A value for the `<factor>` parts in `Filter`.
#[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)]
@ -48,25 +49,25 @@ impl Parse for Factor {
} }
impl ToComputedValue for Factor { impl ToComputedValue for Factor {
type ComputedValue = ComputedNumber; type ComputedValue = ComputedNonNegativeNumber;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
use values::computed::NumberOrPercentage; use values::computed::NumberOrPercentage;
match self.0.to_computed_value(context) { match self.0.to_computed_value(context) {
NumberOrPercentage::Number(n) => n, NumberOrPercentage::Number(n) => n.into(),
NumberOrPercentage::Percentage(p) => p.0, NumberOrPercentage::Percentage(p) => p.0.into(),
} }
} }
#[inline] #[inline]
fn from_computed_value(computed: &Self::ComputedValue) -> Self { 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. /// 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 { impl Parse for BoxShadow {
fn parse<'i, 't>( fn parse<'i, 't>(
@ -91,7 +92,7 @@ impl Parse for BoxShadow {
let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) { let (blur, spread) = match i.try::<_, _, ParseError>(|i| Length::parse_non_negative(context, i)) {
Ok(blur) => { Ok(blur) => {
let spread = i.try(|i| Length::parse(context, i)).ok(); let spread = i.try(|i| Length::parse(context, i)).ok();
(Some(blur), spread) (Some(blur.into()), spread)
}, },
Err(_) => (None, None), Err(_) => (None, None),
}; };
@ -162,7 +163,7 @@ impl Parse for Filter {
let function = input.expect_function()?.clone(); let function = input.expect_function()?.clone();
input.parse_nested_block(|i| { input.parse_nested_block(|i| {
try_match_ident_ignore_ascii_case! { function, try_match_ident_ignore_ascii_case! { function,
"blur" => Ok(GenericFilter::Blur(Length::parse_non_negative(context, i)?)), "blur" => Ok(GenericFilter::Blur((Length::parse_non_negative(context, i)?).into())),
"brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)), "brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)),
"contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)), "contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)),
"grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)), "grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)),
@ -192,7 +193,7 @@ impl Parse for SimpleShadow {
color: color, color: color,
horizontal: horizontal, horizontal: horizontal,
vertical: vertical, vertical: vertical,
blur: blur, blur: blur.map(NonNegative::<Length>),
}) })
} }
} }
@ -208,7 +209,7 @@ impl ToComputedValue for SimpleShadow {
horizontal: self.horizontal.to_computed_value(context), horizontal: self.horizontal.to_computed_value(context),
vertical: self.vertical.to_computed_value(context), vertical: self.vertical.to_computed_value(context),
blur: 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),
} }
} }

View file

@ -733,6 +733,20 @@ impl<T: Parse> Parse for Either<NonNegativeLength, T> {
} }
} }
impl NonNegativeLength {
/// Returns a `zero` length.
#[inline]
pub fn zero() -> Self {
Length::zero().into()
}
/// Get an absolute length from a px value.
#[inline]
pub fn from_px(px_value: CSSFloat) -> Self {
Length::from_px(px_value.max(0.)).into()
}
}
/// Either a NonNegativeLength or the `normal` keyword. /// Either a NonNegativeLength or the `normal` keyword.
pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>; pub type NonNegativeLengthOrNormal = Either<NonNegativeLength, Normal>;

View file

@ -1241,13 +1241,15 @@ mod shorthand_serialization {
#[test] #[test]
fn box_shadow_should_serialize_correctly() { fn box_shadow_should_serialize_correctly() {
use style::values::specified::length::NonNegativeLength;
let mut properties = Vec::new(); let mut properties = Vec::new();
let shadow_val = BoxShadow { let shadow_val = BoxShadow {
base: SimpleShadow { base: SimpleShadow {
color: None, color: None,
horizontal: Length::from_px(1f32), horizontal: Length::from_px(1f32),
vertical: Length::from_px(2f32), vertical: Length::from_px(2f32),
blur: Some(Length::from_px(3f32)), blur: Some(NonNegativeLength::from_px(3f32)),
}, },
spread: Some(Length::from_px(4f32)), spread: Some(Length::from_px(4f32)),
inset: false, inset: false,