diff --git a/components/style/properties/longhands/position.mako.rs b/components/style/properties/longhands/position.mako.rs index 4500b7d911f..56c60a71ce9 100644 --- a/components/style/properties/longhands/position.mako.rs +++ b/components/style/properties/longhands/position.mako.rs @@ -457,7 +457,7 @@ ${helpers.predefined_type( "AspectRatio", "computed::AspectRatio::auto()", engines="gecko servo-2013", - animation_value_type="discrete", + animation_value_type="ComputedValue", spec="https://drafts.csswg.org/css-sizing-4/#aspect-ratio", gecko_pref="layout.css.aspect-ratio.enabled", servo_restyle_damage="reflow", diff --git a/components/style/values/computed/ratio.rs b/components/style/values/computed/ratio.rs index b1786f3983f..ba40039eae1 100644 --- a/components/style/values/computed/ratio.rs +++ b/components/style/values/computed/ratio.rs @@ -4,7 +4,9 @@ //! `` computed values. +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::{One, Zero}; use std::cmp::{Ordering, PartialOrd}; @@ -21,8 +23,58 @@ impl PartialOrd for Ratio { } } +/// https://drafts.csswg.org/css-values/#combine-ratio +impl Animate for Ratio { + fn animate(&self, other: &Self, procedure: Procedure) -> Result { + // If either is degenerate, the values cannot be interpolated. + if self.is_degenerate() || other.is_degenerate() { + return Err(()); + } + + // Addition of s is not possible, and based on + // https://drafts.csswg.org/css-values-4/#not-additive, + // we simply use the first value as the result value. + // Besides, the procedure for accumulation should be identical to addition here. + if matches!(procedure, Procedure::Add | Procedure::Accumulate { .. }) { + return Ok(self.clone()); + } + + // The interpolation of a is defined by converting each to a number by + // dividing the first value by the second (so a ratio of 3 / 2 would become 1.5), taking + // the logarithm of that result (so the 1.5 would become approximately 0.176), then + // interpolating those values. + // + // The result during the interpolation is converted back to a by inverting the + // logarithm, then interpreting the result as a with the result as the first value + // and 1 as the second value. + let start = self.to_f32().ln(); + let end = other.to_f32().ln(); + let e = std::f32::consts::E; + let result = e.powf(start.animate(&end, procedure)?); + // The range of the result is [0, inf), based on the easing function. + if result.is_zero() || result.is_infinite() { + return Err(()); + } + Ok(Ratio::new(result, 1.0f32)) + } +} + +impl ComputeSquaredDistance for Ratio { + fn compute_squared_distance(&self, other: &Self) -> Result { + if self.is_degenerate() || other.is_degenerate() { + return Err(()); + } + // Use the distance of their logarithm values. (This is used by testing, so don't need to + // care about the base. Here we use the same base as that in animate().) + self.to_f32() + .ln() + .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()) } @@ -36,4 +88,18 @@ impl Ratio { self } } + + /// Returns true if this is a degenerate ratio. + /// https://drafts.csswg.org/css-values/#degenerate-ratio + #[inline] + pub fn is_degenerate(&self) -> bool { + self.0.is_zero() || self.1.is_zero() + } + + /// 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).0 / (self.1).0 + } } diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index 7a909ccfc90..17afb1c39b1 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -5,6 +5,7 @@ //! Generic types for CSS handling of specified and computed values of //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) +use crate::values::animated::ToAnimatedZero; use crate::values::generics::ratio::Ratio; /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). @@ -163,7 +164,6 @@ impl ZIndex { MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToAnimatedZero, ToComputedValue, ToCss, ToResolvedValue, @@ -175,7 +175,12 @@ pub enum PreferredRatio { #[css(skip)] None, /// With specified ratio - Ratio(#[css(field_bound)] Ratio), + Ratio( + #[animation(field_bound)] + #[css(field_bound)] + #[distance(field_bound)] + Ratio, + ), } /// A generic value for the `aspect-ratio` property, the value is `auto || `. @@ -188,7 +193,6 @@ pub enum PreferredRatio { MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToAnimatedZero, ToComputedValue, ToCss, ToResolvedValue, @@ -201,7 +205,9 @@ pub struct GenericAspectRatio { #[css(represents_keyword)] pub auto: bool, /// The preferred aspect-ratio value. + #[animation(field_bound)] #[css(field_bound)] + #[distance(field_bound)] pub ratio: PreferredRatio, } @@ -217,3 +223,10 @@ impl AspectRatio { } } } + +impl ToAnimatedZero for AspectRatio { + #[inline] + fn to_animated_zero(&self) -> Result { + Err(()) + } +} diff --git a/components/style/values/generics/ratio.rs b/components/style/values/generics/ratio.rs index ea3354f9828..8c66fed6026 100644 --- a/components/style/values/generics/ratio.rs +++ b/components/style/values/generics/ratio.rs @@ -10,15 +10,12 @@ use style_traits::{CssWriter, ToCss}; /// A generic value for the `` value. #[derive( - Animate, Clone, - ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, - ToAnimatedZero, ToComputedValue, ToResolvedValue, ToShmem,