diff options
-rw-r--r-- | components/style/animation.rs | 18 | ||||
-rw-r--r-- | components/style/bezier.rs | 12 | ||||
-rw-r--r-- | components/style/gecko_bindings/sugar/ns_timing_function.rs | 44 | ||||
-rw-r--r-- | components/style/macros.rs | 5 | ||||
-rw-r--r-- | components/style/properties/helpers.mako.rs | 7 | ||||
-rw-r--r-- | components/style/properties/helpers/animated_properties.mako.rs | 343 | ||||
-rw-r--r-- | components/style/properties/longhand/font.mako.rs | 6 | ||||
-rw-r--r-- | components/style/properties/longhand/inherited_table.mako.rs | 6 | ||||
-rw-r--r-- | components/style/values/animated/effects.rs | 64 | ||||
-rw-r--r-- | components/style/values/animated/mod.rs | 31 | ||||
-rw-r--r-- | components/style/values/computed/background.rs | 6 | ||||
-rw-r--r-- | components/style/values/computed/text.rs | 6 | ||||
-rw-r--r-- | components/style/values/computed/transform.rs | 12 | ||||
-rw-r--r-- | components/style/values/generics/text.rs | 9 | ||||
-rw-r--r-- | components/style/values/generics/transform.rs | 29 | ||||
-rw-r--r-- | components/style/values/specified/transform.rs | 50 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 3 | ||||
-rw-r--r-- | tests/unit/style/animated_properties.rs | 2 |
18 files changed, 402 insertions, 251 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs index 8d652d8e0e9..123cdf19ebc 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -9,7 +9,6 @@ use Atom; use bezier::Bezier; use context::SharedStyleContext; use dom::OpaqueNode; -use euclid::Point2D; use font_metrics::FontMetricsProvider; use properties::{self, CascadeFlags, ComputedValues, Importance}; use properties::animated_properties::{AnimatableLonghand, AnimatedProperty, TransitionProperty}; @@ -369,18 +368,10 @@ impl PropertyAnimation { /// Update the given animation at a given point of progress. pub fn update(&self, style: &mut ComputedValues, time: f64) { - let solve_bezier = |(p1, p2): (Point2D<_>, Point2D<_>)| { - let epsilon = 1. / (200. * (self.duration.seconds() as f64)); - let bezier = Bezier::new( - Point2D::new(p1.x as f64, p1.y as f64), - Point2D::new(p2.x as f64, p2.y as f64), - ); - bezier.solve(time, epsilon) - }; - + let epsilon = 1. / (200. * (self.duration.seconds() as f64)); let progress = match self.timing_function { - GenericTimingFunction::CubicBezier(p1, p2) => { - solve_bezier((p1, p2)) + GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => { + Bezier::new(x1, y1, x2, y2).solve(time, epsilon) }, GenericTimingFunction::Steps(steps, StepPosition::Start) => { (time * (steps as f64)).ceil() / (steps as f64) @@ -405,7 +396,8 @@ impl PropertyAnimation { out }, GenericTimingFunction::Keyword(keyword) => { - solve_bezier(keyword.to_bezier_points()) + let (x1, x2, y1, y2) = keyword.to_bezier(); + Bezier::new(x1, x2, y1, y2).solve(time, epsilon) }, }; diff --git a/components/style/bezier.rs b/components/style/bezier.rs index 30f6f6735a2..2e85f9cf095 100644 --- a/components/style/bezier.rs +++ b/components/style/bezier.rs @@ -8,7 +8,7 @@ #![deny(missing_docs)] -use euclid::Point2D; +use values::CSSFloat; const NEWTON_METHOD_ITERATIONS: u8 = 8; @@ -31,12 +31,12 @@ impl Bezier { /// The start and end points are always (0, 0) and (1, 1) so that a transition or animation /// starts at 0% and ends at 100%. #[inline] - pub fn new(p1: Point2D<f64>, p2: Point2D<f64>) -> Bezier { - let cx = 3.0 * p1.x; - let bx = 3.0 * (p2.x - p1.x) - cx; + pub fn new(x1: CSSFloat, y1: CSSFloat, x2: CSSFloat, y2: CSSFloat) -> Bezier { + let cx = 3. * x1 as f64; + let bx = 3. * (x2 as f64 - x1 as f64) - cx; - let cy = 3.0 * p1.y; - let by = 3.0 * (p2.y - p1.y) - cy; + let cy = 3. * y1 as f64; + let by = 3. * (y2 as f64 - y1 as f64) - cy; Bezier { ax: 1.0 - cx - bx, diff --git a/components/style/gecko_bindings/sugar/ns_timing_function.rs b/components/style/gecko_bindings/sugar/ns_timing_function.rs index fbcde7ecd1e..04023e13d71 100644 --- a/components/style/gecko_bindings/sugar/ns_timing_function.rs +++ b/components/style/gecko_bindings/sugar/ns_timing_function.rs @@ -2,7 +2,6 @@ * 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/. */ -use euclid::{Point2D, TypedPoint2D}; use gecko_bindings::structs::{nsTimingFunction, nsTimingFunction_Type}; use std::mem; use values::computed::ToComputedValue; @@ -28,18 +27,19 @@ impl nsTimingFunction { } } - fn set_as_bezier(&mut self, - function_type: nsTimingFunction_Type, - p1: Point2D<f32>, - p2: Point2D<f32>) { + fn set_as_bezier( + &mut self, + function_type: nsTimingFunction_Type, + x1: f32, y1: f32, x2: f32, y2: f32, + ) { self.mType = function_type; unsafe { let ref mut gecko_cubic_bezier = unsafe { self.__bindgen_anon_1.mFunc.as_mut() }; - gecko_cubic_bezier.mX1 = p1.x; - gecko_cubic_bezier.mY1 = p1.y; - gecko_cubic_bezier.mX2 = p2.x; - gecko_cubic_bezier.mY2 = p2.y; + gecko_cubic_bezier.mX1 = x1; + gecko_cubic_bezier.mY1 = y1; + gecko_cubic_bezier.mX2 = x2; + gecko_cubic_bezier.mY2 = y2; } } } @@ -67,14 +67,15 @@ impl From<TimingFunction> for nsTimingFunction { debug_assert!(frames.value() >= 2); tf.set_as_frames(frames.value() as u32); }, - GenericTimingFunction::CubicBezier(p1, p2) => { - tf.set_as_bezier(nsTimingFunction_Type::CubicBezier, - Point2D::new(p1.x.get(), p1.y.get()), - Point2D::new(p2.x.get(), p2.y.get())); + GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => { + tf.set_as_bezier( + nsTimingFunction_Type::CubicBezier, + x1.get(), y1.get(), x2.get(), y2.get(), + ); }, GenericTimingFunction::Keyword(keyword) => { - let (p1, p2) = keyword.to_bezier_points(); - tf.set_as_bezier(keyword.into(), p1, p2) + let (x1, y1, x2, y2) = keyword.to_bezier(); + tf.set_as_bezier(keyword.into(), x1, y1, x2, y2); }, } tf @@ -114,11 +115,14 @@ impl From<nsTimingFunction> for ComputedTimingFunction { GenericTimingFunction::Keyword(TimingKeyword::EaseInOut) }, nsTimingFunction_Type::CubicBezier => { - GenericTimingFunction::CubicBezier( - TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX1 }, - unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY1 }), - TypedPoint2D::new(unsafe { function.__bindgen_anon_1.mFunc.as_ref().mX2 }, - unsafe { function.__bindgen_anon_1.mFunc.as_ref().mY2 })) + unsafe { + GenericTimingFunction::CubicBezier { + x1: function.__bindgen_anon_1.mFunc.as_ref().mX1, + y1: function.__bindgen_anon_1.mFunc.as_ref().mY1, + x2: function.__bindgen_anon_1.mFunc.as_ref().mX2, + y2: function.__bindgen_anon_1.mFunc.as_ref().mY2, + } + } }, } } diff --git a/components/style/macros.rs b/components/style/macros.rs index 569d5e7d54c..af4e0b74684 100644 --- a/components/style/macros.rs +++ b/components/style/macros.rs @@ -112,5 +112,10 @@ macro_rules! define_keyword_type { impl $crate::values::computed::ComputedValueAsSpecified for $name {} impl $crate::values::animated::AnimatedValueAsComputed for $name {} no_viewport_percentage!($name); + + impl $crate::values::animated::ToAnimatedZero for $name { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Ok($name) } + } }; } diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index e59be799737..0517b824faa 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -129,6 +129,8 @@ % if animation_value_type == "ComputedValue": use properties::animated_properties::Animatable; + use values::animated::ToAnimatedZero; + impl Animatable for T { fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { @@ -149,6 +151,11 @@ self.0.compute_squared_distance(&other.0) } } + + impl ToAnimatedZero for T { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } + } % endif pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index d81028284e3..21c0b25fa01 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -33,7 +33,7 @@ use super::ComputedValues; #[cfg(any(feature = "gecko", feature = "testing"))] use values::Auto; use values::{CSSFloat, CustomIdent, Either}; -use values::animated::ToAnimatedValue; +use values::animated::{ToAnimatedValue, ToAnimatedZero}; use values::animated::effects::BoxShadowList as AnimatedBoxShadowList; use values::animated::effects::Filter as AnimatedFilter; use values::animated::effects::FilterList as AnimatedFilterList; @@ -47,6 +47,49 @@ use values::generics::border::BorderCornerRadius as GenericBorderCornerRadius; use values::generics::effects::Filter; use values::generics::position as generic_position; +/// A trait used to implement various procedures used during animation. +pub trait Animatable: Sized { + /// Performs a weighted sum of this value and |other|. This is used for + /// interpolation and addition of animation values. + fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) + -> Result<Self, ()>; + + /// [Interpolates][interpolation] a value with another for a given property. + /// + /// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation + fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { + self.add_weighted(other, 1.0 - progress, progress) + } + + /// Returns the [sum][animation-addition] of this value and |other|. + /// + /// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition + fn add(&self, other: &Self) -> Result<Self, ()> { + self.add_weighted(other, 1.0, 1.0) + } + + /// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then + /// accumulates |other| onto the result. + /// If |count| is zero, the result will be |other|. + /// + /// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation + fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> { + self.add_weighted(other, count as f64, 1.0) + } + + /// Compute distance between a value and another for a given property. + fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) } + + /// In order to compute the Euclidean distance of a list or property value with multiple + /// components, we need to compute squared distance for each element, so the vector can sum it + /// and then get its squared root as the distance. + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_distance(other).map(|d| d * d) + } +} + +/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list +pub trait RepeatableListAnimatable: Animatable {} /// A longhand property whose animation type is not "none". /// @@ -692,19 +735,6 @@ impl Animatable for AnimationValue { } } - fn get_zero_value(&self) -> Result<Self, ()> { - match *self { - % for prop in data.longhands: - % if prop.animatable and prop.animation_value_type != "discrete": - AnimationValue::${prop.camel_case}(ref base) => { - Ok(AnimationValue::${prop.camel_case}(base.get_zero_value()?)) - }, - % endif - % endfor - _ => Err(()), - } - } - fn compute_distance(&self, other: &Self) -> Result<f64, ()> { match (self, other) { % for prop in data.longhands: @@ -730,61 +760,22 @@ impl Animatable for AnimationValue { } } - -/// A trait used to implement various procedures used during animation. -pub trait Animatable: Sized { - /// Performs a weighted sum of this value and |other|. This is used for - /// interpolation and addition of animation values. - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) - -> Result<Self, ()>; - - /// [Interpolates][interpolation] a value with another for a given property. - /// - /// [interpolation]: https://w3c.github.io/web-animations/#animation-interpolation - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - self.add_weighted(other, 1.0 - progress, progress) - } - - /// Returns the [sum][animation-addition] of this value and |other|. - /// - /// [animation-addition]: https://w3c.github.io/web-animations/#animation-addition - fn add(&self, other: &Self) -> Result<Self, ()> { - self.add_weighted(other, 1.0, 1.0) - } - - /// [Accumulates][animation-accumulation] this value onto itself (|count| - 1) times then - /// accumulates |other| onto the result. - /// If |count| is zero, the result will be |other|. - /// - /// [animation-accumulation]: https://w3c.github.io/web-animations/#animation-accumulation - fn accumulate(&self, other: &Self, count: u64) -> Result<Self, ()> { - self.add_weighted(other, count as f64, 1.0) - } - - /// Returns a value that, when added with an underlying value, will produce the underlying - /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from - /// the zero value to the 'by' value, and then adds the result to the underlying value. - /// - /// This is not the necessarily the same as the initial value of a property. For example, the - /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the - /// underlying value will not produce the underlying value. +impl ToAnimatedZero for AnimationValue { #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Err(()) } - - /// Compute distance between a value and another for a given property. - fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { Err(()) } - - /// In order to compute the Euclidean distance of a list or property value with multiple - /// components, we need to compute squared distance for each element, so the vector can sum it - /// and then get its squared root as the distance. - fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { - self.compute_distance(other).map(|d| d * d) + fn to_animated_zero(&self) -> Result<Self, ()> { + match *self { + % for prop in data.longhands: + % if prop.animatable and prop.animation_value_type != "discrete": + AnimationValue::${prop.camel_case}(ref base) => { + Ok(AnimationValue::${prop.camel_case}(base.to_animated_zero()?)) + }, + % endif + % endfor + _ => Err(()), + } } } -/// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list -pub trait RepeatableListAnimatable: Animatable {} - impl RepeatableListAnimatable for LengthOrPercentage {} impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {} @@ -835,9 +826,6 @@ impl Animatable for Au { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(Au(0)) } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { self.0.compute_distance(&other.0) } @@ -888,9 +876,6 @@ impl Animatable for f32 { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(0.) } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { Ok((*self - *other).abs() as f64) } @@ -904,9 +889,6 @@ impl Animatable for f64 { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(0.) } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { Ok((*self - *other).abs()) } @@ -920,9 +902,6 @@ impl Animatable for i32 { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(0) } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { Ok((*self - *other).abs() as f64) } @@ -957,14 +936,18 @@ impl Animatable for Percentage { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(Percentage(0.)) } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { Ok((self.0 as f64 - other.0 as f64).abs()) } } +impl ToAnimatedZero for Percentage { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(Percentage(0.)) + } +} + /// https://drafts.csswg.org/css-transitions/#animtype-visibility impl Animatable for Visibility { #[inline] @@ -990,6 +973,13 @@ impl Animatable for Visibility { } } +impl ToAnimatedZero for Visibility { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Err(()) + } +} + impl<T: Animatable + Copy> Animatable for Size2D<T> { #[inline] fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { @@ -1028,6 +1018,11 @@ impl Animatable for BorderCornerRadius { } } +impl ToAnimatedZero for BorderCornerRadius { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// https://drafts.csswg.org/css-transitions/#animtype-length impl Animatable for VerticalAlign { #[inline] @@ -1055,6 +1050,11 @@ impl Animatable for VerticalAlign { } } +impl ToAnimatedZero for VerticalAlign { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc impl Animatable for CalcLengthOrPercentage { #[inline] @@ -1126,11 +1126,6 @@ impl Animatable for LengthOrPercentage { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - Ok(LengthOrPercentage::zero()) - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { match (*self, *other) { (LengthOrPercentage::Length(ref this), @@ -1173,6 +1168,13 @@ impl Animatable for LengthOrPercentage { } } +impl ToAnimatedZero for LengthOrPercentage { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(LengthOrPercentage::zero()) + } +} + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc impl Animatable for LengthOrPercentageOrAuto { #[inline] @@ -1203,18 +1205,6 @@ impl Animatable for LengthOrPercentageOrAuto { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - match *self { - LengthOrPercentageOrAuto::Length(_) | - LengthOrPercentageOrAuto::Percentage(_) | - LengthOrPercentageOrAuto::Calc(_) => { - Ok(LengthOrPercentageOrAuto::Length(Au(0))) - }, - LengthOrPercentageOrAuto::Auto => Err(()), - } - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { match (*self, *other) { (LengthOrPercentageOrAuto::Length(ref this), @@ -1262,6 +1252,20 @@ impl Animatable for LengthOrPercentageOrAuto { } } +impl ToAnimatedZero for LengthOrPercentageOrAuto { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + match *self { + LengthOrPercentageOrAuto::Length(_) | + LengthOrPercentageOrAuto::Percentage(_) | + LengthOrPercentageOrAuto::Calc(_) => { + Ok(LengthOrPercentageOrAuto::Length(Au(0))) + }, + LengthOrPercentageOrAuto::Auto => Err(()), + } + } +} + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc impl Animatable for LengthOrPercentageOrNone { #[inline] @@ -1292,18 +1296,6 @@ impl Animatable for LengthOrPercentageOrNone { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - match *self { - LengthOrPercentageOrNone::Length(_) | - LengthOrPercentageOrNone::Percentage(_) | - LengthOrPercentageOrNone::Calc(_) => { - Ok(LengthOrPercentageOrNone::Length(Au(0))) - }, - LengthOrPercentageOrNone::None => Err(()), - } - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { match (*self, *other) { (LengthOrPercentageOrNone::Length(ref this), @@ -1324,6 +1316,20 @@ impl Animatable for LengthOrPercentageOrNone { } } +impl ToAnimatedZero for LengthOrPercentageOrNone { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + match *self { + LengthOrPercentageOrNone::Length(_) | + LengthOrPercentageOrNone::Percentage(_) | + LengthOrPercentageOrNone::Calc(_) => { + Ok(LengthOrPercentageOrNone::Length(Au(0))) + }, + LengthOrPercentageOrNone::None => Err(()), + } + } +} + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc impl Animatable for MozLength { #[inline] @@ -1350,6 +1356,11 @@ impl Animatable for MozLength { } } +impl ToAnimatedZero for MozLength { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc impl Animatable for MaxLength { #[inline] @@ -1376,6 +1387,11 @@ impl Animatable for MaxLength { } } +impl ToAnimatedZero for MaxLength { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight impl Animatable for FontWeight { #[inline] @@ -1389,9 +1405,6 @@ impl Animatable for FontWeight { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(FontWeight::normal()) } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { let a = self.0 as f64; let b = other.0 as f64; @@ -1399,6 +1412,13 @@ impl Animatable for FontWeight { } } +impl ToAnimatedZero for FontWeight { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(FontWeight::normal()) + } +} + /// https://drafts.csswg.org/css-fonts/#font-stretch-prop impl Animatable for FontStretch { #[inline] @@ -1422,6 +1442,11 @@ impl Animatable for FontStretch { } } +impl ToAnimatedZero for FontStretch { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// We should treat font stretch as real number in order to interpolate this property. /// https://drafts.csswg.org/css-fonts-3/#font-stretch-animation impl From<FontStretch> for f64 { @@ -1463,14 +1488,6 @@ impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - Ok(generic_position::Position { - horizontal: self.horizontal.get_zero_value()?, - vertical: self.vertical.get_zero_value()?, - }) - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { self.compute_squared_distance(other).map(|sd| sd.sqrt()) } @@ -1482,6 +1499,20 @@ impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, } } +impl<H, V> ToAnimatedZero for generic_position::Position<H, V> +where + H: ToAnimatedZero, + V: ToAnimatedZero, +{ + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(generic_position::Position { + horizontal: self.horizontal.to_animated_zero()?, + vertical: self.vertical.to_animated_zero()?, + }) + } +} + impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V> where H: RepeatableListAnimatable, V: RepeatableListAnimatable {} @@ -1515,6 +1546,11 @@ impl Animatable for ClipRect { } } +impl ToAnimatedZero for ClipRect { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// Check if it's possible to do a direct numerical interpolation /// between these two transform lists. /// http://dev.w3.org/csswg/css-transforms/#transform-transform-animation @@ -2589,9 +2625,13 @@ impl Animatable for TransformList { } } } +} +impl ToAnimatedZero for TransformList { #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { Ok(TransformList(None)) } + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(TransformList(None)) + } } impl<T, U> Animatable for Either<T, U> @@ -2614,18 +2654,6 @@ impl<T, U> Animatable for Either<T, U> } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - match *self { - Either::First(ref this) => { - Ok(Either::First(this.get_zero_value()?)) - }, - Either::Second(ref this) => { - Ok(Either::Second(this.get_zero_value()?)) - }, - } - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { match (self, other) { (&Either::First(ref this), &Either::First(ref other)) => { @@ -2652,6 +2680,24 @@ impl<T, U> Animatable for Either<T, U> } } +impl<A, B> ToAnimatedZero for Either<A, B> +where + A: ToAnimatedZero, + B: ToAnimatedZero, +{ + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + match *self { + Either::First(ref first) => { + Ok(Either::First(first.to_animated_zero()?)) + }, + Either::Second(ref second) => { + Ok(Either::Second(second.to_animated_zero()?)) + }, + } + } +} + #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// Unlike RGBA, each component value may exceed the range [0.0, 1.0]. @@ -2731,11 +2777,6 @@ impl Animatable for IntermediateRGBA { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - Ok(IntermediateRGBA::transparent()) - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { self.compute_squared_distance(other).map(|sq| sq.sqrt()) } @@ -2759,6 +2800,13 @@ impl Animatable for IntermediateRGBA { } } +impl ToAnimatedZero for IntermediateRGBA { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(IntermediateRGBA::transparent()) + } +} + #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] @@ -2897,6 +2945,11 @@ impl Animatable for IntermediateColor { } } +impl ToAnimatedZero for IntermediateColor { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// Animatable SVGPaint pub type IntermediateSVGPaint = SVGPaint<IntermediateRGBA>; @@ -2922,12 +2975,14 @@ impl Animatable for IntermediateSVGPaint { Ok(self.kind.compute_squared_distance(&other.kind)? + self.fallback.compute_squared_distance(&other.fallback)?) } +} +impl ToAnimatedZero for IntermediateSVGPaint { #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { + fn to_animated_zero(&self) -> Result<Self, ()> { Ok(IntermediateSVGPaint { - kind: self.kind.get_zero_value()?, - fallback: self.fallback.and_then(|v| v.get_zero_value().ok()), + kind: self.kind.to_animated_zero()?, + fallback: self.fallback.and_then(|v| v.to_animated_zero().ok()), }) } } @@ -2960,12 +3015,14 @@ impl Animatable for IntermediateSVGPaintKind { _ => Err(()) } } +} +impl ToAnimatedZero for IntermediateSVGPaintKind { #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { + fn to_animated_zero(&self) -> Result<Self, ()> { match *self { SVGPaintKind::Color(ref color) => { - Ok(SVGPaintKind::Color(color.get_zero_value()?)) + Ok(SVGPaintKind::Color(color.to_animated_zero()?)) }, SVGPaintKind::None | SVGPaintKind::ContextFill | diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index f4c0332b3eb..d5a0180208e 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -1044,6 +1044,7 @@ ${helpers.single_keyword_system("font-variant-caps", pub mod computed_value { use properties::animated_properties::Animatable; use values::CSSFloat; + use values::animated::ToAnimatedZero; #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Copy, Clone, Debug, PartialEq, ToCss)] @@ -1081,6 +1082,11 @@ ${helpers.single_keyword_system("font-variant-caps", } } } + + impl ToAnimatedZero for T { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } + } } #[inline] diff --git a/components/style/properties/longhand/inherited_table.mako.rs b/components/style/properties/longhand/inherited_table.mako.rs index 44ddc1881c9..d524833304c 100644 --- a/components/style/properties/longhand/inherited_table.mako.rs +++ b/components/style/properties/longhand/inherited_table.mako.rs @@ -28,6 +28,7 @@ ${helpers.single_keyword("caption-side", "top bottom", pub mod computed_value { use app_units::Au; use properties::animated_properties::Animatable; + use values::animated::ToAnimatedZero; #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Copy, Debug, PartialEq, ToCss)] @@ -60,6 +61,11 @@ ${helpers.single_keyword("caption-side", "top bottom", self.vertical.compute_squared_distance(&other.vertical)?) } } + + impl ToAnimatedZero for T { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } + } } #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/components/style/values/animated/effects.rs b/components/style/values/animated/effects.rs index 0d5204275a3..cb0fc8799d4 100644 --- a/components/style/values/animated/effects.rs +++ b/components/style/values/animated/effects.rs @@ -11,7 +11,7 @@ use properties::longhands::text_shadow::computed_value::T as ComputedTextShadowL use std::cmp; #[cfg(not(feature = "gecko"))] use values::Impossible; -use values::animated::ToAnimatedValue; +use values::animated::{ToAnimatedValue, ToAnimatedZero}; use values::computed::{Angle, Number}; use values::computed::length::Length; use values::generics::effects::BoxShadow as GenericBoxShadow; @@ -66,7 +66,7 @@ impl ToAnimatedValue for ComputedBoxShadowList { impl<S> Animatable for ShadowList<S> where - S: Animatable + Clone, + S: Animatable + Clone + ToAnimatedZero, { #[inline] fn add_weighted( @@ -83,10 +83,10 @@ where shadow.add_weighted(other, self_portion, other_portion)? }, (Some(shadow), None) => { - shadow.add_weighted(&shadow.get_zero_value()?, self_portion, other_portion)? + shadow.add_weighted(&shadow.to_animated_zero()?, self_portion, other_portion)? }, (None, Some(shadow)) => { - shadow.get_zero_value()?.add_weighted(&shadow, self_portion, other_portion)? + shadow.to_animated_zero()?.add_weighted(&shadow, self_portion, other_portion)? }, (None, None) => unreachable!(), }); @@ -102,6 +102,13 @@ where } } +impl<S> ToAnimatedZero for ShadowList<S> { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(ShadowList(vec![])) + } +} + impl ToAnimatedValue for ComputedTextShadowList { type AnimatedValue = TextShadowList; @@ -135,15 +142,6 @@ impl Animatable for BoxShadow { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - Ok(BoxShadow { - base: self.base.get_zero_value()?, - spread: self.spread.get_zero_value()?, - inset: self.inset, - }) - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { self.compute_squared_distance(other).map(|sd| sd.sqrt()) } @@ -160,6 +158,17 @@ impl Animatable for BoxShadow { } } +impl ToAnimatedZero for BoxShadow { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(BoxShadow { + base: self.base.to_animated_zero()?, + spread: self.spread.to_animated_zero()?, + inset: self.inset, + }) + } +} + impl ToAnimatedValue for ComputedFilterList { type AnimatedValue = FilterList; @@ -188,6 +197,13 @@ impl ToAnimatedValue for ComputedFilterList { } } +impl ToAnimatedZero for FilterList { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(FilterList(vec![])) + } +} + impl Animatable for SimpleShadow { #[inline] fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result<Self, ()> { @@ -205,16 +221,6 @@ impl Animatable for SimpleShadow { } #[inline] - fn get_zero_value(&self) -> Result<Self, ()> { - Ok(SimpleShadow { - color: IntermediateColor::transparent(), - horizontal: self.horizontal.get_zero_value()?, - vertical: self.vertical.get_zero_value()?, - blur: self.blur.get_zero_value()?, - }) - } - - #[inline] fn compute_distance(&self, other: &Self) -> Result<f64, ()> { self.compute_squared_distance(other).map(|sd| sd.sqrt()) } @@ -229,3 +235,15 @@ impl Animatable for SimpleShadow { ) } } + +impl ToAnimatedZero for SimpleShadow { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(SimpleShadow { + color: IntermediateColor::transparent(), + horizontal: self.horizontal.to_animated_zero()?, + vertical: self.vertical.to_animated_zero()?, + blur: self.blur.to_animated_zero()?, + }) + } +} diff --git a/components/style/values/animated/mod.rs b/components/style/values/animated/mod.rs index f671d1e207f..63d85254598 100644 --- a/components/style/values/animated/mod.rs +++ b/components/style/values/animated/mod.rs @@ -88,3 +88,34 @@ where } } +/// Returns a value similar to `self` that represents zero. +pub trait ToAnimatedZero: Sized { + /// Returns a value that, when added with an underlying value, will produce the underlying + /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from + /// the zero value to the 'by' value, and then adds the result to the underlying value. + /// + /// This is not the necessarily the same as the initial value of a property. For example, the + /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the + /// underlying value will not produce the underlying value. + fn to_animated_zero(&self) -> Result<Self, ()>; +} + +impl ToAnimatedZero for Au { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Ok(Au(0)) } +} + +impl ToAnimatedZero for f32 { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0.) } +} + +impl ToAnimatedZero for f64 { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0.) } +} + +impl ToAnimatedZero for i32 { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Ok(0) } +} diff --git a/components/style/values/computed/background.rs b/components/style/values/computed/background.rs index cdcab051405..a1de43c5fe6 100644 --- a/components/style/values/computed/background.rs +++ b/components/style/values/computed/background.rs @@ -5,6 +5,7 @@ //! Computed types for CSS values related to backgrounds. use properties::animated_properties::{Animatable, RepeatableListAnimatable}; +use values::animated::ToAnimatedZero; use values::computed::length::LengthOrPercentageOrAuto; use values::generics::background::BackgroundSize as GenericBackgroundSize; @@ -50,3 +51,8 @@ impl Animatable for BackgroundSize { } } } + +impl ToAnimatedZero for BackgroundSize { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} diff --git a/components/style/values/computed/text.rs b/components/style/values/computed/text.rs index 857a985d851..c6902515c2a 100644 --- a/components/style/values/computed/text.rs +++ b/components/style/values/computed/text.rs @@ -7,6 +7,7 @@ use app_units::Au; use properties::animated_properties::Animatable; use values::{CSSInteger, CSSFloat}; +use values::animated::ToAnimatedZero; use values::computed::length::{Length, LengthOrPercentage}; use values::generics::text::InitialLetter as GenericInitialLetter; use values::generics::text::LineHeight as GenericLineHeight; @@ -61,3 +62,8 @@ impl Animatable for LineHeight { } } } + +impl ToAnimatedZero for LineHeight { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} diff --git a/components/style/values/computed/transform.rs b/components/style/values/computed/transform.rs index a4f35215560..5bf953d46be 100644 --- a/components/style/values/computed/transform.rs +++ b/components/style/values/computed/transform.rs @@ -5,6 +5,7 @@ //! Computed types for CSS values that are related to transformations. use properties::animated_properties::Animatable; +use values::animated::ToAnimatedZero; use values::computed::{Length, LengthOrPercentage, Number, Percentage}; use values::generics::transform::TimingFunction as GenericTimingFunction; use values::generics::transform::TransformOrigin as GenericTransformOrigin; @@ -51,3 +52,14 @@ impl Animatable for TransformOrigin { ) } } + +impl ToAnimatedZero for TransformOrigin { + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { + Ok(Self::new( + self.horizontal.to_animated_zero()?, + self.vertical.to_animated_zero()?, + self.depth.to_animated_zero()?, + )) + } +} diff --git a/components/style/values/generics/text.rs b/components/style/values/generics/text.rs index 64b2e4c9c10..995752ce70f 100644 --- a/components/style/values/generics/text.rs +++ b/components/style/values/generics/text.rs @@ -9,6 +9,7 @@ use cssparser::Parser; use parser::ParserContext; use properties::animated_properties::Animatable; use style_traits::ParseError; +use values::animated::ToAnimatedZero; /// A generic value for the `initial-letter` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -93,6 +94,14 @@ impl<Value> Animatable for Spacing<Value> } } +impl<V> ToAnimatedZero for Spacing<V> +where + V: From<Au>, +{ + #[inline] + fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } +} + /// A generic value for the `line-height` property. #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToCss)] diff --git a/components/style/values/generics/transform.rs b/components/style/values/generics/transform.rs index 097297bc9f4..e00104f0c43 100644 --- a/components/style/values/generics/transform.rs +++ b/components/style/values/generics/transform.rs @@ -4,7 +4,6 @@ //! Generic types for CSS values that are related to transformations. -use euclid::Point2D; use std::fmt; use style_traits::{HasViewportPercentage, ToCss}; use values::CSSFloat; @@ -44,7 +43,8 @@ pub enum TimingFunction<Integer, Number> { /// `linear | ease | ease-in | ease-out | ease-in-out` Keyword(TimingKeyword), /// `cubic-bezier(<number>, <number>, <number>, <number>)` - CubicBezier(Point2D<Number>, Point2D<Number>), + #[allow(missing_docs)] + CubicBezier { x1: Number, y1: Number, x2: Number, y2: Number }, /// `step-start | step-end | steps(<integer>, [ start | end ]?)` Steps(Integer, StepPosition), /// `frames(<integer>)` @@ -100,15 +100,15 @@ where { match *self { TimingFunction::Keyword(keyword) => keyword.to_css(dest), - TimingFunction::CubicBezier(ref p1, ref p2) => { + TimingFunction::CubicBezier { ref x1, ref y1, ref x2, ref y2 } => { dest.write_str("cubic-bezier(")?; - p1.x.to_css(dest)?; + x1.to_css(dest)?; dest.write_str(", ")?; - p1.y.to_css(dest)?; + y1.to_css(dest)?; dest.write_str(", ")?; - p2.x.to_css(dest)?; + x2.to_css(dest)?; dest.write_str(", ")?; - p2.y.to_css(dest)?; + y2.to_css(dest)?; dest.write_str(")") }, TimingFunction::Steps(ref intervals, position) => { @@ -130,15 +130,16 @@ where } impl TimingKeyword { - /// Returns this timing keyword as a pair of `cubic-bezier()` points. + /// Returns the keyword as a quadruplet of Bezier point coordinates + /// `(x1, y1, x2, y2)`. #[inline] - pub fn to_bezier_points(self) -> (Point2D<CSSFloat>, Point2D<CSSFloat>) { + pub fn to_bezier(self) -> (CSSFloat, CSSFloat, CSSFloat, CSSFloat) { match self { - TimingKeyword::Linear => (Point2D::new(0., 0.), Point2D::new(1., 1.)), - TimingKeyword::Ease => (Point2D::new(0.25, 0.1), Point2D::new(0.25, 1.)), - TimingKeyword::EaseIn => (Point2D::new(0.42, 0.), Point2D::new(1., 1.)), - TimingKeyword::EaseOut => (Point2D::new(0., 0.), Point2D::new(0.58, 1.)), - TimingKeyword::EaseInOut => (Point2D::new(0.42, 0.), Point2D::new(0.58, 1.)), + TimingKeyword::Linear => (0., 0., 1., 1.), + TimingKeyword::Ease => (0.25, 0.1, 0.25, 1.), + TimingKeyword::EaseIn => (0.42, 0., 1., 1.), + TimingKeyword::EaseOut => (0., 0., 0.58, 1.), + TimingKeyword::EaseInOut => (0.42, 0., 0.58, 1.), } } } diff --git a/components/style/values/specified/transform.rs b/components/style/values/specified/transform.rs index 4f301d2c2ad..e169181f725 100644 --- a/components/style/values/specified/transform.rs +++ b/components/style/values/specified/transform.rs @@ -5,7 +5,6 @@ //! Specified types for CSS values that are related to transformations. use cssparser::Parser; -use euclid::Point2D; use parser::{Parse, ParserContext}; use selectors::parser::SelectorParseError; use style_traits::{ParseError, StyleParseError}; @@ -160,20 +159,19 @@ impl Parse for TimingFunction { input.parse_nested_block(move |i| { (match_ignore_ascii_case! { &function, "cubic-bezier" => { - let p1x = Number::parse(context, i)?; + let x1 = Number::parse(context, i)?; i.expect_comma()?; - let p1y = Number::parse(context, i)?; + let y1 = Number::parse(context, i)?; i.expect_comma()?; - let p2x = Number::parse(context, i)?; + let x2 = Number::parse(context, i)?; i.expect_comma()?; - let p2y = Number::parse(context, i)?; + let y2 = Number::parse(context, i)?; - if p1x.get() < 0.0 || p1x.get() > 1.0 || p2x.get() < 0.0 || p2x.get() > 1.0 { + if x1.get() < 0.0 || x1.get() > 1.0 || x2.get() < 0.0 || x2.get() > 1.0 { return Err(StyleParseError::UnspecifiedError.into()); } - let (p1, p2) = (Point2D::new(p1x, p1y), Point2D::new(p2x, p2y)); - Ok(GenericTimingFunction::CubicBezier(p1, p2)) + Ok(GenericTimingFunction::CubicBezier { x1, y1, x2, y2 }) }, "steps" => { let steps = Integer::parse_positive(context, i)?; @@ -206,17 +204,13 @@ impl ToComputedValue for TimingFunction { GenericTimingFunction::Keyword(keyword) => { GenericTimingFunction::Keyword(keyword) }, - GenericTimingFunction::CubicBezier(p1, p2) => { - GenericTimingFunction::CubicBezier( - Point2D::new( - p1.x.to_computed_value(context), - p1.y.to_computed_value(context), - ), - Point2D::new( - p2.x.to_computed_value(context), - p2.y.to_computed_value(context), - ), - ) + GenericTimingFunction::CubicBezier { x1, y1, x2, y2 } => { + GenericTimingFunction::CubicBezier { + x1: x1.to_computed_value(context), + y1: y1.to_computed_value(context), + x2: x2.to_computed_value(context), + y2: y2.to_computed_value(context), + } }, GenericTimingFunction::Steps(steps, position) => { GenericTimingFunction::Steps( @@ -238,17 +232,13 @@ impl ToComputedValue for TimingFunction { GenericTimingFunction::Keyword(keyword) => { GenericTimingFunction::Keyword(keyword) }, - GenericTimingFunction::CubicBezier(p1, p2) => { - GenericTimingFunction::CubicBezier( - Point2D::new( - Number::from_computed_value(&p1.x), - Number::from_computed_value(&p1.y), - ), - Point2D::new( - Number::from_computed_value(&p2.x), - Number::from_computed_value(&p2.y), - ), - ) + GenericTimingFunction::CubicBezier { ref x1, ref y1, ref x2, ref y2 } => { + GenericTimingFunction::CubicBezier { + x1: Number::from_computed_value(x1), + y1: Number::from_computed_value(y1), + x2: Number::from_computed_value(x2), + y2: Number::from_computed_value(y2), + } }, GenericTimingFunction::Steps(steps, position) => { GenericTimingFunction::Steps( diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index b56d56c8e85..a6f5c87529c 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -117,6 +117,7 @@ use style::traversal::{ANIMATION_ONLY, DomTraversal, FOR_CSS_RULE_CHANGES, FOR_R use style::traversal::{TraversalDriver, TraversalFlags, UNSTYLED_CHILDREN_ONLY}; use style::traversal::resolve_style; use style::values::{CustomIdent, KeyframesName}; +use style::values::animated::ToAnimatedZero; use style::values::computed::Context; use style_traits::{PARSING_MODE_DEFAULT, ToCss}; use super::error_reporter::ErrorReporter; @@ -375,7 +376,7 @@ pub extern "C" fn Servo_AnimationValues_GetZeroValue( -> RawServoAnimationValueStrong { let value_to_match = AnimationValue::as_arc(&value_to_match); - if let Ok(zero_value) = value_to_match.get_zero_value() { + if let Ok(zero_value) = value_to_match.to_animated_zero() { Arc::new(zero_value).into_strong() } else { RawServoAnimationValueStrong::null() diff --git a/tests/unit/style/animated_properties.rs b/tests/unit/style/animated_properties.rs index b1c33c65dc6..ba387422262 100644 --- a/tests/unit/style/animated_properties.rs +++ b/tests/unit/style/animated_properties.rs @@ -4,7 +4,7 @@ use app_units::Au; use cssparser::RGBA; -use style::properties::animated_properties::{Animatable, IntermediateRGBA}; +use style::properties::animated_properties::Animatable; use style::properties::longhands::transform::computed_value::ComputedOperation as TransformOperation; use style::properties::longhands::transform::computed_value::T as TransformList; use style::values::animated::ToAnimatedValue; |