Bug 1424134 - Part 3: Implement ComputeSquaredDistance for individual transforms. r=birtles
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 16 Nov 2018 18:58:41 +0000
changeset 503295 fbf6efa9b8ecb9697ec385a96b4a5854b11ad21c
parent 503294 f0c56dea286e3ffc9ae90bc56e702060388af651
child 503296 dbc9d48aa60b8d31cc1ac90fe41f1fc386ff77cb
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1424134
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1424134 - Part 3: Implement ComputeSquaredDistance for individual transforms. r=birtles We manually implement ComputeSquaredDistance for Translate, Rotate, and Scale because we have to handle mismatch cases, and actually we don't need to implement it for specified types. Depends on D11934 Differential Revision: https://phabricator.services.mozilla.com/D11935
dom/animation/test/mochitest.ini
dom/animation/test/mozilla/test_distance_of_transform.html
servo/components/style/values/animated/transform.rs
servo/components/style/values/generics/transform.rs
--- a/dom/animation/test/mochitest.ini
+++ b/dom/animation/test/mochitest.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 prefs =
   dom.animations-api.compositing.enabled=true
   dom.animations-api.core.enabled=true
   dom.animations-api.getAnimations.enabled=true
   dom.animations-api.implicit-keyframes.enabled=true
   dom.animations-api.timelines.enabled=true
   layout.css.motion-path.enabled=true
+  layout.css.individual-transform.enabled=true
 # Support files for chrome tests that we want to load over HTTP need
 # to go in here, not chrome.ini.
 support-files =
   chrome/file_animate_xrays.html
   mozilla/xhr_doc.html
   mozilla/file_deferred_start.html
   mozilla/file_disable_animations_api_compositing.html
   mozilla/file_disable_animations_api_get_animations.html
--- a/dom/animation/test/mozilla/test_distance_of_transform.html
+++ b/dom/animation/test/mozilla/test_distance_of_transform.html
@@ -334,10 +334,71 @@ test(function(t) {
                          'translate(100px) skew(1rad)',
                          'translate(1000px) rotate3d(0, 1, 0, -2rad)');
   assert_approx_equals(dist,
                        Math.sqrt(900 * 900 + 1 * 1 + 2 * 2),
                        EPSILON,
                        'distance of transform lists');
 }, 'Test distance of mismatched transform lists with skew function');
 
+
+// Individual transforms
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'translate', '50px', 'none');
+  assert_equals(dist, Math.sqrt(50 * 50), 'distance of 2D translate and none');
+}, 'Test distance of 2D translate property with none');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'translate', '10px 30px', '50px');
+  assert_equals(dist, Math.sqrt(40 * 40 + 30 * 30), 'distance of 2D translate');
+}, 'Test distance of 2D translate property');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'translate', '10px 30px 50px', '50px');
+  assert_equals(dist, Math.sqrt(40 * 40 + 30 * 30 + 50 * 50),
+                'distance of 3D translate');
+}, 'Test distance of 3D translate property');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'scale', '2', 'none');
+  assert_equals(dist, Math.sqrt(1 + 1), 'distance of 2D scale and none');
+}, 'Test distance of 2D scale property with none');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'scale', '3', '1 1');
+  assert_equals(dist, Math.sqrt(2 * 2 + 2 * 2), 'distance of 2D scale');
+}, 'Test distance of 2D scale property');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'scale', '3 2 2', '1 1');
+  assert_equals(dist, Math.sqrt(2 * 2 + 1 * 1 + 1 * 1),
+                'distance of 3D scale');
+}, 'Test distance of 3D scale property');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'rotate', '180deg', 'none');
+  assert_equals(dist, Math.PI, 'distance of 2D rotate and none');
+}, 'Test distance of 2D rotate property with none');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'rotate', '180deg', '90deg');
+  assert_equals(dist, Math.PI / 2.0, 'distance of 2D rotate');
+}, 'Test distance of 2D rotate property');
+
+test(function(t) {
+  var target = addDiv(t);
+  var dist = getDistance(target, 'rotate', 'z 90deg', 'x 90deg');
+  let q1 = getQuaternion([0, 0, 1], Math.PI / 2.0);
+  let q2 = getQuaternion([1, 0, 0], Math.PI / 2.0);
+  assert_approx_equals(dist, computeRotateDistance(q1, q2), EPSILON,
+                       'distance of 3D rotate');
+}, 'Test distance of 3D rotate property');
+
 </script>
 </html>
