Bug 1207734 - Part 8.b. (stylo) Implement Animate trait for individual transforms. draft
authorcku <cku@mozilla.com>
Thu, 07 Dec 2017 14:46:37 +0800
changeset 749196 7b7636b19922be08ad107df6fda8b807132f2914
parent 749195 6cab7d237f2d48f53bfa68b5a6835904c15771f4
child 749197 f7f5499cde9e8120cd73f60f9a274634045308f4
push id97349
push userbbirtles@mozilla.com
push dateWed, 31 Jan 2018 02:59:16 +0000
bugs1207734
milestone60.0a1
Bug 1207734 - Part 8.b. (stylo) Implement Animate trait for individual transforms. MozReview-Commit-ID: HsEmyJ1d0D3
servo/components/style/properties/helpers/animated_properties.mako.rs
servo/components/style/values/generics/transform.rs
--- a/servo/components/style/properties/helpers/animated_properties.mako.rs
+++ b/servo/components/style/properties/helpers/animated_properties.mako.rs
@@ -41,17 +41,20 @@ use values::computed::{ClipRect, Context
 use values::computed::{Length, LengthOrPercentage, LengthOrPercentageOrAuto};
 use values::computed::{LengthOrPercentageOrNone, MaxLength};
 use values::computed::{NonNegativeNumber, Number, NumberOrPercentage, Percentage};
 use values::computed::length::NonNegativeLengthOrPercentage;
 use values::computed::ToComputedValue;
 use values::computed::transform::{DirectionVector, Matrix, Matrix3D};
 use values::computed::transform::TransformOperation as ComputedTransformOperation;
 use values::computed::transform::Transform as ComputedTransform;
-use values::generics::transform::{self, Transform, TransformOperation};
+use values::computed::transform::Rotate as ComputedRotate;
+use values::computed::transform::Translate as ComputedTranslate;
+use values::computed::transform::Scale as ComputedScale;
+use values::generics::transform::{self, Rotate, Translate, Scale, Transform, TransformOperation};
 use values::distance::{ComputeSquaredDistance, SquaredDistance};
 #[cfg(feature = "gecko")] use values::generics::FontSettings as GenericFontSettings;
 #[cfg(feature = "gecko")] use values::generics::FontSettingTag as GenericFontSettingTag;
 #[cfg(feature = "gecko")] use values::generics::FontSettingTagFloat;
 use values::generics::NonNegative;
 use values::generics::effects::Filter;
 use values::generics::position as generic_position;
 use values::generics::svg::{SVGLength,  SvgLengthOrPercentageOrNumber, SVGPaint};
@@ -2283,16 +2286,140 @@ impl Matrix3D {
              self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33),
         };
 
         Some(x)
     }
 }
 
 /// <https://drafts.csswg.org/css-transforms/#interpolation-of-transforms>
