[cc] Apply sublayer transform about anchor instead of about layer center.

There are some cases where WebCore internally needs to "reposition" the origin
point about which CSS transforms are applied. For example, when a perspective
container becomes composited, the composited location/bounds may change
depending on the positioning of its children. The perspective-origin from the
original DOM tree should not change, but internally it does require a new
origin to be given to the compositor. It turns out that WebCore uses the anchor
point layer property to communicate these cases. So, the compositor needs to
apply the sublayer transform about the anchor point instead of about the layer
center.

BUG=157961


Review URL: https://chromiumcodereview.appspot.com/12224113

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@181957 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/cc/layer_tree_host_common.cc b/cc/layer_tree_host_common.cc
index e316c37..4d3377a 100644
--- a/cc/layer_tree_host_common.cc
+++ b/cc/layer_tree_host_common.cc
@@ -169,6 +169,7 @@
 
 static inline bool transformToParentIsKnown(Layer* layer)
 {
+
     return !layer->transformIsAnimating();
 }
 
@@ -570,15 +571,12 @@
     //        Tr[origin2anchor] is the translation from the layer's origin to its anchor point
     //        Tr[origin2center] is the translation from the layer's origin to its center
     //        M[layer] is the layer's matrix (applied at the anchor point)
-    //        M[sublayer] is the layer's sublayer transform (applied at the layer's center)
+    //        M[sublayer] is the layer's sublayer transform (also applied at the layer's anchor point)
     //        S[layer2content] is the ratio of a layer's contentBounds() to its bounds().
     //
     //    Some composite transforms can help in understanding the sequence of transforms:
     //        compositeLayerTransform = Tr[origin2anchor] * M[layer] * Tr[origin2anchor].inverse()
-    //        compositeSublayerTransform = Tr[origin2center] * M[sublayer] * Tr[origin2center].inverse()
-    //
-    //    In words, the layer transform is applied about the anchor point, and the sublayer transform is
-    //    applied about the center of the layer.
+    //        compositeSublayerTransform = Tr[origin2anchor] * M[sublayer] * Tr[origin2anchor].inverse()
     //
     // 4. When a layer (or render surface) is drawn, it is drawn into a "target render surface". Therefore the draw
     //    transform does not necessarily transform from screen space to local layer space. Instead, the draw transform
@@ -754,7 +752,7 @@
         layerDrawProperties.target_space_transform.Scale(renderSurfaceSublayerScale.x() / layer->contentsScaleX(), renderSurfaceSublayerScale.y() / layer->contentsScaleY());
 
         // Inside the surface's subtree, we scale everything to the owning layer's scale.
-        // The sublayer matrix transforms centered layer rects into target
+        // The sublayer matrix transforms layer rects into target
         // surface content space.
         DCHECK(sublayerMatrix.IsIdentity());
         sublayerMatrix.Scale(renderSurfaceSublayerScale.x(), renderSurfaceSublayerScale.y());
@@ -867,11 +865,11 @@
     if (!layer->preserves3D())
         sublayerMatrix.FlattenTo2d();
 
-    // Apply the sublayer transform at the center of the layer.
+    // Apply the sublayer transform at the anchor point of the layer.
     if (!layer->sublayerTransform().IsIdentity()) {
-        sublayerMatrix.Translate(0.5 * bounds.width(), 0.5 * bounds.height());
+        sublayerMatrix.Translate(layer->anchorPoint().x() * bounds.width(), layer->anchorPoint().y() * bounds.height());
         sublayerMatrix.PreconcatTransform(layer->sublayerTransform());
-        sublayerMatrix.Translate(-0.5 * bounds.width(), -0.5 * bounds.height());
+        sublayerMatrix.Translate(-layer->anchorPoint().x() * bounds.width(), -layer->anchorPoint().y() * bounds.height());
     }
 
     LayerList& descendants = (layer->renderSurface() ? layer->renderSurface()->layerList() : layerList);
diff --git a/cc/layer_tree_host_common_unittest.cc b/cc/layer_tree_host_common_unittest.cc
index 0b35c52..37249714 100644
--- a/cc/layer_tree_host_common_unittest.cc
+++ b/cc/layer_tree_host_common_unittest.cc
@@ -313,11 +313,9 @@
     //         But then, the child also does not preserve3D. When it gives its hierarchy to the grandChild, it should be flattened to 2D.
     gfx::Transform parentSublayerMatrix;
     parentSublayerMatrix.Scale3d(10, 10, 3.3);
-    gfx::Transform parentTranslationToCenter;
-    parentTranslationToCenter.Translate(5, 6);
-    // Sublayer matrix is applied to the center of the parent layer.
+    // Sublayer matrix is applied to the anchor point of the parent layer.
     parentCompositeTransform = parentTranslationToAnchor * parentLayerTransform * inverse(parentTranslationToAnchor)
-            * parentTranslationToCenter * parentSublayerMatrix * inverse(parentTranslationToCenter);
+            * parentTranslationToAnchor * parentSublayerMatrix * inverse(parentTranslationToAnchor);
     gfx::Transform flattenedCompositeTransform = parentCompositeTransform;
     flattenedCompositeTransform.FlattenTo2d();
     setLayerPropertiesForTesting(parent.get(), parentLayerTransform, parentSublayerMatrix, gfx::PointF(0.25, 0.25), gfx::PointF(0, 0), gfx::Size(10, 12), false);