--- a/servo/components/style/values/animated/transform.rs
+++ b/servo/components/style/values/animated/transform.rs
@@ -1304,29 +1304,18 @@ impl ComputeSquaredDistance for Computed
                     fy.compute_squared_distance(&ty)? +
                     fz.compute_squared_distance(&tz)?,
                 )
             },
             (
                 &TransformOperation::Rotate3D(fx, fy, fz, fa),
                 &TransformOperation::Rotate3D(tx, ty, tz, ta),
             ) => {
-                let (fx, fy, fz, angle1) =
-                    transform::get_normalized_vector_and_angle(fx, fy, fz, fa);
-                let (tx, ty, tz, angle2) =
-                    transform::get_normalized_vector_and_angle(tx, ty, tz, ta);
-                if (fx, fy, fz) == (tx, ty, tz) {
-                    angle1.compute_squared_distance(&angle2)
-                } else {
-                    let v1 = DirectionVector::new(fx, fy, fz);
-                    let v2 = DirectionVector::new(tx, ty, tz);
-                    let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
-                    let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
-                    q1.compute_squared_distance(&q2)
-                }
+                Rotate::Rotate3D(fx, fy, fz, fa)
+                    .compute_squared_distance(&Rotate::Rotate3D(tx, ty, tz, ta))
             },
             (
                 &TransformOperation::RotateX(fa),
                 &TransformOperation::RotateX(ta),
             ) |
             (
                 &TransformOperation::RotateY(fa),
                 &TransformOperation::RotateY(ta),
@@ -1385,17 +1374,17 @@ impl ComputeSquaredDistance for Computed
 /// <https://drafts.csswg.org/css-transforms-2/#propdef-rotate>
 impl ComputedRotate {
     fn resolve(&self) -> (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 *self {
-            Rotate::None => unreachable!("None is handled by the caller"),
+            Rotate::None => (0., 0., 1., Angle::zero()),
             Rotate::Rotate3D(rx, ry, rz, angle) => (rx, ry, rz, angle),
             Rotate::Rotate(angle) => (0., 0., 1., angle),
         }
     }
 }
 
 impl Animate for ComputedRotate {
     #[inline]
@@ -1454,16 +1443,59 @@ impl Animate for ComputedRotate {
                 // If this is a 2D rotation, we just animate the <angle>
                 let (from, to) = (self.resolve().3, other.resolve().3);
                 Ok(Rotate::Rotate(from.animate(&to, procedure)?))
             },
         }
     }
 }
 
