diff options
-rw-r--r-- | components/style/gecko_bindings/bindings.rs | 7 | ||||
-rw-r--r-- | components/style/properties/helpers.mako.rs | 51 | ||||
-rw-r--r-- | components/style/properties/helpers/animated_properties.mako.rs | 619 | ||||
-rw-r--r-- | components/style/properties/longhand/background.mako.rs | 20 | ||||
-rw-r--r-- | components/style/properties/longhand/box.mako.rs | 17 | ||||
-rw-r--r-- | components/style/properties/longhand/font.mako.rs | 13 | ||||
-rw-r--r-- | components/style/properties/longhand/inherited_text.mako.rs | 6 | ||||
-rw-r--r-- | components/style/properties/longhand/svg.mako.rs | 18 | ||||
-rw-r--r-- | ports/geckolib/glue.rs | 11 |
9 files changed, 750 insertions, 12 deletions
diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 2ea1f286db5..603efb2b100 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -1754,6 +1754,13 @@ extern "C" { -> bool; } extern "C" { + pub fn Servo_AnimationValues_ComputeDistance(from: + RawServoAnimationValueBorrowed, + to: + RawServoAnimationValueBorrowed) + -> f64; +} +extern "C" { pub fn Servo_AnimationValue_Serialize(value: RawServoAnimationValueBorrowed, property: nsCSSPropertyID, diff --git a/components/style/properties/helpers.mako.rs b/components/style/properties/helpers.mako.rs index a6cb68f160f..115ed297c57 100644 --- a/components/style/properties/helpers.mako.rs +++ b/components/style/properties/helpers.mako.rs @@ -95,6 +95,19 @@ 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<f64, ()> { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_squared_distance(&other.0) + } + } % endif } @@ -785,3 +798,41 @@ } } </%def> + +/// Macro for defining ComputeDistance trait for tuple struct which has Option<T>, +/// e.g. struct T(pub Option<Au>). +<%def name="impl_compute_distance_for_option_tuple(value_for_none)"> + impl ComputeDistance for T { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&T(Some(ref this)), &T(Some(ref other))) => { + this.compute_distance(other) + }, + (&T(Some(ref value)), &T(None)) | + (&T(None), &T(Some(ref value)))=> { + value.compute_distance(&${value_for_none}) + }, + (&T(None), &T(None)) => { + Ok(0.0) + }, + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&T(Some(ref this)), &T(Some(ref other))) => { + this.compute_squared_distance(other) + }, + (&T(Some(ref value)), &T(None)) | + (&T(None), &T(Some(ref value))) => { + value.compute_squared_distance(&${value_for_none}) + }, + (&T(None), &T(None)) => { + Ok(0.0) + }, + } + } + } +</%def> diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index ee90f5283b7..fe8b4a47b75 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -10,7 +10,7 @@ use euclid::{Point2D, Size2D}; #[cfg(feature = "gecko")] use gecko_bindings::structs::nsCSSPropertyID; use properties::{CSSWideKeyword, PropertyDeclaration}; use properties::longhands; -use properties::longhands::background_size::computed_value::T as BackgroundSize; +use properties::longhands::background_size::computed_value::T as BackgroundSizeList; use properties::longhands::font_weight::computed_value::T as FontWeight; use properties::longhands::line_height::computed_value::T as LineHeight; use properties::longhands::text_shadow::computed_value::T as TextShadowList; @@ -696,14 +696,14 @@ impl Interpolate for VerticalAlign { } } } -impl Interpolate for BackgroundSize { + +impl Interpolate for BackgroundSizeList { #[inline] fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - self.0.interpolate(&other.0, progress).map(BackgroundSize) + self.0.interpolate(&other.0, progress).map(BackgroundSizeList) } } - /// https://drafts.csswg.org/css-transitions/#animtype-color impl Interpolate for RGBA { #[inline] @@ -2032,3 +2032,614 @@ impl<T, U> Interpolate for Either<T, U> } } } + + +/// We support ComputeDistance for an API in gecko to test the transition per property. +impl ComputeDistance for AnimationValue { + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + % for prop in data.longhands: + % if prop.animatable: + % if prop.animation_type == "normal": + (&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<f64, ()>; + + /// 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<f64, ()> { + self.compute_distance(other).map(|d| d * d) + } +} + +impl<T: ComputeDistance> ComputeDistance for Vec<T> { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + self.0.compute_distance(&other.0) + } +} + +impl ComputeDistance for Auto { + #[inline] + fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { + Err(()) + } +} + +impl ComputeDistance for Normal { + #[inline] + fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { + Err(()) + } +} + +impl <T> ComputeDistance for Option<T> + where T: ComputeDistance, +{ + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&Some(ref this), &Some(ref other)) => { + this.compute_distance(other) + }, + _ => Err(()), + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + Ok((*self - *other).abs() as f64) + } +} + +impl ComputeDistance for f64 { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok((*self - *other).abs()) + } +} + +impl ComputeDistance for i32 { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + Ok((*self - *other).abs() as f64) + } +} + +impl ComputeDistance for Visibility { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + self.compute_squared_distance(other).map(|sq| sq.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + match (*self, *other) { + (CSSParserColor::RGBA(ref this), CSSParserColor::RGBA(ref other)) => { + this.compute_squared_distance(other) + }, + _ => Ok(0.0), + } + } +} + +impl ComputeDistance for CalcLengthOrPercentage { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sq| sq.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + 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<f64, ()> { + 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<f64, ()> { + 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<CalcLengthOrPercentage> = From::from(this); + let other: Option<CalcLengthOrPercentage> = From::from(other); + this.compute_distance(&other) + } + } + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<CalcLengthOrPercentage> = From::from(this); + let other: Option<CalcLengthOrPercentage> = 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<f64, ()> { + 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 LengthOrNone { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (*self, *other) { + (Either::First(ref length), Either::First(ref other)) => { + length.compute_distance(other) + }, + _ => Err(()), + } + } +} + +impl ComputeDistance for MinLength { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + 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<f64, ()> { + 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<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_squared_distance(&other.0) + } +} + +impl ComputeDistance for LineHeight { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + let a = (*self as u32) as f64; + let b = (*other as u32) as f64; + a.compute_distance(&b) + } +} + +impl ComputeDistance for Position { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_squared_distance(&other.0) + } +} + +impl ComputeDistance for VerticalPosition { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_distance(&other.0) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + self.0.compute_squared_distance(&other.0) + } +} + +impl ComputeDistance for ClipRect { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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 TextShadow { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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 TextShadowList { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + let zero = TextShadow { + offset_x: Au(0), + offset_y: Au(0), + blur_radius: Au(0), + color: CSSParserColor::RGBA(RGBA::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 BoxShadow { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + 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 BoxShadowList { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + // The inset value must change + let mut zero = BoxShadow { + offset_x: Au(0), + offset_y: Au(0), + spread_radius: Au(0), + blur_radius: Au(0), + color: CSSParserColor::RGBA(RGBA::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<f64, ()> { + Err(()) + } +} + +impl<T, U> ComputeDistance for Either<T, U> + where T: ComputeDistance, U: ComputeDistance +{ + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + 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<f64, ()> { + 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(()) + } + } +} diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 994f70a0a25..2c085cfe9b9 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -334,7 +334,7 @@ ${helpers.single_keyword("background-origin", #[allow(missing_docs)] pub mod computed_value { use values::computed::LengthOrPercentageOrAuto; - use properties::animated_properties::{Interpolate, RepeatableListInterpolate}; + use properties::animated_properties::{ComputeDistance, Interpolate, RepeatableListInterpolate}; #[derive(PartialEq, Clone, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] @@ -367,6 +367,24 @@ ${helpers.single_keyword("background-origin", } } } + + impl ComputeDistance for T { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + match (self, other) { + (&T::Explicit(ref me), &T::Explicit(ref other)) => { + Ok(try!(me.width.compute_squared_distance(&other.width)) + + try!(me.height.compute_squared_distance(&other.height))) + }, + _ => Err(()) + } + } + } } impl ToCss for computed_value::T { diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index 9f539243fd2..4e6c958f7e5 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -2197,7 +2197,7 @@ ${helpers.single_keyword("transform-style", use values::specified::{NoCalcLength, LengthOrPercentage, Percentage}; pub mod computed_value { - use properties::animated_properties::Interpolate; + use properties::animated_properties::{ComputeDistance, Interpolate}; use values::computed::{Length, LengthOrPercentage}; #[derive(Clone, Copy, Debug, PartialEq)] @@ -2209,6 +2209,7 @@ ${helpers.single_keyword("transform-style", } impl Interpolate for T { + #[inline] fn interpolate(&self, other: &Self, time: f64) -> Result<Self, ()> { Ok(T { horizontal: try!(self.horizontal.interpolate(&other.horizontal, time)), @@ -2217,6 +2218,20 @@ ${helpers.single_keyword("transform-style", }) } } + + impl ComputeDistance for T { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + self.compute_squared_distance(other).map(|sd| sd.sqrt()) + } + + #[inline] + fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { + Ok(try!(self.horizontal.compute_squared_distance(&other.horizontal)) + + try!(self.vertical.compute_squared_distance(&other.vertical)) + + try!(self.depth.compute_squared_distance(&other.depth))) + } + } } impl HasViewportPercentage for SpecifiedValue { diff --git a/components/style/properties/longhand/font.mako.rs b/components/style/properties/longhand/font.mako.rs index e9ad7208c76..edb99e39caf 100644 --- a/components/style/properties/longhand/font.mako.rs +++ b/components/style/properties/longhand/font.mako.rs @@ -818,7 +818,7 @@ ${helpers.single_keyword("font-variant-caps", } pub mod computed_value { - use properties::animated_properties::Interpolate; + use properties::animated_properties::{ComputeDistance, Interpolate}; use std::fmt; use style_traits::ToCss; use values::CSSFloat; @@ -850,6 +850,17 @@ ${helpers.single_keyword("font-variant-caps", } } } + + impl ComputeDistance for T { + #[inline] + fn compute_distance(&self, other: &Self) -> Result<f64, ()> { + match (*self, *other) { + (T::Number(ref number), T::Number(ref other)) => + number.compute_distance(other), + _ => Err(()), + } + } + } } #[inline] diff --git a/components/style/properties/longhand/inherited_text.mako.rs b/components/style/properties/longhand/inherited_text.mako.rs index bddc1ea10c7..0b1cf0a0229 100644 --- a/components/style/properties/longhand/inherited_text.mako.rs +++ b/components/style/properties/longhand/inherited_text.mako.rs @@ -439,13 +439,14 @@ ${helpers.single_keyword("text-align-last", pub mod computed_value { use app_units::Au; - use properties::animated_properties::Interpolate; + use properties::animated_properties::{ComputeDistance, Interpolate}; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct T(pub Option<Au>); ${helpers.impl_interpolate_for_option_tuple('Au(0)')} + ${helpers.impl_compute_distance_for_option_tuple('Au(0)')} } impl ToCss for computed_value::T { @@ -523,13 +524,14 @@ ${helpers.single_keyword("text-align-last", } pub mod computed_value { - use properties::animated_properties::Interpolate; + use properties::animated_properties::{ComputeDistance, Interpolate}; use values::computed::LengthOrPercentage; #[derive(Debug, Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct T(pub Option<LengthOrPercentage>); ${helpers.impl_interpolate_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 dea04984cf1..ddcf86c35f6 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -121,7 +121,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::{Interpolate, RepeatableListInterpolate}; + use properties::animated_properties::{ComputeDistance, Interpolate, RepeatableListInterpolate}; use properties::longhands::mask_position_x::computed_value::T as MaskPositionX; impl Interpolate for MaskPositionX { @@ -132,6 +132,13 @@ ${helpers.single_keyword("mask-mode", } impl RepeatableListInterpolate for MaskPositionX {} + + impl ComputeDistance for MaskPositionX { + #[inline] + fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { + Err(()) + } + } </%helpers:vector_longhand> <%helpers:vector_longhand name="mask-position-y" products="gecko" animation_type="normal" extra_prefixes="webkit" @@ -142,7 +149,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::{Interpolate, RepeatableListInterpolate}; + use properties::animated_properties::{ComputeDistance, Interpolate, RepeatableListInterpolate}; use properties::longhands::mask_position_y::computed_value::T as MaskPositionY; impl Interpolate for MaskPositionY { @@ -153,6 +160,13 @@ ${helpers.single_keyword("mask-mode", } impl RepeatableListInterpolate for MaskPositionY {} + + impl ComputeDistance for MaskPositionY { + #[inline] + fn compute_distance(&self, _other: &Self) -> Result<f64, ()> { + Err(()) + } + } </%helpers:vector_longhand> ${helpers.single_keyword("mask-clip", diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index 81c956c3187..426802e615b 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -74,7 +74,7 @@ use style::parser::{LengthParsingMode, ParserContext}; use style::properties::{CascadeFlags, ComputedValues, Importance, ParsedDeclaration}; use style::properties::{PropertyDeclarationBlock, PropertyId}; use style::properties::SKIP_ROOT_AND_ITEM_BASED_DISPLAY_FIXUP; -use style::properties::animated_properties::{AnimationValue, Interpolate, TransitionProperty}; +use style::properties::animated_properties::{AnimationValue, ComputeDistance, Interpolate, TransitionProperty}; use style::properties::parse_one_declaration; use style::restyle_hints::{self, RestyleHint}; use style::rule_tree::StyleSource; @@ -266,6 +266,15 @@ pub extern "C" fn Servo_AnimationValues_IsInterpolable(from: RawServoAnimationVa } #[no_mangle] +pub extern "C" fn Servo_AnimationValues_ComputeDistance(from: RawServoAnimationValueBorrowed, + to: RawServoAnimationValueBorrowed) + -> f64 { + let from_value = AnimationValue::as_arc(&from); + let to_value = AnimationValue::as_arc(&to); + from_value.compute_distance(to_value).unwrap_or(0.0) +} + +#[no_mangle] pub extern "C" fn Servo_AnimationValueMap_Push(value_map: RawServoAnimationValueMapBorrowed, property: nsCSSPropertyID, value: RawServoAnimationValueBorrowed) |