Bug 1272549 - Part 8: Compute distance for perspective transform function. draft
authorBoris Chiou <boris.chiou@gmail.com>
Mon, 03 Oct 2016 16:04:24 +0800
changeset 428941 610a8e4554455823375c4e893e163d2b54c53431
parent 428940 4013ed01cad58173207381455e3019312dcc92de
child 428942 dd78d20f7abbb7f7fe0fe4d4b76101c615a883b3
push id33433
push userbmo:boris.chiou@gmail.com
push dateMon, 24 Oct 2016 19:01:16 +0000
bugs1272549
milestone52.0a1
Bug 1272549 - Part 8: Compute distance for perspective transform function. MozReview-Commit-ID: IUL9RYuP82r
layout/style/StyleAnimationValue.cpp
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -934,20 +934,47 @@ ComputeTransformDistance(nsCSSValue::Arr
         // cos(theta/2) = (q1 dot q2) / (|q1| * |q2|) = q1 dot q2.
         gfxQuaternion q1(vector1, a1->Item(4).GetAngleValueInRadians());
         gfxQuaternion q2(vector2, a2->Item(4).GetAngleValueInRadians());
         distance = 2.0 * acos(clamped(q1.DotProduct(q2), -1.0, 1.0));
         distance = distance * distance;
       }
       break;
     }
-    case eCSSKeyword_perspective:
-      // TODO: This will be fixed in the later patch.
-      distance = 0.0;
+    case eCSSKeyword_perspective: {
+      MOZ_ASSERT(a1->Count() == 2, "unexpected count");
+      MOZ_ASSERT(a2->Count() == 2, "unexpected count");
+
+      // We convert a perspective function into an equivalent matrix3d, and
+      // then do matrix decomposition to get the distance.
+      // Why don't we just subtract one perspective depth from the other?
+      // I think it's better to follow the logic of our interpolation,
+      // which does linear interpolation between two decomposed perspective
+      // vectors.
+      // e.g.
+      // Do interpolation between perspective(100px) and perspective(1000px).
+      //   1) Convert them into matrix3d, and then do matrix decomposition:
+      //      perspective vector 1: perspective(0, 0, -1/100, 1);
+      //      perspective vector 2: perspective(0, 0, -1/1000, 1);
+      //   2) Do linear interpolation between these two vectors.
+      // Therefore, we use the same rule to get the distance as what we do for
+      // matrix3d.
+
+      auto clampPerspectiveDepth = [](float aDepth) {
+        // Perspective depth should be positive non-zero value.
+        return std::max(aDepth, std::numeric_limits<float>::epsilon());
+      };
+      Matrix4x4 m1;
+      m1.Perspective(clampPerspectiveDepth(a1->Item(1).GetFloatValue()));
+      Matrix4x4 m2;
+      m2.Perspective(clampPerspectiveDepth(a2->Item(1).GetFloatValue()));
+
+      distance = ComputeTransform3DMatrixDistance(m1, m2);
       break;
+    }
     case eCSSKeyword_matrix: {
       MOZ_ASSERT(a1->Count() == 7, "unexpected count");
       MOZ_ASSERT(a2->Count() == 7, "unexpected count");
 
       distance = ComputeTransform2DMatrixDistance(
         nsStyleTransformMatrix::CSSValueArrayTo2DMatrix(a1),
         nsStyleTransformMatrix::CSSValueArrayTo2DMatrix(a2));
       break;