diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 4d10b9e8fa6..cc96ea02657 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1388,7 +1388,7 @@ impl FragmentDisplayListBuilding for Fragment { box_shadow.base.horizontal, box_shadow.base.vertical, )), - box_shadow.base.blur, + box_shadow.base.blur.0, box_shadow.spread, ); @@ -1403,7 +1403,7 @@ impl FragmentDisplayListBuilding for Fragment { box_bounds: *absolute_bounds, color: style.resolve_color(box_shadow.base.color).to_gfx_color(), 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, border_radius: model::specified_border_radius(style.get_border() .border_top_left_radius, @@ -2049,7 +2049,7 @@ impl FragmentDisplayListBuilding for Fragment { let effects = self.style().get_effects(); let mut filters = effects.filter.0.clone(); if effects.opacity != 1.0 { - filters.push(Filter::Opacity(effects.opacity)) + filters.push(Filter::Opacity(effects.opacity.into())) } let context_type = match mode { @@ -2124,7 +2124,7 @@ impl FragmentDisplayListBuilding for Fragment { for shadow in text_shadows.iter().rev() { state.add_display_item(DisplayItem::PushTextShadow(box PushTextShadowDisplayItem { base: base.clone(), - blur_radius: shadow.blur, + blur_radius: shadow.blur.0, offset: Vector2D::new(shadow.horizontal, shadow.vertical), color: self.style().resolve_color(shadow.color).to_gfx_color(), })); diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index be596745318..fd2d5698efd 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -2570,7 +2570,7 @@ impl Fragment { // Box shadows cause us to draw outside our border box. for box_shadow in &self.style().get_effects().box_shadow.0 { 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) .inflate(inflation, inflation)) } diff --git a/components/layout/webrender_helpers.rs b/components/layout/webrender_helpers.rs index d33638d08d2..969368a98a8 100644 --- a/components/layout/webrender_helpers.rs +++ b/components/layout/webrender_helpers.rs @@ -190,15 +190,15 @@ impl ToFilterOps for Vec { let mut result = Vec::with_capacity(self.len()); for filter in self.iter() { match *filter { - GenericFilter::Blur(radius) => result.push(webrender_api::FilterOp::Blur(radius.to_f32_px())), - GenericFilter::Brightness(amount) => result.push(webrender_api::FilterOp::Brightness(amount)), - GenericFilter::Contrast(amount) => result.push(webrender_api::FilterOp::Contrast(amount)), - GenericFilter::Grayscale(amount) => result.push(webrender_api::FilterOp::Grayscale(amount)), + GenericFilter::Blur(radius) => result.push(webrender_api::FilterOp::Blur(radius.0.to_f32_px())), + GenericFilter::Brightness(amount) => result.push(webrender_api::FilterOp::Brightness(amount.0)), + GenericFilter::Contrast(amount) => result.push(webrender_api::FilterOp::Contrast(amount.0)), + GenericFilter::Grayscale(amount) => result.push(webrender_api::FilterOp::Grayscale(amount.0)), GenericFilter::HueRotate(angle) => result.push(webrender_api::FilterOp::HueRotate(angle.radians())), - GenericFilter::Invert(amount) => result.push(webrender_api::FilterOp::Invert(amount)), - GenericFilter::Opacity(amount) => result.push(webrender_api::FilterOp::Opacity(amount.into())), - GenericFilter::Saturate(amount) => result.push(webrender_api::FilterOp::Saturate(amount)), - GenericFilter::Sepia(amount) => result.push(webrender_api::FilterOp::Sepia(amount)), + GenericFilter::Invert(amount) => result.push(webrender_api::FilterOp::Invert(amount.0)), + GenericFilter::Opacity(amount) => result.push(webrender_api::FilterOp::Opacity(amount.0.into())), + GenericFilter::Saturate(amount) => result.push(webrender_api::FilterOp::Saturate(amount.0)), + GenericFilter::Sepia(amount) => result.push(webrender_api::FilterOp::Sepia(amount.0)), GenericFilter::DropShadow(ref shadow) => match *shadow {}, } } diff --git a/components/style/gecko/values.rs b/components/style/gecko/values.rs index 194627e84b2..9d961ee18c3 100644 --- a/components/style/gecko/values.rs +++ b/components/style/gecko/values.rs @@ -17,9 +17,9 @@ 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, NonNegative}; use values::generics::basic_shape::ShapeRadius; @@ -155,6 +155,16 @@ impl GeckoStyleCoordConvertible for NonNegativeAu { } } +impl GeckoStyleCoordConvertible for NonNegativeNumber { + fn to_gecko_style_coord(&self, coord: &mut T) { + self.0.to_gecko_style_coord(coord); + } + + fn from_gecko_style_coord(coord: &T) -> Option { + Number::from_gecko_style_coord(coord).map(NonNegative::) + } +} + impl GeckoStyleCoordConvertible for LengthOrPercentageOrAuto { fn to_gecko_style_coord(&self, coord: &mut T) { let value = match *self { diff --git a/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs b/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs index 0efebc94c19..0111256d5d1 100644 --- a/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs +++ b/components/style/gecko_bindings/sugar/ns_css_shadow_item.rs @@ -27,7 +27,7 @@ impl nsCSSShadowItem { color: Color::rgba(convert_nscolor_to_rgba(self.mColor)), horizontal: Au(self.mXOffset), vertical: Au(self.mYOffset), - blur: Au(self.mRadius), + blur: Au(self.mRadius).into(), }, spread: Au(self.mSpread), inset: self.mInset, @@ -39,7 +39,7 @@ impl nsCSSShadowItem { 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() { @@ -62,7 +62,7 @@ impl nsCSSShadowItem { color: Color::rgba(convert_nscolor_to_rgba(self.mColor)), horizontal: Au(self.mXOffset), vertical: Au(self.mYOffset), - blur: Au(self.mRadius), + blur: Au(self.mRadius).into(), } } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 5f292cd40e3..b45990870b8 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -4420,11 +4420,11 @@ fn static_assert() { 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, @@ -4492,7 +4492,7 @@ fn static_assert() { }, % 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 => { diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 7b932fc5449..746532ac78e 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -3192,7 +3192,7 @@ fn add_weighted_filter_function_impl(from: &AnimatedFilter, &to_value, self_portion, other_portion, - &0.0, + &NonNegative::(0.0), )?)) }, % endfor @@ -3203,7 +3203,7 @@ fn add_weighted_filter_function_impl(from: &AnimatedFilter, &to_value, self_portion, other_portion, - &1.0, + &NonNegative::(1.0), )?)) }, % endfor diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index cb0fc8799d4..9bd3456d028 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -12,8 +12,8 @@ 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; @@ -32,7 +32,7 @@ pub type TextShadowList = ShadowList; pub struct ShadowList(Vec); /// An animated value for a single `box-shadow`. -pub type BoxShadow = GenericBoxShadow; +pub type BoxShadow = GenericBoxShadow; /// An animated value for the `filter` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -41,14 +41,14 @@ pub struct FilterList(pub Vec); /// An animated value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// An animated value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// An animated value for the `drop-shadow()` filter. -pub type SimpleShadow = GenericSimpleShadow; +pub type SimpleShadow = GenericSimpleShadow; impl ToAnimatedValue for ComputedBoxShadowList { type AnimatedValue = BoxShadowList; diff --git a/components/style/values/computed/effects.rs b/components/style/values/computed/effects.rs index b718ea7f265..fb87c58bf6f 100644 --- a/components/style/values/computed/effects.rs +++ b/components/style/values/computed/effects.rs @@ -6,23 +6,23 @@ #[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; +pub type BoxShadow = GenericBoxShadow; /// A computed value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A computed value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A computed value for the `drop-shadow()` filter. -pub type SimpleShadow = GenericSimpleShadow; +pub type SimpleShadow = GenericSimpleShadow; diff --git a/components/style/values/generics/effects.rs b/components/style/values/generics/effects.rs index f0a6cbc0b8b..9105123f5ab 100644 --- a/components/style/values/generics/effects.rs +++ b/components/style/values/generics/effects.rs @@ -12,9 +12,9 @@ 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 { +pub struct BoxShadow { /// The base shadow. - pub base: SimpleShadow, + pub base: SimpleShadow, /// The spread radius. pub spread: ShapeLength, /// Whether this is an inset box shadow. @@ -77,10 +77,14 @@ pub struct SimpleShadow { pub blur: ShapeLength, } -impl ToCss for BoxShadow +impl ToCss for BoxShadow where Color: ToCss, SizeLength: ToCss, + BlurShapeLength: ToCss, ShapeLength: ToCss, { fn to_css(&self, dest: &mut W) -> fmt::Result diff --git a/components/style/values/specified/effects.rs b/components/style/values/specified/effects.rs index 134827e958e..27bf0f531aa 100644 --- a/components/style/values/specified/effects.rs +++ b/components/style/values/specified/effects.rs @@ -9,28 +9,29 @@ 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::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::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, Length, Option>; +pub type BoxShadow = GenericBoxShadow, Length, Option, Option>; /// A specified value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A specified value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type Filter = GenericFilter; +pub type Filter = GenericFilter; /// A value for the `` parts in `Filter`. #[derive(Clone, Debug, HasViewportPercentage, PartialEq, ToCss)] @@ -48,25 +49,25 @@ impl Parse for 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) => n.into(), + NumberOrPercentage::Percentage(p) => p.0.into(), } } #[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, Length, Option>; +pub type SimpleShadow = GenericSimpleShadow, Length, Option>; impl Parse for BoxShadow { 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)) { Ok(blur) => { let spread = i.try(|i| Length::parse(context, i)).ok(); - (Some(blur), spread) + (Some(blur.into()), spread) }, Err(_) => (None, None), }; @@ -162,7 +163,7 @@ impl Parse for Filter { let function = input.expect_function()?.clone(); 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((Length::parse_non_negative(context, i)?).into())), "brightness" => Ok(GenericFilter::Brightness(Factor::parse(context, i)?)), "contrast" => Ok(GenericFilter::Contrast(Factor::parse(context, i)?)), "grayscale" => Ok(GenericFilter::Grayscale(Factor::parse(context, i)?)), @@ -192,7 +193,7 @@ impl Parse for SimpleShadow { color: color, horizontal: horizontal, vertical: vertical, - blur: blur, + blur: blur.map(NonNegative::), }) } } @@ -208,7 +209,7 @@ impl ToComputedValue for SimpleShadow { 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), } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index a9675bcbd24..8959743655e 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -733,6 +733,20 @@ impl Parse for Either { } } +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. pub type NonNegativeLengthOrNormal = Either; diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 202bdf808a2..3cf56a1dc7f 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -1241,13 +1241,15 @@ mod shorthand_serialization { #[test] fn box_shadow_should_serialize_correctly() { + use style::values::specified::length::NonNegativeLength; + let mut properties = Vec::new(); let shadow_val = BoxShadow { base: SimpleShadow { color: None, horizontal: Length::from_px(1f32), vertical: Length::from_px(2f32), - blur: Some(Length::from_px(3f32)), + blur: Some(NonNegativeLength::from_px(3f32)), }, spread: Some(Length::from_px(4f32)), inset: false,