commit 0c2f135b248ef12781cd6943a3e0e5ead7b76d31 parent f02daab3a3b1f6bb0ba4bf9bb751a2051311d1fa Author: Emilio Cobos Álvarez <emilio@crisal.io> Date: Thu, 13 Nov 2025 19:14:03 +0000 Bug 1999891 - Make NonNegative easier to use generically. r=sukil Differential Revision: https://phabricator.services.mozilla.com/D272405 Diffstat:
19 files changed, 161 insertions(+), 238 deletions(-)
diff --git a/servo/components/style/properties/helpers/animated_properties.mako.rs b/servo/components/style/properties/helpers/animated_properties.mako.rs @@ -695,7 +695,7 @@ impl Animate for AnimatedFilter { % endfor % for func in ['Brightness', 'Contrast', 'Opacity', 'Saturate']: (&Filter::${func}(this), &Filter::${func}(other)) => { - Ok(Filter::${func}(animate_multiplicative_factor(this, other, procedure)?)) + Ok(Filter::${func}(animate_multiplicative_factor(this.0, other.0, procedure)?.into())) }, % endfor _ => Err(()), @@ -711,7 +711,7 @@ impl ToAnimatedZero for AnimatedFilter { Filter::${func}(ref this) => Ok(Filter::${func}(this.to_animated_zero()?)), % endfor % for func in ['Brightness', 'Contrast', 'Opacity', 'Saturate']: - Filter::${func}(_) => Ok(Filter::${func}(1.)), + Filter::${func}(_) => Ok(Filter::${func}(1.0.into())), % endfor _ => Err(()), } diff --git a/servo/components/style/values/animated/effects.rs b/servo/components/style/values/animated/effects.rs @@ -8,21 +8,19 @@ use crate::values::animated::color::Color; use crate::values::computed::length::Length; #[cfg(feature = "gecko")] use crate::values::computed::url::ComputedUrl; -use crate::values::computed::{Angle, Number}; +use crate::values::computed::{Angle, NonNegativeLength, Number}; use crate::values::generics::effects::Filter as GenericFilter; use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow; #[cfg(not(feature = "gecko"))] use crate::values::Impossible; /// An animated value for the `drop-shadow()` filter. -pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>; +pub type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>; /// An animated value for a single `filter`. #[cfg(feature = "gecko")] -pub type AnimatedFilter = - GenericFilter<Angle, Number, Number, Length, AnimatedSimpleShadow, ComputedUrl>; +pub type AnimatedFilter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>; /// An animated value for a single `filter`. #[cfg(not(feature = "gecko"))] -pub type AnimatedFilter = - GenericFilter<Angle, Number, Number, Length, AnimatedSimpleShadow, Impossible>; +pub type AnimatedFilter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, Impossible>; diff --git a/servo/components/style/values/animated/mod.rs b/servo/components/style/values/animated/mod.rs @@ -12,6 +12,7 @@ use crate::color::AbsoluteColor; use crate::properties::{ComputedValues, PropertyId}; use crate::values::computed::url::ComputedUrl; use crate::values::computed::{Angle, Image, Length}; +use crate::values::generics::{ClampToNonNegative, NonNegative}; use crate::values::specified::SVGPathData; use crate::values::CSSFloat; use app_units::Au; @@ -231,6 +232,20 @@ where } } +impl<T: ToAnimatedValue + ClampToNonNegative> ToAnimatedValue for NonNegative<T> { + type AnimatedValue = NonNegative<<T as ToAnimatedValue>::AnimatedValue>; + + #[inline] + fn to_animated_value(self, cx: &crate::values::animated::Context) -> Self::AnimatedValue { + NonNegative(self.0.to_animated_value(cx)) + } + + #[inline] + fn from_animated_value(animated: Self::AnimatedValue) -> Self { + Self(<T as ToAnimatedValue>::from_animated_value(animated.0).clamp_to_non_negative()) + } +} + impl ToAnimatedValue for Au { type AnimatedValue = Length; diff --git a/servo/components/style/values/computed/basic_shape.rs b/servo/components/style/values/computed/basic_shape.rs @@ -26,16 +26,10 @@ pub type ClipPath = generic::GenericClipPath<BasicShape, ComputedUrl>; pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>; /// A computed basic shape. -pub type BasicShape = generic::GenericBasicShape< - Angle, - Position, - LengthPercentage, - NonNegativeLengthPercentage, - InsetRect, ->; +pub type BasicShape = generic::GenericBasicShape<Angle, Position, LengthPercentage, InsetRect>; /// The computed value of `inset()`. -pub type InsetRect = generic::GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage>; +pub type InsetRect = generic::GenericInsetRect<LengthPercentage>; /// A computed circle. pub type Circle = generic::Circle<Position, NonNegativeLengthPercentage>; diff --git a/servo/components/style/values/computed/effects.rs b/servo/components/style/values/computed/effects.rs @@ -8,7 +8,7 @@ use crate::values::computed::color::Color; use crate::values::computed::length::{Length, NonNegativeLength}; #[cfg(feature = "gecko")] use crate::values::computed::url::ComputedUrl; -use crate::values::computed::{Angle, NonNegativeNumber, ZeroToOneNumber}; +use crate::values::computed::{Angle, Number}; use crate::values::generics::effects::BoxShadow as GenericBoxShadow; use crate::values::generics::effects::Filter as GenericFilter; use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow; @@ -20,25 +20,11 @@ pub type BoxShadow = GenericBoxShadow<Color, Length, NonNegativeLength, Length>; /// A computed value for a single `filter`. #[cfg(feature = "gecko")] -pub type Filter = GenericFilter< - Angle, - NonNegativeNumber, - ZeroToOneNumber, - NonNegativeLength, - SimpleShadow, - ComputedUrl, ->; +pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>; /// A computed value for a single `filter`. #[cfg(feature = "servo")] -pub type Filter = GenericFilter< - Angle, - NonNegativeNumber, - ZeroToOneNumber, - NonNegativeLength, - SimpleShadow, - Impossible, ->; +pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, Impossible>; /// A computed value for the `drop-shadow()` filter. pub type SimpleShadow = GenericSimpleShadow<Color, Length, NonNegativeLength>; diff --git a/servo/components/style/values/computed/image.rs b/servo/components/style/values/computed/image.rs @@ -12,7 +12,7 @@ use crate::values::computed::position::Position; use crate::values::computed::url::ComputedUrl; use crate::values::computed::{Angle, Color, Context}; use crate::values::computed::{ - AngleOrPercentage, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, + AngleOrPercentage, Length, LengthPercentage, NonNegativeLength, NonNegativeLengthPercentage, Resolution, ToComputedValue, }; use crate::values::generics::image::{self as generic, GradientCompatMode}; @@ -38,9 +38,8 @@ size_of_test!(Image, 24); /// <https://drafts.csswg.org/css-images/#gradients> pub type Gradient = generic::GenericGradient< LineDirection, + Length, LengthPercentage, - NonNegativeLength, - NonNegativeLengthPercentage, Position, Angle, AngleOrPercentage, diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs @@ -9,11 +9,11 @@ use crate::logical_geometry::PhysicalSide; use crate::values::animated::{Context as AnimatedContext, ToAnimatedValue}; use crate::values::computed::position::TryTacticAdjustment; use crate::values::computed::{NonNegativeNumber, Percentage, Zoom}; -use crate::values::generics::length as generics; use crate::values::generics::length::{ GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize, }; use crate::values::generics::NonNegative; +use crate::values::generics::{length as generics, ClampToNonNegative}; use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue}; use crate::values::specified::length::{AbsoluteLength, FontBaseSize, LineHeightBase}; use crate::values::{specified, CSSFloat}; @@ -450,17 +450,9 @@ pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>; /// A wrapper of Length, whose value must be >= 0. pub type NonNegativeLength = NonNegative<Length>; -impl ToAnimatedValue for NonNegativeLength { - type AnimatedValue = Length; - - #[inline] - fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue { - self.0.to_animated_value(context) - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - NonNegativeLength::new(animated.px().max(0.)) +impl ClampToNonNegative for Length { + fn clamp_to_non_negative(self) -> Self { + Self::new(self.px().max(0.)) } } diff --git a/servo/components/style/values/computed/length_percentage.rs b/servo/components/style/values/computed/length_percentage.rs @@ -37,7 +37,7 @@ use crate::values::generics::calc::{CalcUnits, PositivePercentageBasis}; #[cfg(feature = "gecko")] use crate::values::generics::length::AnchorResolutionResult; use crate::values::generics::position::{AnchorSideKeyword, GenericAnchorSide}; -use crate::values::generics::{calc, NonNegative}; +use crate::values::generics::{calc, ClampToNonNegative, NonNegative}; use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue}; use crate::values::specified::length::{FontBaseSize, LineHeightBase}; use crate::values::{specified, CSSFloat}; @@ -544,10 +544,12 @@ impl LengthPercentage { } Some(self.resolve(container_len?)) } +} +impl ClampToNonNegative for LengthPercentage { /// Returns the clamped non-negative values. #[inline] - pub fn clamp_to_non_negative(mut self) -> Self { + fn clamp_to_non_negative(mut self) -> Self { match self.unpack_mut() { UnpackedMut::Length(l) => Self::new_length(l.clamp_to_non_negative()), UnpackedMut::Percentage(p) => Self::new_percent(p.clamp_to_non_negative()), @@ -1303,20 +1305,6 @@ impl Animate for LengthPercentage { /// A wrapper of LengthPercentage, whose value must be >= 0. pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>; -impl ToAnimatedValue for NonNegativeLengthPercentage { - type AnimatedValue = LengthPercentage; - - #[inline] - fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue { - self.0.to_animated_value(context) - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - NonNegative(animated.clamp_to_non_negative()) - } -} - impl NonNegativeLengthPercentage { /// Returns the used value. #[inline] diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs @@ -27,6 +27,7 @@ use crate::stylesheets::container_rule::{ ContainerInfo, ContainerSizeQuery, ContainerSizeQueryResult, }; use crate::stylist::Stylist; +use crate::values::generics::ClampToNonNegative; use crate::values::specified::font::QueryFontMetricsFlags; use crate::values::specified::length::FontBaseSize; use crate::{ArcSlice, Atom, One}; @@ -798,20 +799,6 @@ impl IsParallelTo for (Number, Number, Number) { /// A wrapper of Number, but the value >= 0. pub type NonNegativeNumber = NonNegative<CSSFloat>; -impl ToAnimatedValue for NonNegativeNumber { - type AnimatedValue = CSSFloat; - - #[inline] - fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { - self.0 - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - animated.max(0.).into() - } -} - impl From<CSSFloat> for NonNegativeNumber { #[inline] fn from(number: CSSFloat) -> NonNegativeNumber { @@ -842,16 +829,16 @@ impl One for NonNegativeNumber { pub type ZeroToOneNumber = ZeroToOne<CSSFloat>; impl ToAnimatedValue for ZeroToOneNumber { - type AnimatedValue = CSSFloat; + type AnimatedValue = Self; #[inline] fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { - self.0 + self } #[inline] fn from_animated_value(animated: Self::AnimatedValue) -> Self { - Self(animated.max(0.).min(1.)) + Self(animated.0.max(0.).min(1.)) } } @@ -903,6 +890,7 @@ impl From<GreaterThanOrEqualToOneNumber> for CSSFloat { MallocSizeOf, PartialEq, ToAnimatedZero, + ToAnimatedValue, ToCss, ToResolvedValue, )] @@ -912,13 +900,13 @@ pub enum NumberOrPercentage { Number(Number), } -impl NumberOrPercentage { +impl ClampToNonNegative for NumberOrPercentage { fn clamp_to_non_negative(self) -> Self { match self { NumberOrPercentage::Percentage(p) => { NumberOrPercentage::Percentage(p.clamp_to_non_negative()) }, - NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.max(0.)), + NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()), } } } @@ -963,20 +951,6 @@ impl NonNegativeNumberOrPercentage { } } -impl ToAnimatedValue for NonNegativeNumberOrPercentage { - type AnimatedValue = NumberOrPercentage; - - #[inline] - fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { - self.0 - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - NonNegative(animated.clamp_to_non_negative()) - } -} - /// A type used for opacity. pub type Opacity = CSSFloat; diff --git a/servo/components/style/values/computed/percentage.rs b/servo/components/style/values/computed/percentage.rs @@ -4,8 +4,7 @@ //! Computed percentages. -use crate::values::animated::ToAnimatedValue; -use crate::values::generics::NonNegative; +use crate::values::generics::{ClampToNonNegative, NonNegative}; use crate::values::specified::percentage::ToPercentage; use crate::values::{serialize_normalized_percentage, CSSFloat}; use crate::Zero; @@ -36,6 +35,13 @@ use style_traits::{CssWriter, ToCss}; #[repr(C)] pub struct Percentage(pub CSSFloat); +impl ClampToNonNegative for Percentage { + #[inline] + fn clamp_to_non_negative(self) -> Self { + Percentage(self.0.max(0.)) + } +} + impl Percentage { /// 100% #[inline] @@ -48,12 +54,6 @@ impl Percentage { pub fn abs(&self) -> Self { Percentage(self.0.abs()) } - - /// Clamps this percentage to a non-negative percentage. - #[inline] - pub fn clamp_to_non_negative(self) -> Self { - Percentage(self.0.max(0.)) - } } impl Zero for Percentage { @@ -121,17 +121,3 @@ impl NonNegativePercentage { NonNegative(Percentage::hundred()) } } - -impl ToAnimatedValue for NonNegativePercentage { - type AnimatedValue = Percentage; - - #[inline] - fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { - self.0 - } - - #[inline] - fn from_animated_value(animated: Self::AnimatedValue) -> Self { - NonNegative(animated.clamp_to_non_negative()) - } -} diff --git a/servo/components/style/values/computed/ratio.rs b/servo/components/style/values/computed/ratio.rs @@ -8,6 +8,7 @@ use crate::values::animated::{Animate, Procedure}; use crate::values::computed::NonNegativeNumber; use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; use crate::values::generics::ratio::Ratio as GenericRatio; +use crate::values::generics::NonNegative; use crate::Zero; use std::cmp::Ordering; @@ -23,17 +24,22 @@ impl PartialOrd for Ratio { } } -impl GenericRatio<f32> { +impl Ratio { /// Returns the f32 value by dividing the first value by the second one. #[inline] fn to_f32(&self) -> f32 { debug_assert!(!self.is_degenerate()); - self.0 / self.1 + (self.0).0 / (self.1).0 + } + /// Returns a new Ratio. + #[inline] + pub fn new(a: f32, b: f32) -> Self { + GenericRatio(a.into(), b.into()) } } /// https://drafts.csswg.org/css-values/#combine-ratio -impl Animate for GenericRatio<f32> { +impl Animate for Ratio { fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> { // If either <ratio> is degenerate, the values cannot be interpolated. if self.is_degenerate() || other.is_degenerate() { @@ -64,11 +70,11 @@ impl Animate for GenericRatio<f32> { if result.is_zero() || result.is_infinite() { return Err(()); } - Ok(GenericRatio(result, 1.0)) + Ok(GenericRatio(NonNegative(result), NonNegative(1.0))) } } -impl ComputeSquaredDistance for GenericRatio<f32> { +impl ComputeSquaredDistance for Ratio { fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> { if self.is_degenerate() || other.is_degenerate() { return Err(()); @@ -80,11 +86,3 @@ impl ComputeSquaredDistance for GenericRatio<f32> { .compute_squared_distance(&other.to_f32().ln()) } } - -impl Ratio { - /// Returns a new Ratio. - #[inline] - pub fn new(a: f32, b: f32) -> Self { - GenericRatio(a.into(), b.into()) - } -} diff --git a/servo/components/style/values/generics/basic_shape.rs b/servo/components/style/values/generics/basic_shape.rs @@ -7,9 +7,12 @@ use crate::values::animated::{lists, Animate, Procedure, ToAnimatedZero}; use crate::values::distance::{ComputeSquaredDistance, SquaredDistance}; -use crate::values::generics::border::GenericBorderRadius; -use crate::values::generics::position::{GenericPosition, GenericPositionOrAuto}; -use crate::values::generics::rect::Rect; +use crate::values::generics::{ + border::GenericBorderRadius, + position::{GenericPosition, GenericPositionOrAuto}, + rect::Rect, + NonNegative, +}; use crate::values::specified::svg_path::{PathCommand, SVGPathData}; use crate::Zero; use std::fmt::{self, Write}; @@ -136,7 +139,7 @@ pub enum GenericClipPath<BasicShape, U> { Url(U), #[typed_value(skip)] Shape( - Box<BasicShape>, + #[animation(field_bound)] Box<BasicShape>, #[css(skip_if = "is_default_box_for_clip_path")] ShapeGeometryBox, ), #[animation(error)] @@ -196,26 +199,22 @@ pub use self::GenericShapeOutside as ShapeOutside; ToShmem, )] #[repr(C, u8)] -pub enum GenericBasicShape< - Angle, - Position, - LengthPercentage, - NonNegativeLengthPercentage, - BasicShapeRect, -> { +pub enum GenericBasicShape<Angle, Position, LengthPercentage, BasicShapeRect> { /// The <basic-shape-rect>. Rect(BasicShapeRect), /// Defines a circle with a center and a radius. Circle( + #[animation(field_bound)] #[css(field_bound)] #[shmem(field_bound)] - Circle<Position, NonNegativeLengthPercentage>, + Circle<Position, NonNegative<LengthPercentage>>, ), /// Defines an ellipse with a center and x-axis/y-axis radii. Ellipse( + #[animation(field_bound)] #[css(field_bound)] #[shmem(field_bound)] - Ellipse<Position, NonNegativeLengthPercentage>, + Ellipse<Position, NonNegative<LengthPercentage>>, ), /// Defines a polygon with pair arguments. Polygon(GenericPolygon<LengthPercentage>), @@ -248,10 +247,11 @@ pub use self::GenericBasicShape as BasicShape; )] #[css(function = "inset")] #[repr(C)] -pub struct GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage> { +pub struct GenericInsetRect<LengthPercentage> { pub rect: Rect<LengthPercentage>, #[shmem(field_bound)] - pub round: GenericBorderRadius<NonNegativeLengthPercentage>, + #[animation(field_bound)] + pub round: GenericBorderRadius<NonNegative<LengthPercentage>>, } pub use self::GenericInsetRect as InsetRect; @@ -492,10 +492,9 @@ impl<B, U> ToAnimatedZero for ShapeOutside<B, U> { } } -impl<Length, NonNegativeLength> ToCss for InsetRect<Length, NonNegativeLength> +impl<Length> ToCss for InsetRect<Length> where - Length: ToCss + PartialEq, - NonNegativeLength: ToCss + PartialEq + Zero, + Length: ToCss + PartialEq + Zero, { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where diff --git a/servo/components/style/values/generics/effects.rs b/servo/components/style/values/generics/effects.rs @@ -4,6 +4,8 @@ //! Generic types for CSS values related to effects. +use crate::values::generics::{NonNegative, ZeroToOne}; + /// A generic value for a single `box-shadow`. #[derive( Animate, @@ -50,34 +52,34 @@ pub use self::GenericBoxShadow as BoxShadow; )] #[animation(no_bound(U))] #[repr(C, u8)] -pub enum GenericFilter<Angle, NonNegativeFactor, ZeroToOneFactor, Length, Shadow, U> { +pub enum GenericFilter<Angle, Factor, Length, Shadow, U> { /// `blur(<length>)` #[css(function)] - Blur(Length), + Blur(#[animation(field_bound)] NonNegative<Length>), /// `brightness(<factor>)` #[css(function)] - Brightness(NonNegativeFactor), + Brightness(#[animation(field_bound)] NonNegative<Factor>), /// `contrast(<factor>)` #[css(function)] - Contrast(NonNegativeFactor), + Contrast(#[animation(field_bound)] NonNegative<Factor>), /// `grayscale(<factor>)` #[css(function)] - Grayscale(ZeroToOneFactor), + Grayscale(#[animation(field_bound)] ZeroToOne<Factor>), /// `hue-rotate(<angle>)` #[css(function)] HueRotate(Angle), /// `invert(<factor>)` #[css(function)] - Invert(ZeroToOneFactor), + Invert(#[animation(field_bound)] ZeroToOne<Factor>), /// `opacity(<factor>)` #[css(function)] - Opacity(ZeroToOneFactor), + Opacity(#[animation(field_bound)] ZeroToOne<Factor>), /// `saturate(<factor>)` #[css(function)] - Saturate(NonNegativeFactor), + Saturate(#[animation(field_bound)] NonNegative<Factor>), /// `sepia(<factor>)` #[css(function)] - Sepia(ZeroToOneFactor), + Sepia(#[animation(field_bound)] ZeroToOne<Factor>), /// `drop-shadow(...)` #[css(function)] DropShadow(Shadow), diff --git a/servo/components/style/values/generics/image.rs b/servo/components/style/values/generics/image.rs @@ -10,8 +10,8 @@ use crate::color::mix::ColorInterpolationMethod; use crate::custom_properties; use crate::values::generics::{color::GenericLightDark, position::PositionComponent, Optional}; use crate::values::serialize_atom_identifier; -use crate::Atom; -use crate::Zero; +use crate::values::generics::NonNegative; +use crate::{Atom, Zero}; use servo_arc::Arc; use std::fmt::{self, Write}; use style_traits::{CssWriter, ToCss}; @@ -185,9 +185,8 @@ bitflags! { #[repr(C)] pub enum GenericGradient< LineDirection, + Length, LengthPercentage, - NonNegativeLength, - NonNegativeLengthPercentage, Position, Angle, AngleOrPercentage, @@ -209,7 +208,7 @@ pub enum GenericGradient< /// A radial gradient. Radial { /// Shape of gradient - shape: GenericEndingShape<NonNegativeLength, NonNegativeLengthPercentage>, + shape: GenericEndingShape<NonNegative<Length>, NonNegative<LengthPercentage>>, /// Center of gradient position: Position, /// Method to use for color interpolation. @@ -446,12 +445,11 @@ where } } -impl<D, LP, NL, NLP, P, A: Zero, AoP, C> ToCss for Gradient<D, LP, NL, NLP, P, A, AoP, C> +impl<D, L, LP, P, A: Zero, AoP, C> ToCss for Gradient<D, L, LP, P, A, AoP, C> where D: LineDirection, + L: ToCss, LP: ToCss, - NL: ToCss, - NLP: ToCss, P: PositionComponent + ToCss, A: ToCss, AoP: ToCss, diff --git a/servo/components/style/values/generics/mod.rs b/servo/components/style/values/generics/mod.rs @@ -61,6 +61,18 @@ pub mod url; #[repr(transparent)] pub struct NonNegative<T>(pub T); +/// A trait to clamp a negative value to another. +pub trait ClampToNonNegative { + /// Clamps the value to be non-negative after an animation. + fn clamp_to_non_negative(self) -> Self; +} + +impl ClampToNonNegative for f32 { + fn clamp_to_non_negative(self) -> Self { + self.max(0.) + } +} + impl<T: Add<Output = T>> Add<NonNegative<T>> for NonNegative<T> { type Output = Self; diff --git a/servo/components/style/values/specified/basic_shape.rs b/servo/components/style/values/specified/basic_shape.rs @@ -42,16 +42,11 @@ pub type ShapeOutside = generic::GenericShapeOutside<BasicShape, Image>; pub type ShapePosition = GenericPosition<LengthPercentage, LengthPercentage>; /// A specified basic shape. -pub type BasicShape = generic::GenericBasicShape< - Angle, - ShapePosition, - LengthPercentage, - NonNegativeLengthPercentage, - BasicShapeRect, ->; +pub type BasicShape = + generic::GenericBasicShape<Angle, ShapePosition, LengthPercentage, BasicShapeRect>; /// The specified value of `inset()`. -pub type InsetRect = generic::GenericInsetRect<LengthPercentage, NonNegativeLengthPercentage>; +pub type InsetRect = generic::GenericInsetRect<LengthPercentage>; /// A specified circle. pub type Circle = generic::Circle<ShapePosition, NonNegativeLengthPercentage>; diff --git a/servo/components/style/values/specified/effects.rs b/servo/components/style/values/specified/effects.rs @@ -14,17 +14,18 @@ use crate::values::computed::CSSPixelLength as ComputedCSSPixelLength; use crate::values::computed::Filter as ComputedFilter; use crate::values::computed::NonNegativeLength as ComputedNonNegativeLength; use crate::values::computed::NonNegativeNumber as ComputedNonNegativeNumber; +use crate::values::computed::Number as ComputedNumber; use crate::values::computed::ZeroToOneNumber as ComputedZeroToOneNumber; use crate::values::computed::{Context, ToComputedValue}; use crate::values::generics::effects::BoxShadow as GenericBoxShadow; use crate::values::generics::effects::Filter as GenericFilter; use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow; -use crate::values::generics::NonNegative; +use crate::values::generics::{NonNegative, ZeroToOne}; use crate::values::specified::color::Color; use crate::values::specified::length::{Length, NonNegativeLength}; #[cfg(feature = "gecko")] use crate::values::specified::url::SpecifiedUrl; -use crate::values::specified::{Angle, Number, NumberOrPercentage}; +use crate::values::specified::{Angle, NonNegativeNumberOrPercentage, Number, NumberOrPercentage}; #[cfg(feature = "servo")] use crate::values::Impossible; use crate::Zero; @@ -37,35 +38,33 @@ pub type BoxShadow = /// A specified value for a single `filter`. #[cfg(feature = "gecko")] -pub type SpecifiedFilter = GenericFilter< - Angle, - NonNegativeFactor, - ZeroToOneFactor, - NonNegativeLength, - SimpleShadow, - SpecifiedUrl, ->; +pub type SpecifiedFilter = GenericFilter<Angle, FilterFactor, Length, SimpleShadow, SpecifiedUrl>; /// A specified value for a single `filter`. #[cfg(feature = "servo")] -pub type SpecifiedFilter = GenericFilter< - Angle, - NonNegativeFactor, - ZeroToOneFactor, - NonNegativeLength, - SimpleShadow, - Impossible, ->; +pub type SpecifiedFilter = GenericFilter<Angle, FilterFactor, Length, SimpleShadow, Impossible>; pub use self::SpecifiedFilter as Filter; -/// A value for the `<factor>` parts in `Filter`. +/// The factor for a filter function. #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] -pub struct NonNegativeFactor(NumberOrPercentage); +pub struct FilterFactor(NumberOrPercentage); -/// A value for the `<factor>` parts in `Filter` which clamps to one. -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] -pub struct ZeroToOneFactor(NumberOrPercentage); +impl FilterFactor { + fn to_number(&self) -> Number { + self.0.to_number() + } +} + +impl ToComputedValue for FilterFactor { + type ComputedValue = ComputedNumber; + fn to_computed_value(&self, _: &Context) -> Self::ComputedValue { + self.0.to_number().get() + } + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + Self(NumberOrPercentage::Number(Number::new(*computed))) + } +} /// Clamp the value to 1 if the value is over 100%. #[inline] @@ -78,46 +77,28 @@ fn clamp_to_one(number: NumberOrPercentage) -> NumberOrPercentage { } } -macro_rules! factor_impl_common { - ($ty:ty, $computed_ty:ty) => { - impl $ty { - #[inline] - fn one() -> Self { - Self(NumberOrPercentage::Number(Number::new(1.))) - } - } - - impl ToComputedValue for $ty { - type ComputedValue = $computed_ty; - - #[inline] - fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { - use crate::values::computed::NumberOrPercentage; - match self.0.to_computed_value(context) { - NumberOrPercentage::Number(n) => n.into(), - NumberOrPercentage::Percentage(p) => p.0.into(), - } - } - - #[inline] - fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Self(NumberOrPercentage::Number( - ToComputedValue::from_computed_value(&computed.0), - )) - } - } - }; +type NonNegativeFactor = NonNegative<FilterFactor>; +impl NonNegativeFactor { + fn one() -> Self { + Self(FilterFactor(NumberOrPercentage::Number(Number::new(1.)))) + } } -factor_impl_common!(NonNegativeFactor, ComputedNonNegativeNumber); -factor_impl_common!(ZeroToOneFactor, ComputedZeroToOneNumber); impl Parse for NonNegativeFactor { - #[inline] fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - NumberOrPercentage::parse_non_negative(context, input).map(Self) + Ok(Self(FilterFactor( + NonNegativeNumberOrPercentage::parse(context, input)?.0, + ))) + } +} + +type ZeroToOneFactor = ZeroToOne<FilterFactor>; +impl ZeroToOneFactor { + fn one() -> Self { + Self(FilterFactor(NumberOrPercentage::Number(Number::new(1.)))) } } @@ -127,9 +108,9 @@ impl Parse for ZeroToOneFactor { context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Self, ParseError<'i>> { - NumberOrPercentage::parse_non_negative(context, input) - .map(clamp_to_one) - .map(Self) + Ok(Self(FilterFactor(clamp_to_one( + NumberOrPercentage::parse_non_negative(context, input)?, + )))) } } diff --git a/servo/components/style/values/specified/image.rs b/servo/components/style/values/specified/image.rs @@ -49,9 +49,8 @@ size_of_test!(Image, 16); /// <https://drafts.csswg.org/css-images/#gradients> pub type Gradient = generic::Gradient< LineDirection, + Length, LengthPercentage, - NonNegativeLength, - NonNegativeLengthPercentage, Position, Angle, AngleOrPercentage, diff --git a/servo/components/style_derive/to_animated_value.rs b/servo/components/style_derive/to_animated_value.rs @@ -2,7 +2,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -use crate::to_computed_value; +use crate::animate::AnimationFieldAttrs; +use crate::{cg, to_computed_value}; use proc_macro2::TokenStream; use syn::DeriveInput; use synstructure::BindStyle; @@ -27,7 +28,13 @@ pub fn derive(input: DeriveInput) -> TokenStream { parse_quote!(crate::values::animated::ToAnimatedValue), parse_quote!(AnimatedValue), BindStyle::Move, - |_| Default::default(), + |binding| { + let attrs = cg::parse_field_attrs::<AnimationFieldAttrs>(&binding.ast()); + to_computed_value::ToValueAttrs { + field_bound: attrs.field_bound, + no_field_bound: false, + } + }, |binding| quote!(crate::values::animated::ToAnimatedValue::from_animated_value(#binding)), |binding| quote!(crate::values::animated::ToAnimatedValue::to_animated_value(#binding, context)), trait_impl,