diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index 66b0e3f720a..6adce11d9c1 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -116,10 +116,7 @@ fn interpolate(&self, other: &Self, progress: f64) -> Result { self.0.interpolate(&other.0, progress).map(T) } - } - use properties::animated_properties::ComputeDistance; - impl ComputeDistance for T { #[inline] fn compute_distance(&self, other: &Self) -> Result { self.0.compute_distance(&other.0) @@ -995,13 +992,7 @@ }, } } - } - -/// Macro for defining ComputeDistance trait for tuple struct which has Option, -/// e.g. struct T(pub Option). -<%def name="impl_compute_distance_for_option_tuple(value_for_none)"> - impl ComputeDistance for T { #[inline] fn compute_distance(&self, other: &Self) -> Result { match (self, other) { diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 732b528fff1..fcc963d2d2a 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -607,15 +607,49 @@ impl Animatable for AnimationValue { } } } + + fn compute_distance(&self, other: &Self) -> Result { + match (self, other) { + % for prop in data.longhands: + % if prop.animatable: + % if prop.animation_value_type != "discrete": + (&AnimationValue::${prop.camel_case}(ref from), + &AnimationValue::${prop.camel_case}(ref to)) => { + from.compute_distance(to) + }, + % else: + (&AnimationValue::${prop.camel_case}(ref _from), + &AnimationValue::${prop.camel_case}(ref _to)) => { + Err(()) + }, + % endif + % endif + % endfor + _ => { + panic!("Expected compute_distance of computed values of the same \ + property, got: {:?}, {:?}", self, other); + } + } + } } -/// A trait used to implement [interpolation][interpolated-types]. -/// -/// [interpolated-types]: https://drafts.csswg.org/css-transitions/#interpolated-types +/// A trait used to implement various procedures used during animation. pub trait Animatable: Sized { - /// Interpolate a value with another for a given property. + /// [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; + + /// Compute distance between a value and another for a given property. + fn compute_distance(&self, _other: &Self) -> Result { 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 { + self.compute_distance(other).map(|d| d * d) + } } /// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list @@ -631,6 +665,20 @@ impl Animatable for SmallVec<[T; 1]> { me.interpolate(you, progress) }).collect() } + + #[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 { + use num_integer::lcm; + let len = lcm(self.len(), other.len()); + self.iter().cycle().zip(other.iter().cycle()).take(len).map(|(me, you)| { + me.compute_squared_distance(you) + }).collect::, _>>().map(|d| d.iter().sum()) + } } /// https://drafts.csswg.org/css-transitions/#animtype-number @@ -639,6 +687,11 @@ impl Animatable for Au { fn interpolate(&self, other: &Self, progress: f64) -> Result { Ok(Au((self.0 as f64 + (other.0 as f64 - self.0 as f64) * progress).round() as i32)) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + self.0.compute_distance(&other.0) + } } impl Animatable for Option @@ -653,6 +706,26 @@ impl Animatable for Option _ => Err(()), } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (self, other) { + (&Some(ref this), &Some(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + match (self, other) { + (&Some(ref this), &Some(ref other)) => { + this.compute_squared_distance(other) + }, + _ => Err(()), + } + } } /// https://drafts.csswg.org/css-transitions/#animtype-number @@ -661,6 +734,11 @@ impl Animatable for f32 { fn interpolate(&self, other: &f32, progress: f64) -> Result { Ok(((*self as f64) + ((*other as f64) - (*self as f64)) * progress) as f32) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + Ok((*self - *other).abs() as f64) + } } /// https://drafts.csswg.org/css-transitions/#animtype-number @@ -669,6 +747,11 @@ impl Animatable for f64 { fn interpolate(&self, other: &f64, progress: f64) -> Result { Ok(*self + (*other - *self) * progress) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + Ok((*self - *other).abs()) + } } /// https://drafts.csswg.org/css-transitions/#animtype-integer @@ -679,6 +762,11 @@ impl Animatable for i32 { let b = *other as f64; Ok((a + (b - a) * progress).round() as i32) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + Ok((*self - *other).abs() as f64) + } } /// https://drafts.csswg.org/css-transitions/#animtype-number @@ -706,6 +794,15 @@ impl Animatable for Visibility { _ => Err(()), } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + if *self == *other { + Ok(0.0) + } else { + Ok(1.0) + } + } } impl Animatable for Size2D { @@ -733,6 +830,17 @@ impl Animatable for BorderRadiusSize { fn interpolate(&self, other: &Self, progress: f64) -> Result { self.0.interpolate(&other.0, progress).map(generics::BorderRadiusSize) } + + #[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 { + Ok(try!(self.0.width.compute_squared_distance(&other.0.width)) + + try!(self.0.height.compute_squared_distance(&other.0.height))) + } } /// https://drafts.csswg.org/css-transitions/#animtype-length @@ -749,6 +857,17 @@ impl Animatable for VerticalAlign { _ => Err(()), } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (VerticalAlign::LengthOrPercentage(ref this), + VerticalAlign::LengthOrPercentage(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } } impl Animatable for BackgroundSizeList { @@ -756,6 +875,16 @@ impl Animatable for BackgroundSizeList { fn interpolate(&self, other: &Self, progress: f64) -> Result { self.0.interpolate(&other.0, progress).map(BackgroundSizeList) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + self.0.compute_squared_distance(&other.0) + } } /// https://drafts.csswg.org/css-transitions/#animtype-color @@ -783,6 +912,37 @@ impl Animatable for RGBA { 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 @@ -796,6 +956,21 @@ impl Animatable for CSSParserColor { _ => 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 @@ -823,6 +998,18 @@ impl Animatable for CalcLengthOrPercentage { percentage: try!(interpolate_half(self.percentage, other.percentage, progress)), }) } + + #[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 { + let length_diff = (self.length().0 - other.length().0) as f64; + let percentage_diff = (self.percentage() - other.percentage()) as f64; + Ok(length_diff * length_diff + percentage_diff * percentage_diff) + } } /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc @@ -846,6 +1033,48 @@ impl Animatable for LengthOrPercentage { } } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (LengthOrPercentage::Length(ref this), + LengthOrPercentage::Length(ref other)) => { + this.compute_distance(other) + }, + (LengthOrPercentage::Percentage(ref this), + LengthOrPercentage::Percentage(ref other)) => { + this.compute_distance(other) + }, + (this, other) => { + let this: CalcLengthOrPercentage = From::from(this); + let other: CalcLengthOrPercentage = From::from(other); + this.compute_distance(&other) + } + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (LengthOrPercentage::Length(ref this), + LengthOrPercentage::Length(ref other)) => { + let diff = (this.0 - other.0) as f64; + Ok(diff * diff) + }, + (LengthOrPercentage::Percentage(ref this), + LengthOrPercentage::Percentage(ref other)) => { + let diff = (this - other) as f64; + Ok(diff * diff) + }, + (this, other) => { + let this: CalcLengthOrPercentage = From::from(this); + let other: CalcLengthOrPercentage = From::from(other); + let length_diff = (this.length().0 - other.length().0) as f64; + let percentage_diff = (this.percentage() - other.percentage()) as f64; + Ok(length_diff * length_diff + percentage_diff * percentage_diff) + } + } + } } /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc @@ -874,6 +1103,53 @@ impl Animatable for LengthOrPercentageOrAuto { } } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (LengthOrPercentageOrAuto::Length(ref this), + LengthOrPercentageOrAuto::Length(ref other)) => { + this.compute_distance(other) + }, + (LengthOrPercentageOrAuto::Percentage(ref this), + LengthOrPercentageOrAuto::Percentage(ref other)) => { + this.compute_distance(other) + }, + (this, other) => { + // If one of the element is Auto, Option<> will be None, and the returned distance is Err(()) + let this: Option = From::from(this); + let other: Option = From::from(other); + this.compute_distance(&other) + } + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (LengthOrPercentageOrAuto::Length(ref this), + LengthOrPercentageOrAuto::Length(ref other)) => { + let diff = (this.0 - other.0) as f64; + Ok(diff * diff) + }, + (LengthOrPercentageOrAuto::Percentage(ref this), + LengthOrPercentageOrAuto::Percentage(ref other)) => { + let diff = (this - other) as f64; + Ok(diff * diff) + }, + (this, other) => { + let this: Option = From::from(this); + let other: Option = From::from(other); + if this.is_none() || other.is_none() { + Err(()) + } else { + let length_diff = (this.unwrap().length().0 - other.unwrap().length().0) as f64; + let percentage_diff = (this.unwrap().percentage() - other.unwrap().percentage()) as f64; + Ok(length_diff * length_diff + percentage_diff * percentage_diff) + } + } + } + } } /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc @@ -895,6 +1171,21 @@ impl Animatable for LengthOrPercentageOrNone { _ => Err(()) } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (LengthOrPercentageOrNone::Length(ref this), + LengthOrPercentageOrNone::Length(ref other)) => { + this.compute_distance(other) + }, + (LengthOrPercentageOrNone::Percentage(ref this), + LengthOrPercentageOrNone::Percentage(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()) + } + } } /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc @@ -909,6 +1200,17 @@ impl Animatable for MinLength { _ => Err(()), } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (MinLength::LengthOrPercentage(ref this), + MinLength::LengthOrPercentage(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } } /// https://drafts.csswg.org/css-transitions/#animtype-lpcalc @@ -923,6 +1225,17 @@ impl Animatable for MaxLength { _ => Err(()), } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (MaxLength::LengthOrPercentage(ref this), + MaxLength::LengthOrPercentage(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } } /// https://drafts.csswg.org/css-transitions/#animtype-number @@ -945,6 +1258,21 @@ impl Animatable for LineHeight { _ => Err(()), } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (*self, *other) { + (LineHeight::Length(ref this), + LineHeight::Length(ref other)) => { + this.compute_distance(other) + }, + (LineHeight::Number(ref this), + LineHeight::Number(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } } /// http://dev.w3.org/csswg/css-transitions/#animtype-font-weight @@ -974,6 +1302,13 @@ impl Animatable for FontWeight { FontWeight::Weight900 }) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + let a = (*self as u32) as f64; + let b = (*other as u32) as f64; + a.compute_distance(&b) + } } /// https://drafts.csswg.org/css-transitions/#animtype-simple-list @@ -985,6 +1320,17 @@ impl Animatable for generic_position::Position Result { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + Ok(try!(self.horizontal.compute_squared_distance(&other.horizontal)) + + try!(self.vertical.compute_squared_distance(&other.vertical))) + } } impl RepeatableListAnimatable for generic_position::Position @@ -996,6 +1342,16 @@ impl Animatable for HorizontalPosition { fn interpolate(&self, other: &Self, progress: f64) -> Result { self.0.interpolate(&other.0, progress).map(generic_position::HorizontalPosition) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + self.0.compute_squared_distance(&other.0) + } } impl RepeatableListAnimatable for HorizontalPosition {} @@ -1006,6 +1362,16 @@ impl Animatable for VerticalPosition { fn interpolate(&self, other: &Self, progress: f64) -> Result { self.0.interpolate(&other.0, progress).map(generic_position::VerticalPosition) } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + self.0.compute_squared_distance(&other.0) + } } impl RepeatableListAnimatable for VerticalPosition {} @@ -1021,6 +1387,20 @@ impl Animatable for ClipRect { left: try!(self.left.interpolate(&other.left, time)), }) } + + #[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 { + let list = [ try!(self.top.compute_distance(&other.top)), + try!(self.right.compute_distance(&other.right)), + try!(self.bottom.compute_distance(&other.bottom)), + try!(self.left.compute_distance(&other.left)) ]; + Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) + } } <%def name="impl_animatable_for_shadow(item, transparent_color)"> @@ -1053,6 +1433,29 @@ impl Animatable for ClipRect { % endif }) } + + #[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 { + % if "Box" in item: + if self.inset != other.inset { + return Err(()); + } + % endif + let list = [ try!(self.offset_x.compute_distance(&other.offset_x)), + try!(self.offset_y.compute_distance(&other.offset_y)), + try!(self.blur_radius.compute_distance(&other.blur_radius)), + try!(self.color.compute_distance(&other.color)), + % if "Box" in item: + try!(self.spread_radius.compute_distance(&other.spread_radius)), + % endif + ]; + Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) + } } /// https://drafts.csswg.org/css-transitions/#animtype-shadow-list @@ -2056,6 +2459,32 @@ impl Animatable for Either } } } + + #[inline] + fn compute_distance(&self, other: &Self) -> Result { + match (self, other) { + (&Either::First(ref this), &Either::First(ref other)) => { + this.compute_distance(other) + }, + (&Either::Second(ref this), &Either::Second(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()) + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result { + match (self, other) { + (&Either::First(ref this), &Either::First(ref other)) => { + this.compute_squared_distance(other) + }, + (&Either::Second(ref this), &Either::Second(ref other)) => { + this.compute_squared_distance(other) + }, + _ => Err(()) + } + } } impl <'a> From<<&'a IntermediateRGBA> for RGBA { @@ -2127,6 +2556,29 @@ impl Animatable for IntermediateRGBA { Ok(IntermediateRGBA::new(red, green, blue, alpha)) } } + + #[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 { + let start = [ self.alpha, + self.red * self.alpha, + self.green * self.alpha, + self.blue * self.alpha ]; + let end = [ other.alpha, + other.red * other.alpha, + other.green * other.alpha, + other.blue * other.alpha ]; + let diff = start.iter().zip(&end) + .fold(0.0f64, |n, (&a, &b)| { + let diff = (a - b) as f64; + n + diff * diff + }); + Ok(diff) + } } impl<'a> From<<&'a Either> for Either { @@ -2166,635 +2618,6 @@ impl<'a> From<<&'a Either> for Either Result { - match (self, other) { - % for prop in data.longhands: - % if prop.animatable: - % if prop.animation_value_type != "discrete": - (&AnimationValue::${prop.camel_case}(ref from), - &AnimationValue::${prop.camel_case}(ref to)) => { - from.compute_distance(to) - }, - % else: - (&AnimationValue::${prop.camel_case}(ref _from), - &AnimationValue::${prop.camel_case}(ref _to)) => { - Err(()) - }, - % endif - % endif - % endfor - _ => { - panic!("Expected compute_distance of computed values of the same \ - property, got: {:?}, {:?}", self, other); - } - } - } -} - -/// A trait used to implement [compute_distance]. -/// In order to compute the Euclidean distance of a list, we need to compute squared distance -/// for each element, so the vector can sum it and then get its squared root as the distance. -pub trait ComputeDistance: Sized { - /// Compute distance between a value and another for a given property. - fn compute_distance(&self, other: &Self) -> Result; - - /// Compute squared distance between a value and another for a given property. - /// This is used for list or if there are many components in a property value. - fn compute_squared_distance(&self, other: &Self) -> Result { - self.compute_distance(other).map(|d| d * d) - } -} - -impl ComputeDistance for SmallVec<[T; 1]> { - #[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 { - if self.len() != other.len() { - return Err(()); - } - - let mut squared_dist = 0.0f64; - for (this, other) in self.iter().zip(other) { - let diff = try!(this.compute_squared_distance(other)); - squared_dist += diff; - } - Ok(squared_dist) - } -} - -impl ComputeDistance for Au { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.0.compute_distance(&other.0) - } -} - -impl ComputeDistance for Option - where T: ComputeDistance, -{ - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (self, other) { - (&Some(ref this), &Some(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()), - } - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&Some(ref this), &Some(ref other)) => { - this.compute_squared_distance(other) - }, - _ => Err(()), - } - } -} - -impl ComputeDistance for f32 { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - Ok((*self - *other).abs() as f64) - } -} - -impl ComputeDistance for f64 { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - Ok((*self - *other).abs()) - } -} - -impl ComputeDistance for i32 { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - Ok((*self - *other).abs() as f64) - } -} - -impl ComputeDistance for Visibility { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - if *self == *other { - Ok(0.0) - } else { - Ok(1.0) - } - } -} - -/// https://www.w3.org/TR/smil-animation/#animateColorElement says we should use Euclidean RGB-cube distance. -impl ComputeDistance for RGBA { - #[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) - } -} - -impl ComputeDistance for CSSParserColor { - #[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), - } - } -} - -impl ComputeDistance for IntermediateRGBA { - #[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 { - let start = [ self.alpha, - self.red * self.alpha, - self.green * self.alpha, - self.blue * self.alpha ]; - let end = [ other.alpha, - other.red * other.alpha, - other.green * other.alpha, - other.blue * other.alpha ]; - let diff = start.iter().zip(&end) - .fold(0.0f64, |n, (&a, &b)| { - let diff = (a - b) as f64; - n + diff * diff - }); - Ok(diff) - } -} - -impl ComputeDistance for IntermediateColor { - #[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) { - (IntermediateColor::IntermediateRGBA(ref this), IntermediateColor::IntermediateRGBA(ref other)) => { - this.compute_squared_distance(other) - }, - _ => Ok(0.0), - } - } -} - -impl ComputeDistance for CalcLengthOrPercentage { - #[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 { - let length_diff = (self.length().0 - other.length().0) as f64; - let percentage_diff = (self.percentage() - other.percentage()) as f64; - Ok(length_diff * length_diff + percentage_diff * percentage_diff) - } -} - -impl ComputeDistance for LengthOrPercentage { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (LengthOrPercentage::Length(ref this), - LengthOrPercentage::Length(ref other)) => { - this.compute_distance(other) - }, - (LengthOrPercentage::Percentage(ref this), - LengthOrPercentage::Percentage(ref other)) => { - this.compute_distance(other) - }, - (this, other) => { - let this: CalcLengthOrPercentage = From::from(this); - let other: CalcLengthOrPercentage = From::from(other); - this.compute_distance(&other) - } - } - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (LengthOrPercentage::Length(ref this), - LengthOrPercentage::Length(ref other)) => { - let diff = (this.0 - other.0) as f64; - Ok(diff * diff) - }, - (LengthOrPercentage::Percentage(ref this), - LengthOrPercentage::Percentage(ref other)) => { - let diff = (this - other) as f64; - Ok(diff * diff) - }, - (this, other) => { - let this: CalcLengthOrPercentage = From::from(this); - let other: CalcLengthOrPercentage = From::from(other); - let length_diff = (this.length().0 - other.length().0) as f64; - let percentage_diff = (this.percentage() - other.percentage()) as f64; - Ok(length_diff * length_diff + percentage_diff * percentage_diff) - } - } - } -} - -impl ComputeDistance for LengthOrPercentageOrAuto { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (LengthOrPercentageOrAuto::Length(ref this), - LengthOrPercentageOrAuto::Length(ref other)) => { - this.compute_distance(other) - }, - (LengthOrPercentageOrAuto::Percentage(ref this), - LengthOrPercentageOrAuto::Percentage(ref other)) => { - this.compute_distance(other) - }, - (this, other) => { - // If one of the element is Auto, Option<> will be None, and the returned distance is Err(()) - let this: Option = From::from(this); - let other: Option = From::from(other); - this.compute_distance(&other) - } - } - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (LengthOrPercentageOrAuto::Length(ref this), - LengthOrPercentageOrAuto::Length(ref other)) => { - let diff = (this.0 - other.0) as f64; - Ok(diff * diff) - }, - (LengthOrPercentageOrAuto::Percentage(ref this), - LengthOrPercentageOrAuto::Percentage(ref other)) => { - let diff = (this - other) as f64; - Ok(diff * diff) - }, - (this, other) => { - let this: Option = From::from(this); - let other: Option = From::from(other); - if this.is_none() || other.is_none() { - Err(()) - } else { - let length_diff = (this.unwrap().length().0 - other.unwrap().length().0) as f64; - let percentage_diff = (this.unwrap().percentage() - other.unwrap().percentage()) as f64; - Ok(length_diff * length_diff + percentage_diff * percentage_diff) - } - } - } - } -} - -impl ComputeDistance for LengthOrPercentageOrNone { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (LengthOrPercentageOrNone::Length(ref this), - LengthOrPercentageOrNone::Length(ref other)) => { - this.compute_distance(other) - }, - (LengthOrPercentageOrNone::Percentage(ref this), - LengthOrPercentageOrNone::Percentage(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()) - } - } -} - -impl ComputeDistance for MinLength { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (MinLength::LengthOrPercentage(ref this), - MinLength::LengthOrPercentage(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()), - } - } -} - -impl ComputeDistance for MaxLength { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (MaxLength::LengthOrPercentage(ref this), - MaxLength::LengthOrPercentage(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()), - } - } -} - -impl ComputeDistance for VerticalAlign { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (VerticalAlign::LengthOrPercentage(ref this), - VerticalAlign::LengthOrPercentage(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()), - } - } -} - -impl ComputeDistance for BorderRadiusSize { - #[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 { - Ok(try!(self.0.width.compute_squared_distance(&other.0.width)) + - try!(self.0.height.compute_squared_distance(&other.0.height))) - } -} - -impl ComputeDistance for BackgroundSizeList { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.0.compute_distance(&other.0) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - self.0.compute_squared_distance(&other.0) - } -} - -impl ComputeDistance for LineHeight { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (*self, *other) { - (LineHeight::Length(ref this), - LineHeight::Length(ref other)) => { - this.compute_distance(other) - }, - (LineHeight::Number(ref this), - LineHeight::Number(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()), - } - } -} - -impl ComputeDistance for FontWeight { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - let a = (*self as u32) as f64; - let b = (*other as u32) as f64; - a.compute_distance(&b) - } -} - -impl ComputeDistance for generic_position::Position - where H: ComputeDistance, V: ComputeDistance -{ - #[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 { - Ok(try!(self.horizontal.compute_squared_distance(&other.horizontal)) + - try!(self.vertical.compute_squared_distance(&other.vertical))) - } -} - -impl ComputeDistance for HorizontalPosition { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.0.compute_distance(&other.0) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - self.0.compute_squared_distance(&other.0) - } -} - -impl ComputeDistance for VerticalPosition { - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - self.0.compute_distance(&other.0) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - self.0.compute_squared_distance(&other.0) - } -} - -impl ComputeDistance for ClipRect { - #[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 { - let list = [ try!(self.top.compute_distance(&other.top)), - try!(self.right.compute_distance(&other.right)), - try!(self.bottom.compute_distance(&other.bottom)), - try!(self.left.compute_distance(&other.left)) ]; - Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) - } -} - -impl ComputeDistance for IntermediateTextShadow { - #[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 { - let list = [ try!(self.offset_x.compute_distance(&other.offset_x)), - try!(self.offset_y.compute_distance(&other.offset_y)), - try!(self.blur_radius.compute_distance(&other.blur_radius)), - try!(self.color.compute_distance(&other.color)) ]; - Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) - } -} - -impl ComputeDistance for IntermediateTextShadowList { - #[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 { - let zero = IntermediateTextShadow { - offset_x: Au(0), - offset_y: Au(0), - blur_radius: Au(0), - color: IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent()), - }; - - let max_len = cmp::max(self.0.len(), other.0.len()); - let mut diff_squared = 0.0f64; - for i in 0..max_len { - diff_squared += match (self.0.get(i), other.0.get(i)) { - (Some(shadow), Some(other)) => { - try!(shadow.compute_squared_distance(other)) - }, - (Some(shadow), None) | - (None, Some(shadow)) => { - try!(shadow.compute_squared_distance(&zero)) - }, - (None, None) => unreachable!(), - }; - } - Ok(diff_squared) - } -} - -impl ComputeDistance for IntermediateBoxShadow { - #[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 { - if self.inset != other.inset { - return Err(()); - } - let list = [ try!(self.offset_x.compute_distance(&other.offset_x)), - try!(self.offset_y.compute_distance(&other.offset_y)), - try!(self.color.compute_distance(&other.color)), - try!(self.spread_radius.compute_distance(&other.spread_radius)), - try!(self.blur_radius.compute_distance(&other.blur_radius)) ]; - Ok(list.iter().fold(0.0f64, |sum, diff| sum + diff * diff)) - } -} - -impl ComputeDistance for IntermediateBoxShadowList { - #[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 { - // The inset value must change - let mut zero = IntermediateBoxShadow { - offset_x: Au(0), - offset_y: Au(0), - spread_radius: Au(0), - blur_radius: Au(0), - color: IntermediateColor::IntermediateRGBA(IntermediateRGBA::transparent()), - inset: false, - }; - - let max_len = cmp::max(self.0.len(), other.0.len()); - let mut diff_squared = 0.0f64; - for i in 0..max_len { - diff_squared += match (self.0.get(i), other.0.get(i)) { - (Some(shadow), Some(other)) => { - try!(shadow.compute_squared_distance(other)) - }, - (Some(shadow), None) | - (None, Some(shadow)) => { - zero.inset = shadow.inset; - try!(shadow.compute_squared_distance(&zero)) - } - (None, None) => unreachable!(), - }; - } - Ok(diff_squared) - } -} - -impl ComputeDistance for TransformList { - #[inline] - fn compute_distance(&self, _other: &Self) -> Result { - Err(()) - } -} - -impl ComputeDistance for Either - where T: ComputeDistance, U: ComputeDistance -{ - #[inline] - fn compute_distance(&self, other: &Self) -> Result { - match (self, other) { - (&Either::First(ref this), &Either::First(ref other)) => { - this.compute_distance(other) - }, - (&Either::Second(ref this), &Either::Second(ref other)) => { - this.compute_distance(other) - }, - _ => Err(()) - } - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result { - match (self, other) { - (&Either::First(ref this), &Either::First(ref other)) => { - this.compute_squared_distance(other) - }, - (&Either::Second(ref this), &Either::Second(ref other)) => { - this.compute_squared_distance(other) - }, - _ => Err(()) - } - } -} - #[derive(Copy, Clone, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] #[allow(missing_docs)] @@ -2814,6 +2637,21 @@ impl Animatable for IntermediateColor { _ => 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) { + (IntermediateColor::IntermediateRGBA(ref this), IntermediateColor::IntermediateRGBA(ref other)) => { + this.compute_squared_distance(other) + }, + _ => Ok(0.0), + } + } } impl <'a> From<<&'a CSSParserColor> for IntermediateColor { diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 68cdb5557b8..50e2ce4e9bd 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -195,8 +195,7 @@ ${helpers.single_keyword("background-origin", #[allow(missing_docs)] pub mod computed_value { use values::computed::LengthOrPercentageOrAuto; - use properties::animated_properties::{Animatable, ComputeDistance, - RepeatableListAnimatable}; + use properties::animated_properties::{Animatable, RepeatableListAnimatable}; #[derive(PartialEq, Clone, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -228,9 +227,7 @@ ${helpers.single_keyword("background-origin", _ => Err(()), } } - } - impl ComputeDistance for T { #[inline] fn compute_distance(&self, other: &Self) -> Result { self.compute_squared_distance(other).map(|sd| sd.sqrt()) diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 57236d3a0e8..b9a451b1571 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -2181,7 +2181,7 @@ ${helpers.single_keyword("transform-style", use values::specified::{NoCalcLength, LengthOrPercentage, Percentage}; pub mod computed_value { - use properties::animated_properties::{Animatable, ComputeDistance}; + use properties::animated_properties::Animatable; use values::computed::{Length, LengthOrPercentage}; #[derive(Clone, Copy, Debug, PartialEq)] @@ -2201,9 +2201,7 @@ ${helpers.single_keyword("transform-style", depth: try!(self.depth.interpolate(&other.depth, time)), }) } - } - impl ComputeDistance for T { #[inline] fn compute_distance(&self, other: &Self) -> Result { self.compute_squared_distance(other).map(|sd| sd.sqrt()) diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index 2e78c03e073..f83757fb5e8 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -1022,7 +1022,7 @@ ${helpers.single_keyword_system("font-variant-caps", } pub mod computed_value { - use properties::animated_properties::{Animatable, ComputeDistance}; + use properties::animated_properties::Animatable; use std::fmt; use style_traits::ToCss; use values::CSSFloat; @@ -1062,9 +1062,7 @@ ${helpers.single_keyword_system("font-variant-caps", _ => Err(()), } } - } - impl ComputeDistance for T { #[inline] fn compute_distance(&self, other: &Self) -> Result { match (*self, *other) { diff --git a/components/style/properties/longhand/inherited_table.mako.rs b/components/style/properties/longhand/inherited_table.mako.rs index d89ddaf41ee..aba56b125a2 100644 --- a/components/style/properties/longhand/inherited_table.mako.rs +++ b/components/style/properties/longhand/inherited_table.mako.rs @@ -30,7 +30,7 @@ ${helpers.single_keyword("caption-side", "top bottom", pub mod computed_value { use app_units::Au; - use properties::animated_properties::{Animatable, ComputeDistance}; + use properties::animated_properties::Animatable; #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -48,9 +48,7 @@ ${helpers.single_keyword("caption-side", "top bottom", vertical: try!(self.vertical.interpolate(&other.vertical, time)), }) } - } - impl ComputeDistance for T { #[inline] fn compute_distance(&self, other: &Self) -> Result { self.compute_squared_distance(other).map(|sd| sd.sqrt()) diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index bfc9b5ee50c..b2d57a72393 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -441,14 +441,13 @@ ${helpers.single_keyword("text-align-last", pub mod computed_value { use app_units::Au; - use properties::animated_properties::{Animatable, ComputeDistance}; + use properties::animated_properties::Animatable; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct T(pub Option); ${helpers.impl_animatable_for_option_tuple('Au(0)')} - ${helpers.impl_compute_distance_for_option_tuple('Au(0)')} } impl ToCss for computed_value::T { @@ -527,14 +526,13 @@ ${helpers.single_keyword("text-align-last", } pub mod computed_value { - use properties::animated_properties::{ComputeDistance, Animatable}; + use properties::animated_properties::Animatable; use values::computed::LengthOrPercentage; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct T(pub Option); ${helpers.impl_animatable_for_option_tuple('LengthOrPercentage::zero()')} - ${helpers.impl_compute_distance_for_option_tuple('LengthOrPercentage::zero()')} } impl ToCss for computed_value::T { diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index 666d50f3a80..104929fff77 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -99,7 +99,7 @@ ${helpers.single_keyword("mask-mode", pub use properties::longhands::background_position_x::single_value::parse; pub use properties::longhands::background_position_x::single_value::SpecifiedValue; pub use properties::longhands::background_position_x::single_value::computed_value; - use properties::animated_properties::{Animatable, ComputeDistance, RepeatableListAnimatable}; + use properties::animated_properties::{Animatable, RepeatableListAnimatable}; use properties::longhands::mask_position_x::computed_value::T as MaskPositionX; impl Animatable for MaskPositionX { @@ -110,13 +110,6 @@ ${helpers.single_keyword("mask-mode", } impl RepeatableListAnimatable for MaskPositionX {} - - impl ComputeDistance for MaskPositionX { - #[inline] - fn compute_distance(&self, _other: &Self) -> Result { - Err(()) - } - } <%helpers:vector_longhand name="mask-position-y" products="gecko" @@ -128,7 +121,7 @@ ${helpers.single_keyword("mask-mode", pub use properties::longhands::background_position_y::single_value::parse; pub use properties::longhands::background_position_y::single_value::SpecifiedValue; pub use properties::longhands::background_position_y::single_value::computed_value; - use properties::animated_properties::{Animatable, ComputeDistance, RepeatableListAnimatable}; + use properties::animated_properties::{Animatable, RepeatableListAnimatable}; use properties::longhands::mask_position_y::computed_value::T as MaskPositionY; impl Animatable for MaskPositionY { @@ -139,13 +132,6 @@ ${helpers.single_keyword("mask-mode", } impl RepeatableListAnimatable for MaskPositionY {} - - impl ComputeDistance for MaskPositionY { - #[inline] - fn compute_distance(&self, _other: &Self) -> Result { - Err(()) - } - } ${helpers.single_keyword("mask-clip", diff --git a/components/style/values/mod.rs b/components/style/values/mod.rs index aa225777f11..17db73c4ebc 100644 --- a/components/style/values/mod.rs +++ b/components/style/values/mod.rs @@ -11,7 +11,7 @@ use Atom; pub use cssparser::{RGBA, Token, Parser, serialize_identifier, serialize_string}; use parser::{Parse, ParserContext}; -use properties::animated_properties::{Animatable, ComputeDistance}; +use properties::animated_properties::Animatable; use std::ascii::AsciiExt; use std::borrow::Cow; use std::fmt::{self, Debug}; @@ -134,13 +134,6 @@ macro_rules! define_keyword_type { } } - impl ComputeDistance for $name { - #[inline] - fn compute_distance(&self, _other: &Self) -> Result { - Err(()) - } - } - impl fmt::Debug for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, $css) diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index bed5c74edbf..3de322d9d98 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -75,7 +75,7 @@ use style::parser::{LengthParsingMode, ParserContext}; use style::properties::{CascadeFlags, ComputedValues, Importance, ParsedDeclaration, StyleBuilder}; use style::properties::{PropertyDeclarationBlock, PropertyId}; use style::properties::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP; -use style::properties::animated_properties::{Animatable, AnimationValue, ComputeDistance, TransitionProperty}; +use style::properties::animated_properties::{Animatable, AnimationValue, TransitionProperty}; use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::rule_tree::{StrongRuleNode, StyleSource};