Bug 1394284 - add fallback discrete procedure for transform animation. r=boris,hiro
authorJeremy Chen <jeremychen@mozilla.com>
Wed, 13 Sep 2017 17:39:07 +0800
changeset 431697 9044841344c9af963ed30293d8c5ecea0ee23845
parent 431696 e8fabb53ad00dbc94ad2f77d3d58dbe04ca34f22
child 431698 2d942fb27e398ba373cab9bccf7e5bc867615ec0
push id7785
push userryanvm@gmail.com
push dateThu, 21 Sep 2017 13:39:55 +0000
treeherdermozilla-beta@06d4034a8a03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersboris, hiro
bugs1394284
milestone57.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 1394284 - add fallback discrete procedure for transform animation. r=boris,hiro According to the spec, if one of the matrices for transform interpolation is non-invertible, the used animation function must fall-back to a discrete animation. However, in the current implementation, we always use an identity matrix as a fallback for the non-invertible matrix. Decompose2DMatrix and Decompose3DMatrix both return a boolean, but we just never use it. So, in this patch, we use the returned boolean from the matrix decomposition as a condition, and do the fallback discrete procedure for the non-invertible matrices case. MozReview-Commit-ID: E7i1a1MJOXN
layout/style/nsStyleTransformMatrix.cpp
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -321,16 +321,23 @@ public:
 
     gfxQuaternion result = gfxQuaternion(scale * aTwo.x,
                                          scale * aTwo.y,
                                          scale * aTwo.z,
                                          cos(theta)) * aOne;
     return result.ToMatrix();
   }
 
+  static Matrix4x4 operateForFallback(const Matrix4x4& aMatrix1,
+                                      const Matrix4x4& aMatrix2,
+                                      double aProgress)
+  {
+    return aMatrix1;
+  }
+
   static Matrix4x4 operateByServo(const Matrix4x4& aMatrix1,
                                   const Matrix4x4& aMatrix2,
                                   double aCount)
   {
     Matrix4x4 result;
     Servo_MatrixTransform_Operate(MatrixTransformOperator::Accumulate,
                                   &aMatrix1.components,
                                   &aMatrix2.components,
@@ -364,16 +371,23 @@ public:
 
   static Matrix4x4 operateForRotate(const gfxQuaternion& aOne,
                                     const gfxQuaternion& aTwo,
                                     double aCoeff)
   {
     return aOne.Slerp(aTwo, aCoeff).ToMatrix();
   }
 
+  static Matrix4x4 operateForFallback(const Matrix4x4& aMatrix1,
+                                      const Matrix4x4& aMatrix2,
+                                      double aProgress)
+  {
+    return aProgress < 0.5 ? aMatrix1 : aMatrix2;
+  }
+
   static Matrix4x4 operateByServo(const Matrix4x4& aMatrix1,
                                   const Matrix4x4& aMatrix2,
                                   double aProgress)
   {
     Matrix4x4 result;
     Servo_MatrixTransform_Operate(MatrixTransformOperator::Interpolate,
                                   &aMatrix1.components,
                                   &aMatrix2.components,
@@ -393,36 +407,44 @@ public:
 template <typename Operator>
 static Matrix4x4
 OperateTransformMatrix(const Matrix4x4 &aMatrix1,
                        const Matrix4x4 &aMatrix2,
                        double aProgress)
 {
   // Decompose both matrices
 
-  // TODO: What do we do if one of these returns false (singular matrix)
   Point3D scale1(1, 1, 1), translate1;
   Point4D perspective1(0, 0, 0, 1);
   gfxQuaternion rotate1;
   nsStyleTransformMatrix::ShearArray shear1{0.0f, 0.0f, 0.0f};
 
   Point3D scale2(1, 1, 1), translate2;
   Point4D perspective2(0, 0, 0, 1);
   gfxQuaternion rotate2;
   nsStyleTransformMatrix::ShearArray shear2{0.0f, 0.0f, 0.0f};
 
+  // Check if both matrices are decomposable.
+  bool wasDecomposed;
   Matrix matrix2d1, matrix2d2;
   if (aMatrix1.Is2D(&matrix2d1) && aMatrix2.Is2D(&matrix2d2)) {
-    Decompose2DMatrix(matrix2d1, scale1, shear1, rotate1, translate1);
-    Decompose2DMatrix(matrix2d2, scale2, shear2, rotate2, translate2);
+    wasDecomposed =
+      Decompose2DMatrix(matrix2d1, scale1, shear1, rotate1, translate1) &&
+      Decompose2DMatrix(matrix2d2, scale2, shear2, rotate2, translate2);
   } else {
-    Decompose3DMatrix(aMatrix1, scale1, shear1,
-                      rotate1, translate1, perspective1);
-    Decompose3DMatrix(aMatrix2, scale2, shear2,
-                      rotate2, translate2, perspective2);
+    wasDecomposed =
+      Decompose3DMatrix(aMatrix1, scale1, shear1,
+                        rotate1, translate1, perspective1) &&
+      Decompose3DMatrix(aMatrix2, scale2, shear2,
+                        rotate2, translate2, perspective2);
+  }
+
+  // Fallback to discrete operation if one of the matrices is not decomposable.
+  if (!wasDecomposed) {
+    return Operator::operateForFallback(aMatrix1, aMatrix2, aProgress);
   }
 
   Matrix4x4 result;
 
   // Operate each of the pieces in response to |Operator|.
   Point4D perspective =
     Operator::operateForPerspective(perspective1, perspective2, aProgress);
   result.SetTransposedVector(3, perspective);