@@ -366,10 +364,8 @@
     gfx::Transform parentSublayerMatrix;
     parentSublayerMatrix.Scale3d(0.9, 1, 3.3);
 
-    gfx::Transform parentTranslationToCenter;
-    parentTranslationToCenter.Translate(50, 60);
     gfx::Transform parentCompositeTransform = parentTranslationToAnchor * parentLayerTransform * inverse(parentTranslationToAnchor)
-            * parentTranslationToCenter * parentSublayerMatrix * inverse(parentTranslationToCenter);
+            * parentTranslationToAnchor * parentSublayerMatrix * inverse(parentTranslationToAnchor);
     gfx::Vector2dF parentCompositeScale = MathUtil::computeTransform2dScaleComponents(parentCompositeTransform, 1.0f);
     gfx::Transform surfaceSublayerTransform;
     surfaceSublayerTransform.Scale(parentCompositeScale.x(), parentCompositeScale.y());
@@ -400,6 +396,35 @@
     EXPECT_TRANSFORMATION_MATRIX_EQ(surfaceSublayerCompositeTransform, child->renderTarget()->renderSurface()->screenSpaceTransform());
 }
 
+TEST(LayerTreeHostCommonTest, verifySublayerTransformWithAnchorPoint)
+{
+    // crbug.com/157961 - we were always applying the sublayer transform about
+    // the center of the layer, rather than the anchor point.
+
+    scoped_refptr<Layer> root = Layer::create();
+    scoped_refptr<Layer> parent = Layer::create();
+    scoped_refptr<LayerWithForcedDrawsContent> child = make_scoped_refptr(new LayerWithForcedDrawsContent());
+    root->addChild(parent);
+    parent->addChild(child);
+
+    gfx::Transform identityMatrix;
+    gfx::Transform parentSublayerMatrix;
+    parentSublayerMatrix.ApplyPerspectiveDepth(2.0);
+    gfx::PointF parentAnchorPoint(0.2f, 0.8f);
+
+    setLayerPropertiesForTesting(root.get(), identityMatrix, identityMatrix, gfx::PointF(0, 0), gfx::PointF(0, 0), gfx::Size(1, 2), false);
+    setLayerPropertiesForTesting(parent.get(), identityMatrix, parentSublayerMatrix, parentAnchorPoint, gfx::PointF(0, 0), gfx::Size(100, 100), false);
+    setLayerPropertiesForTesting(child.get(), identityMatrix, identityMatrix, gfx::PointF(0, 0), gfx::PointF(0, 0), gfx::Size(10, 10), false);
+    executeCalculateDrawProperties(root.get());
+
+    gfx::Transform expectedChildDrawTransform;
+    expectedChildDrawTransform.Translate(20, 80);
+    expectedChildDrawTransform.ApplyPerspectiveDepth(2.0);
+    expectedChildDrawTransform.Translate(-20, -80);
+    EXPECT_TRANSFORMATION_MATRIX_EQ(expectedChildDrawTransform, child->drawTransform());
+}
+
+
 TEST(LayerTreeHostCommonTest, verifySeparateRenderTargetRequirementWithClipping)
 {
     scoped_refptr<Layer> root = Layer::create();
@@ -510,12 +535,8 @@
     parentTranslationToAnchor.Translate(2.5, 3);
     gfx::Transform parentSublayerMatrix;
     parentSublayerMatrix.Scale3d(10, 10, 3.3);
-    gfx::Transform parentTranslationToCenter;
-    parentTranslationToCenter.Translate(5, 6);
     gfx::Transform parentCompositeTransform = parentTranslationToAnchor * parentLayerTransform * inverse(parentTranslationToAnchor)
-            * parentTranslationToCenter * parentSublayerMatrix * inverse(parentTranslationToCenter);
-    gfx::Transform childTranslationToCenter;
-    childTranslationToCenter.Translate(8, 9);
+            * parentTranslationToAnchor * parentSublayerMatrix * inverse(parentTranslationToAnchor);
     gfx::Transform replicaLayerTransform;
     replicaLayerTransform.Scale3d(3, 3, 1);
     gfx::Vector2dF parentCompositeScale = MathUtil::computeTransform2dScaleComponents(parentCompositeTransform, 1.f);
@@ -590,8 +611,6 @@
     // y component has a translation by 1 for every ancestor, which indicates the "depth" of the layer in the hierarchy.
     gfx::Transform translationToAnchor;
     translationToAnchor.Translate(2.5, 0);
-    gfx::Transform translationToCenter;
-    translationToCenter.Translate(5, 5);
     gfx::Transform layerTransform;
     layerTransform.Translate(1, 1);
     gfx::Transform sublayerTransform;
@@ -600,7 +619,7 @@
     replicaLayerTransform.Scale3d(-2, 5, 1);
 
     gfx::Transform A = translationToAnchor * layerTransform * inverse(translationToAnchor);
-    gfx::Transform B = translationToCenter * sublayerTransform * inverse(translationToCenter);
+    gfx::Transform B = translationToAnchor * sublayerTransform * inverse(translationToAnchor);
     gfx::Transform R = A * translationToAnchor * replicaLayerTransform * inverse(translationToAnchor);
 
     gfx::Vector2dF surface1ParentTransformScale = MathUtil::computeTransform2dScaleComponents(A * B, 1.f);