diff options
Diffstat (limited to 'components/style/animation.rs')
-rw-r--r-- | components/style/animation.rs | 177 |
1 files changed, 176 insertions, 1 deletions
diff --git a/components/style/animation.rs b/components/style/animation.rs index d8652b3ea0e..cecf676c5e5 100644 --- a/components/style/animation.rs +++ b/components/style/animation.rs @@ -17,7 +17,11 @@ use properties::longhands::text_shadow::computed_value::TextShadow; use properties::longhands::text_shadow::computed_value::T as TextShadowList; use properties::longhands::background_position::computed_value::T as BackgroundPosition; use properties::longhands::transition_property; -use values::computed::{LengthOrPercentageOrAuto, LengthOrPercentageOrNone, LengthOrPercentage, Length, Time}; +use properties::longhands::transform::computed_value::ComputedMatrix; +use properties::longhands::transform::computed_value::ComputedOperation as TransformOperation; +use properties::longhands::transform::computed_value::T as TransformList; +use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone}; +use values::computed::{LengthAndPercentage, LengthOrPercentage, Length, Time}; use values::CSSFloat; use cssparser::{RGBA, Color}; @@ -92,6 +96,10 @@ impl PropertyAnimation { AnimatedProperty::TextShadow(old_style.get_effects().text_shadow.clone(), new_style.get_effects().text_shadow.clone()) } + TransitionProperty::Transform => { + AnimatedProperty::Transform(old_style.get_effects().transform.clone(), + new_style.get_effects().transform.clone()) + } } } } @@ -220,6 +228,7 @@ impl PropertyAnimation { [TextIndent; mutate_inheritedtext; text_indent], [TextShadow; mutate_effects; text_shadow], [Top; mutate_positionoffsets; top], + [Transform; mutate_effects; transform], [VerticalAlign; mutate_box; vertical_align], [Visibility; mutate_inheritedbox; visibility], [Width; mutate_box; width], @@ -274,6 +283,7 @@ enum AnimatedProperty { TextIndent(LengthOrPercentage, LengthOrPercentage), TextShadow(TextShadowList, TextShadowList), Top(LengthOrPercentageOrAuto, LengthOrPercentageOrAuto), + Transform(TransformList, TransformList), VerticalAlign(VerticalAlign, VerticalAlign), Visibility(Visibility, Visibility), Width(LengthOrPercentageOrAuto, LengthOrPercentageOrAuto), @@ -329,6 +339,7 @@ impl AnimatedProperty { AnimatedProperty::Visibility(ref a, ref b) => a == b, AnimatedProperty::WordSpacing(ref a, ref b) => a == b, AnimatedProperty::ZIndex(ref a, ref b) => a == b, + AnimatedProperty::Transform(ref a, ref b) => a == b, } } } @@ -495,6 +506,17 @@ impl Interpolate for LengthOrPercentage { } } +impl Interpolate for LengthAndPercentage { + #[inline] + fn interpolate(&self, other: &LengthAndPercentage, time: f32) + -> Option<LengthAndPercentage> { + Some(LengthAndPercentage { + length: self.length.interpolate(&other.length, time).unwrap(), + percentage: self.percentage.interpolate(&other.percentage, time).unwrap(), + }) + } +} + impl Interpolate for LengthOrPercentageOrAuto { #[inline] fn interpolate(&self, other: &LengthOrPercentageOrAuto, time: f32) @@ -670,6 +692,159 @@ impl Interpolate for TextShadowList { } } +/// 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 +fn can_interpolate_list(from_list: &Vec<TransformOperation>, + to_list: &Vec<TransformOperation>) -> bool { + // Lists must be equal length + if from_list.len() != to_list.len() { + return false; + } + + // Each transform operation must match primitive type in other list + for (from, to) in from_list.iter().zip(to_list.iter()) { + match (from, to) { + (&TransformOperation::Matrix(..), &TransformOperation::Matrix(..)) | + (&TransformOperation::Skew(..), &TransformOperation::Skew(..)) | + (&TransformOperation::Translate(..), &TransformOperation::Translate(..)) | + (&TransformOperation::Scale(..), &TransformOperation::Scale(..)) | + (&TransformOperation::Rotate(..), &TransformOperation::Rotate(..)) | + (&TransformOperation::Perspective(..), &TransformOperation::Perspective(..)) => {} + _ => { + return false; + } + } + } + + true +} + +/// Interpolate two transform lists. +/// http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms +fn interpolate_transform_list(from_list: &Vec<TransformOperation>, + to_list: &Vec<TransformOperation>, + time: f32) -> TransformList { + let mut result = vec!(); + + if can_interpolate_list(from_list, to_list) { + for (from, to) in from_list.iter().zip(to_list.iter()) { + match (from, to) { + (&TransformOperation::Matrix(from), + &TransformOperation::Matrix(_to)) => { + // TODO(gw): Implement matrix decomposition and interpolation + result.push(TransformOperation::Matrix(from)); + } + (&TransformOperation::Skew(fx, fy), + &TransformOperation::Skew(tx, ty)) => { + let ix = fx.interpolate(&tx, time).unwrap(); + let iy = fy.interpolate(&ty, time).unwrap(); + result.push(TransformOperation::Skew(ix, iy)); + } + (&TransformOperation::Translate(fx, fy, fz), + &TransformOperation::Translate(tx, ty, tz)) => { + let ix = fx.interpolate(&tx, time).unwrap(); + let iy = fy.interpolate(&ty, time).unwrap(); + let iz = fz.interpolate(&tz, time).unwrap(); + result.push(TransformOperation::Translate(ix, iy, iz)); + } + (&TransformOperation::Scale(fx, fy, fz), + &TransformOperation::Scale(tx, ty, tz)) => { + let ix = fx.interpolate(&tx, time).unwrap(); + let iy = fy.interpolate(&ty, time).unwrap(); + let iz = fz.interpolate(&tz, time).unwrap(); + result.push(TransformOperation::Scale(ix, iy, iz)); + } + (&TransformOperation::Rotate(fx, fy, fz, fa), + &TransformOperation::Rotate(_tx, _ty, _tz, _ta)) => { + // TODO(gw): Implement matrix decomposition and interpolation + result.push(TransformOperation::Rotate(fx, fy, fz, fa)); + } + (&TransformOperation::Perspective(fd), + &TransformOperation::Perspective(_td)) => { + // TODO(gw): Implement matrix decomposition and interpolation + result.push(TransformOperation::Perspective(fd)); + } + _ => { + // This should be unreachable due to the can_interpolate_list() call. + unreachable!(); + } + } + } + } else { + // TODO(gw): Implement matrix decomposition and interpolation + result.push_all(from_list); + } + + Some(result) +} + +/// Build an equivalent 'identity transform function list' based +/// on an existing transform list. +/// http://dev.w3.org/csswg/css-transforms/#none-transform-animation +fn build_identity_transform_list(list: &Vec<TransformOperation>) -> Vec<TransformOperation> { + let mut result = vec!(); + + for operation in list { + match operation { + &TransformOperation::Matrix(..) => { + let identity = ComputedMatrix::identity(); + result.push(TransformOperation::Matrix(identity)); + } + &TransformOperation::Skew(..) => { + result.push(TransformOperation::Skew(0.0, 0.0)); + } + &TransformOperation::Translate(..) => { + result.push(TransformOperation::Translate(LengthAndPercentage::zero(), + LengthAndPercentage::zero(), + Au(0))); + } + &TransformOperation::Scale(..) => { + result.push(TransformOperation::Scale(1.0, 1.0, 1.0)); + } + &TransformOperation::Rotate(..) => { + result.push(TransformOperation::Rotate(0.0, 0.0, 1.0, Angle(0.0))); + } + &TransformOperation::Perspective(..) => { + // http://dev.w3.org/csswg/css-transforms/#identity-transform-function + let identity = ComputedMatrix::identity(); + result.push(TransformOperation::Matrix(identity)); + } + } + } + + result +} + +impl Interpolate for TransformList { + #[inline] + fn interpolate(&self, other: &TransformList, time: f32) -> Option<TransformList> { + // http://dev.w3.org/csswg/css-transforms/#interpolation-of-transforms + let result = match (self, other) { + (&Some(ref from_list), &Some(ref to_list)) => { + // Two lists of transforms + interpolate_transform_list(from_list, &to_list, time) + } + (&Some(ref from_list), &None) => { + // http://dev.w3.org/csswg/css-transforms/#none-transform-animation + let to_list = build_identity_transform_list(from_list); + interpolate_transform_list(from_list, &to_list, time) + } + (&None, &Some(ref to_list)) => { + // http://dev.w3.org/csswg/css-transforms/#none-transform-animation + let from_list = build_identity_transform_list(to_list); + interpolate_transform_list(&from_list, to_list, time) + } + (&None, &None) => { + // http://dev.w3.org/csswg/css-transforms/#none-none-animation + None + } + }; + + Some(result) + } +} + /// Accesses an element of an array, "wrapping around" using modular arithmetic. This is needed /// to handle values of differing lengths according to CSS-TRANSITIONS § 2. pub trait GetMod { |