+impl ComputeSquaredDistance for ComputedRotate {
+    #[inline]
+    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+        match (self, other) {
+            (&Rotate::None, &Rotate::None) => Ok(SquaredDistance::from_sqrt(0.)),
+            (&Rotate::Rotate3D(_, _, _, a), &Rotate::None) |
+            (&Rotate::None, &Rotate::Rotate3D(_, _, _, a)) => {
+                a.compute_squared_distance(&Angle::zero())
+            },
+            (&Rotate::Rotate3D(_, ..), _) | (_, &Rotate::Rotate3D(_, ..)) => {
+                let (from, to) = (self.resolve(), other.resolve());
+                let (mut fx, mut fy, mut fz, angle1) =
+                    transform::get_normalized_vector_and_angle(from.0, from.1, from.2, from.3);
+                let (mut tx, mut ty, mut tz, angle2) =
+                    transform::get_normalized_vector_and_angle(to.0, to.1, to.2, to.3);
+
+                if angle1 == Angle::zero() {
+                    fx = tx;
+                    fy = ty;
+                    fz = tz;
+                } else if angle2 == Angle::zero() {
+                    tx = fx;
+                    ty = fy;
+                    tz = fz;
+                }
+
+                if (fx, fy, fz) == (tx, ty, tz) {
+                    angle1.compute_squared_distance(&angle2)
+                } else {
+                    let v1 = DirectionVector::new(fx, fy, fz);
+                    let v2 = DirectionVector::new(tx, ty, tz);
+                    let q1 = Quaternion::from_direction_and_angle(&v1, angle1.radians64());
+                    let q2 = Quaternion::from_direction_and_angle(&v2, angle2.radians64());
+                    q1.compute_squared_distance(&q2)
+                }
+            },
+            (&Rotate::Rotate(_), _) | (_, &Rotate::Rotate(_)) => {
+                self.resolve().3.compute_squared_distance(&other.resolve().3)
+            },
+        }
+    }
+}
+
 /// <https://drafts.csswg.org/css-transforms-2/#propdef-translate>
 impl ComputedTranslate {
     fn resolve(&self) -> (LengthOrPercentage, LengthOrPercentage, Length) {
         // According to the spec:
         // https://drafts.csswg.org/css-transforms-2/#individual-transforms
         //
         // Unspecified translations default to 0px
         match *self {
@@ -1495,16 +1527,28 @@ impl Animate for ComputedTranslate {
                 let (from, to) = (self.resolve(), other.resolve());
                 Ok(Translate::Translate(from.0.animate(&to.0, procedure)?,
                                         from.1.animate(&to.1, procedure)?))
             },
         }
     }
 }
 
+impl ComputeSquaredDistance for ComputedTranslate {
+    #[inline]
+    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+        let (from, to) = (self.resolve(), other.resolve());
+        Ok(
+            from.0.compute_squared_distance(&to.0)? +
+            from.1.compute_squared_distance(&to.1)? +
+            from.2.compute_squared_distance(&to.2)?
+        )
+    }
+}
+
 /// <https://drafts.csswg.org/css-transforms-2/#propdef-scale>
 impl ComputedScale {
     fn resolve(&self) -> (Number, Number, Number) {
         // According to the spec:
         // https://drafts.csswg.org/css-transforms-2/#individual-transforms
         //
         // Unspecified scales default to 1
         match *self {
@@ -1549,8 +1593,20 @@ impl Animate for ComputedScale {
                 Ok(Scale::Scale(
                     animate_multiplicative_factor(from.0, to.0, procedure)?,
                     animate_multiplicative_factor(from.1, to.1, procedure)?,
                 ))
             },
         }
     }
 }
+
+impl ComputeSquaredDistance for ComputedScale {
+    #[inline]
+    fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
+        let (from, to) = (self.resolve(), other.resolve());
+        Ok(
+            from.0.compute_squared_distance(&to.0)? +
+            from.1.compute_squared_distance(&to.1)? +
+            from.2.compute_squared_distance(&to.2)?
+        )
+    }
+}
--- a/servo/components/style/values/generics/transform.rs
+++ b/servo/components/style/values/generics/transform.rs
@@ -525,17 +525,16 @@ pub fn get_normalized_vector_and_angle<T
     } else {
         let vector = vector.robust_normalize();
         (vector.x, vector.y, vector.z, angle)
     }
 }
 
 #[derive(
     Clone,
-    ComputeSquaredDistance,
     Copy,
     Debug,
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedZero,
     ToComputedValue,
 )]
@@ -595,17 +594,16 @@ where
                 angle.to_css(dest)
             },
         }
     }
 }
 
 #[derive(
     Clone,
-    ComputeSquaredDistance,
     Copy,
     Debug,
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedZero,
     ToComputedValue,
 )]
@@ -644,17 +642,16 @@ impl<Number: ToCss + PartialEq> ToCss fo
                 z.to_css(dest)
             },
         }
     }
 }
 
 #[derive(
     Clone,
-    ComputeSquaredDistance,
     Debug,
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedZero,
     ToComputedValue,
 )]
 /// A value of the `Translate` property