+impl ComputedRotate {
+    fn fill_unspecified(rotate: &ComputedRotate)
+        -> Result<(Number, Number, Number, Angle), ()>{
+        // According to the spec:
+        // https://drafts.csswg.org/css-transforms-2/#individual-transforms
+        //
+        // If the axis is unspecified, it defaults to "0 0 1"
+        match rotate {
+            &Rotate::None =>
+                Ok((0., 0., 1., Angle::zero())),
+            &Rotate::Rotate3D(rx, ry, rz, angle) => Ok((rx, ry, rz, angle)),
+            &Rotate::Rotate(angle) => Ok((0., 0., 1., angle)),
+        }
+    }
+}
+
+impl Animate for ComputedRotate {
+    #[inline]
+    fn animate(
+        &self,
+        other: &Self,
+        procedure: Procedure,
+    ) -> Result<Self, ()> {
+        let from = ComputedRotate::fill_unspecified(self)?;
+        let to = ComputedRotate::fill_unspecified(other)?;
+
+        let (fx, fy, fz, fa) = transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
+        let (tx, ty, tz, ta) = transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3);
+        if (fx, fy, fz) == (tx, ty, tz) {
+            return Ok(Rotate::Rotate3D(fx, fy, fz, fa.animate(&ta, procedure)?));
+        }
+
+        let fv = DirectionVector::new(fx, fy, fz);
+        let tv = DirectionVector::new(tx, ty, tz);
+        let fq = Quaternion::from_direction_and_angle(&fv, fa.radians64());
+        let tq = Quaternion::from_direction_and_angle(&tv, ta.radians64());
+
+        let rq = MatrixDecomposed3D::slerp(&fq, &tq, procedure)?;
+        let (x, y, z, angle) =
+            transform::get_normalized_vector_and_angle(rq.0 as f32,
+                                                       rq.1 as f32,
+                                                       rq.2 as f32,
+                                                       rq.3.acos() as f32 *2.0);
+
+        Ok(Rotate::Rotate3D(x, y, z, Angle::from_radians(angle)))
+    }
+}
+
+/// <https://drafts.csswg.org/css-transforms/#interpolation-of-transforms>
+impl ComputedTranslate {
+    fn fill_unspecified(translate: &ComputedTranslate)
+        -> Result<(LengthOrPercentage, LengthOrPercentage, Length), ()>{
+        // According to the spec:
+        // https://drafts.csswg.org/css-transforms-2/#individual-transforms
+        //
+        // Unspecified translations default to 0px
+        match translate {
+            &Translate::None => {
+                Ok((LengthOrPercentage::Length(Length::zero()),
+                    LengthOrPercentage::Length(Length::zero()),
+                    Length::zero()))
+            },
+            &Translate::Translate3D(tx, ty, tz) => Ok((tx, ty, tz)),
+            &Translate::Translate(tx, ty) => Ok((tx, ty, Length::zero())),
+            &Translate::TranslateX(tx) => Ok((tx, LengthOrPercentage::Length(Length::zero()), Length::zero())),
+        }
+    }
+}
+
+impl Animate for ComputedTranslate {
+    #[inline]
+    fn animate(
+        &self,
+        other: &Self,
+        procedure: Procedure,
+    ) -> Result<Self, ()> {
+        let from = ComputedTranslate::fill_unspecified(self)?;
+        let to = ComputedTranslate::fill_unspecified(other)?;
+
+        Ok(Translate::Translate3D(from.0.animate(&to.0, procedure)?,
+                                  from.1.animate(&to.1, procedure)?,
+                                  from.2.animate(&to.2, procedure)?))
+    }
+}
+
+/// <https://drafts.csswg.org/css-transforms/#interpolation-of-transforms>
+impl ComputedScale {
+    fn fill_unspecified(scale: &ComputedScale)
+        -> Result<(Number, Number, Number), ()>{
+        // According to the spec:
+        // https://drafts.csswg.org/css-transforms-2/#individual-transforms
+        //
+        // Unspecified scales default to 1
+        match scale {
+            &Scale::None => Ok((1.0, 1.0, 1.0)),
+            &Scale::Scale3D(sx, sy, sz) => Ok((sx, sy, sz)),
+            &Scale::Scale(sx, sy) => Ok((sx, sy, 1.)),
+            &Scale::ScaleX(sx) => Ok((sx, 1., 1.)),
+        }
+    }
+}
+
+impl Animate for ComputedScale {
+    #[inline]
+    fn animate(
+        &self,
+        other: &Self,
+        procedure: Procedure,
+    ) -> Result<Self, ()> {
+        let from = ComputedScale::fill_unspecified(self)?;
+        let to = ComputedScale::fill_unspecified(other)?;
+
+        if procedure == Procedure::Add {
+            // scale(x1,y1,z1)*scale(x2,y2,z2) = scale(x1*x2, y1*y2, z1*z2)
+            return Ok(Scale::Scale3D(from.0 * to.0, from.1 * to.1, from.2 * to.2));
+        }
+
+        Ok(Scale::Scale3D(animate_multiplicative_factor(from.0, to.0, procedure)?,
+                          animate_multiplicative_factor(from.1, to.1, procedure)?,
+                          animate_multiplicative_factor(from.2, to.2, procedure)?))
+    }
+}
+
+/// <https://drafts.csswg.org/css-transforms/#interpolation-of-transforms>
 impl Animate for ComputedTransform {
     #[inline]
     fn animate(
         &self,
         other_: &Self,
         procedure: Procedure,
     ) -> Result<Self, ()> {
 
--- a/servo/components/style/values/generics/transform.rs
+++ b/servo/components/style/values/generics/transform.rs
@@ -664,47 +664,47 @@ pub fn get_normalized_vector_and_angle<T
         // rotation to not be applied, so we use identity matrix (i.e. rotate3d(0, 0, 1, 0)).
         (0., 0., 1., T::zero())
     } else {
         let vector = vector.normalize();
         (vector.x, vector.y, vector.z, angle)
     }
 }
 
-#[derive(ToComputedValue, Animate, ComputeSquaredDistance, ToAnimatedZero)]
+#[derive(ToComputedValue, ComputeSquaredDistance, ToAnimatedZero)]
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
 /// A value of the `Rotate` property
 ///
 /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
 pub enum Rotate<Number, Angle> {
     /// 'none'
     None,
     /// '<angle>'
     Rotate(Angle),
     /// '<number>{3} <angle>'
     Rotate3D(Number, Number, Number, Angle),
 }
 
-#[derive(ToComputedValue, Animate, ComputeSquaredDistance, ToAnimatedZero)]
+#[derive(ToComputedValue, ComputeSquaredDistance, ToAnimatedZero)]
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
 /// A value of the `Translate` property
 ///
 /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
 pub enum Translate<LengthOrPercentage, Length> {
     /// 'none'
     None,
     /// '<length-percentage>'
     TranslateX(LengthOrPercentage),
     /// '<length-percentage> <length-percentage>'
     Translate(LengthOrPercentage, LengthOrPercentage),
     /// '<length-percentage> <length-percentage> <length>'
     Translate3D(LengthOrPercentage, LengthOrPercentage, Length),
 }
 
-#[derive(ToComputedValue, Animate, ComputeSquaredDistance, ToAnimatedZero)]
+#[derive(ToComputedValue, ComputeSquaredDistance, ToAnimatedZero)]
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
 /// A value of the `Scale` property
 ///
 /// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
 pub enum Scale<Number> {
     /// 'none'
     None,
     /// '<number>'