diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index ec42f8224421..5c1b86f855fc 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -294,9 +294,14 @@ impl<'a> From for PropertyDeclarationId<'a> { pub enum AnimatedProperty { % for prop in data.longhands: % if prop.animatable: + <% + if prop.is_animatable_with_computed_value: + value_type = "longhands::{}::computed_value::T".format(prop.ident) + else: + value_type = prop.animation_value_type + %> /// ${prop.name} - ${prop.camel_case}(longhands::${prop.ident}::computed_value::T, - longhands::${prop.ident}::computed_value::T), + ${prop.camel_case}(${value_type}, ${value_type}), % endif % endfor } @@ -356,6 +361,9 @@ impl AnimatedProperty { Err(()) => return, }; % endif + % if not prop.is_animatable_with_computed_value: + let value: longhands::${prop.ident}::computed_value::T = value.into(); + % endif style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value); } % endif @@ -375,8 +383,8 @@ impl AnimatedProperty { % if prop.animatable: TransitionProperty::${prop.camel_case} => { AnimatedProperty::${prop.camel_case}( - old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}(), - new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}()) + old_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into(), + new_style.get_${prop.style_struct.ident.strip("_")}().clone_${prop.ident}().into()) } % endif % endfor @@ -936,96 +944,6 @@ impl Animatable for BackgroundSizeList { } } -/// https://drafts.csswg.org/css-transitions/#animtype-color -impl Animatable for RGBA { - #[inline] - fn add_weighted(&self, other: &RGBA, self_portion: f64, other_portion: f64) -> Result { - fn clamp(val: f32) -> f32 { - val.max(0.).min(1.) - } - - let alpha = clamp(try!(self.alpha_f32().add_weighted(&other.alpha_f32(), - self_portion, other_portion))); - if alpha == 0. { - Ok(RGBA::transparent()) - } else { - // NB: We rely on RGBA::from_floats clamping already. - let red = try!((self.red_f32() * self.alpha_f32()) - .add_weighted(&(other.red_f32() * other.alpha_f32()), - self_portion, other_portion)) - * 1. / alpha; - let green = try!((self.green_f32() * self.alpha_f32()) - .add_weighted(&(other.green_f32() * other.alpha_f32()), - self_portion, other_portion)) - * 1. / alpha; - let blue = try!((self.blue_f32() * self.alpha_f32()) - .add_weighted(&(other.blue_f32() * other.alpha_f32()), - self_portion, other_portion)) - * 1. / alpha; - Ok(RGBA::from_floats(red, green, blue, alpha)) - } - } - - /// https://www.w3.org/TR/smil-animation/#animateColorElement says we should use Euclidean - /// RGB-cube distance. - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.compute_squared_distance(other).map(|sd| sd.sqrt()) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - fn clamp(val: f32) -> f32 { - val.max(0.).min(1.) - } - - let start_a = clamp(self.alpha_f32()); - let end_a = clamp(other.alpha_f32()); - let start = [ start_a, - self.red_f32() * start_a, - self.green_f32() * start_a, - self.blue_f32() * start_a ]; - let end = [ end_a, - other.red_f32() * end_a, - other.green_f32() * end_a, - other.blue_f32() * end_a ]; - let diff = start.iter().zip(&end) - .fold(0.0f64, |n, (&a, &b)| { - let diff = (a - b) as f64; - n + diff * diff - }); - Ok(diff) - } -} - -/// https://drafts.csswg.org/css-transitions/#animtype-color -impl Animatable for CSSParserColor { - #[inline] - fn add_weighted(&self, other: &Self, self_portion: f64, other_portion: f64) -> Result { - match (*self, *other) { - (CSSParserColor::RGBA(ref this), CSSParserColor::RGBA(ref other)) => { - this.add_weighted(other, self_portion, other_portion).map(CSSParserColor::RGBA) - } - _ => Err(()), - } - } - - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.compute_squared_distance(other).map(|sq| sq.sqrt()) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (CSSParserColor::RGBA(ref this), CSSParserColor::RGBA(ref other)) => { - this.compute_squared_distance(other) - }, - _ => Ok(0.0), - } - } -} - /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc impl Animatable for CalcLengthOrPercentage { #[inline] @@ -1569,9 +1487,6 @@ impl Animatable for ClipRect { } -${impl_animatable_for_shadow('BoxShadow', 'CSSParserColor::RGBA(RGBA::transparent())',)} -${impl_animatable_for_shadow('TextShadow', 'CSSParserColor::RGBA(RGBA::transparent())',)} - /// 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 diff --git a/tests/unit/style/animated_properties.rs b/tests/unit/style/animated_properties.rs index c9e145c67614..7b69d42a227b 100644 --- a/tests/unit/style/animated_properties.rs +++ b/tests/unit/style/animated_properties.rs @@ -2,49 +2,55 @@ * 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 cssparser::{Color, RGBA}; -use style::properties::animated_properties::Animatable; +use cssparser::RGBA; +use style::properties::animated_properties::{Animatable, IntermediateRGBA}; + +fn interpolate_rgba(from: RGBA, to: RGBA, progress: f64) -> RGBA { + let from: IntermediateRGBA = from.into(); + let to: IntermediateRGBA = to.into(); + from.interpolate(&to, progress).unwrap().into() +} #[test] fn test_rgba_color_interepolation_preserves_transparent() { - assert_eq!(Color::RGBA(RGBA::transparent()) - .interpolate(&Color::RGBA(RGBA::transparent()), 0.5).unwrap(), - Color::RGBA(RGBA::transparent())); + assert_eq!(interpolate_rgba(RGBA::transparent(), + RGBA::transparent(), 0.5), + RGBA::transparent()); } #[test] fn test_rgba_color_interepolation_alpha() { - assert_eq!(Color::RGBA(RGBA::new(200, 0, 0, 100)) - .interpolate(&Color::RGBA(RGBA::new(0, 200, 0, 200)), 0.5).unwrap(), - Color::RGBA(RGBA::new(67, 133, 0, 150))); + assert_eq!(interpolate_rgba(RGBA::new(200, 0, 0, 100), + RGBA::new(0, 200, 0, 200), 0.5), + RGBA::new(67, 133, 0, 150)); } #[test] fn test_rgba_color_interepolation_out_of_range_1() { // Some cubic-bezier functions produce values that are out of range [0, 1]. // Unclamped cases. - assert_eq!(Color::RGBA(RGBA::from_floats(0.3, 0.0, 0.0, 0.4)).interpolate( - &Color::RGBA(RGBA::from_floats(0.0, 1.0, 0.0, 0.6)), -0.5).unwrap(), - Color::RGBA(RGBA::new(154, 0, 0, 77))); + assert_eq!(interpolate_rgba(RGBA::from_floats(0.3, 0.0, 0.0, 0.4), + RGBA::from_floats(0.0, 1.0, 0.0, 0.6), -0.5), + RGBA::new(154, 0, 0, 77)); } #[test] fn test_rgba_color_interepolation_out_of_range_2() { - assert_eq!(Color::RGBA(RGBA::from_floats(1.0, 0.0, 0.0, 0.6)).interpolate( - &Color::RGBA(RGBA::from_floats(0.0, 0.3, 0.0, 0.4)), 1.5).unwrap(), - Color::RGBA(RGBA::new(0, 154, 0, 77))); + assert_eq!(interpolate_rgba(RGBA::from_floats(1.0, 0.0, 0.0, 0.6), + RGBA::from_floats(0.0, 0.3, 0.0, 0.4), 1.5), + RGBA::new(0, 154, 0, 77)); } #[test] fn test_rgba_color_interepolation_out_of_range_clamped_1() { - assert_eq!(Color::RGBA(RGBA::from_floats(1.0, 0.0, 0.0, 0.8)).interpolate( - &Color::RGBA(RGBA::from_floats(0.0, 1.0, 0.0, 0.2)), -0.5).unwrap(), - Color::RGBA(RGBA::from_floats(1.0, 0.0, 0.0, 1.0))); + assert_eq!(interpolate_rgba(RGBA::from_floats(1.0, 0.0, 0.0, 0.8), + RGBA::from_floats(0.0, 1.0, 0.0, 0.2), -0.5), + RGBA::from_floats(1.0, 0.0, 0.0, 1.0)); } #[test] fn test_rgba_color_interepolation_out_of_range_clamped_2() { - assert_eq!(Color::RGBA(RGBA::from_floats(1.0, 0.0, 0.0, 0.8)).interpolate( - &Color::RGBA(RGBA::from_floats(0.0, 1.0, 0.0, 0.2)), 1.5).unwrap(), - Color::RGBA(RGBA::from_floats(0.0, 0.0, 0.0, 0.0))); + assert_eq!(interpolate_rgba(RGBA::from_floats(1.0, 0.0, 0.0, 0.8), + RGBA::from_floats(0.0, 1.0, 0.0, 0.2), 1.5), + RGBA::from_floats(0.0, 0.0, 0.0, 0.0)); }