GraphicsLayer visible rect computation needs to use the current animating transform
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Oct 2012 18:20:31 +0000 (18:20 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 17 Oct 2012 18:20:31 +0000 (18:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=99529

Reviewed by Dean Jackson.

Source/WebCore:

If we're running an accelerated animation of transform
on a GraphicsLayerCA, the current value of the transform won't
be reflected in the GraphicsLayer's m_transform. However,
we need the current value of the transform in order to correctly
compute the visible rect of this layer and descendants.

Add a function to GraphicsLayerClient to retrieve the current
value of the transform from the client.

RenderLayer's currentTransform() used to return a transform
with transform-origin baked in; GraphicsLayerClient needs one
that excludes transform-origin, so enhance RenderLayer::currentTransform()
to be able to produce either.

Tests: compositing/visible-rect/animated-from-none.html
       compositing/visible-rect/animated.html

* platform/graphics/GraphicsLayerClient.h:
(WebCore):
(GraphicsLayerClient):
(WebCore::GraphicsLayerClient::getCurrentTransform):
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::computeVisibleRect):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::currentTransform):
* rendering/RenderLayer.h:
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::currentTransform):
* rendering/RenderLayerBacking.h:
(RenderLayerBacking):

LayoutTests:

Tests that exercise visible-rect computation on an animating layer.

* compositing/visible-rect/animated-expected.txt: Added.
* compositing/visible-rect/animated-from-none-expected.txt: Added.
* compositing/visible-rect/animated-from-none.html: Added.
* compositing/visible-rect/animated.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@131626 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/compositing/visible-rect/animated-expected.txt [new file with mode: 0644]
LayoutTests/compositing/visible-rect/animated-from-none-expected.txt [new file with mode: 0644]
LayoutTests/compositing/visible-rect/animated-from-none.html [new file with mode: 0644]
LayoutTests/compositing/visible-rect/animated.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/GraphicsLayerClient.h
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h
Source/WebCore/rendering/RenderLayerBacking.cpp
Source/WebCore/rendering/RenderLayerBacking.h

index 789dd6d..5cb5cbb 100644 (file)
@@ -1,3 +1,17 @@
+2012-10-17  Simon Fraser  <simon.fraser@apple.com>
+
+        GraphicsLayer visible rect computation needs to use the current animating transform
+        https://bugs.webkit.org/show_bug.cgi?id=99529
+
+        Reviewed by Dean Jackson.
+
+        Tests that exercise visible-rect computation on an animating layer.
+
+        * compositing/visible-rect/animated-expected.txt: Added.
+        * compositing/visible-rect/animated-from-none-expected.txt: Added.
+        * compositing/visible-rect/animated-from-none.html: Added.
+        * compositing/visible-rect/animated.html: Added.
+
 2012-10-17  Sadrul Habib Chowdhury  <sadrul@chromium.org>
 
         plugins: Allow a plugin to dictate whether it can receive drag events or not.
diff --git a/LayoutTests/compositing/visible-rect/animated-expected.txt b/LayoutTests/compositing/visible-rect/animated-expected.txt
new file mode 100644 (file)
index 0000000..522beba
--- /dev/null
@@ -0,0 +1,33 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (visible rect 0.00, 0.00 800.00 x 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (visible rect 0.00, 0.00 800.00 x 600.00)
+      (children 1
+        (GraphicsLayer
+          (position 8.00 8.00)
+          (bounds 502.00 202.00)
+          (visible rect 0.00, 0.00 502.00 x 202.00)
+          (children 1
+            (GraphicsLayer
+              (position 1.00 1.00)
+              (bounds 500.00 200.00)
+              (visible rect 0.00, 0.00 500.00 x 200.00)
+              (children 1
+                (GraphicsLayer
+                  (bounds 200.00 200.00)
+                  (drawsContent 1)
+                  (transform [1.00 0.00 0.00 0.00] [0.00 1.00 0.00 0.00] [0.00 0.00 1.00 0.00] [-100.00 0.00 0.00 1.00])
+                  (visible rect 100.00, 0.00 100.00 x 200.00)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/visible-rect/animated-from-none-expected.txt b/LayoutTests/compositing/visible-rect/animated-from-none-expected.txt
new file mode 100644 (file)
index 0000000..bb42157
--- /dev/null
@@ -0,0 +1,33 @@
+(GraphicsLayer
+  (bounds 800.00 600.00)
+  (visible rect 0.00, 0.00 800.00 x 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (visible rect 0.00, 0.00 800.00 x 600.00)
+      (children 1
+        (GraphicsLayer
+          (position 8.00 8.00)
+          (bounds 502.00 202.00)
+          (visible rect 0.00, 0.00 502.00 x 202.00)
+          (children 1
+            (GraphicsLayer
+              (position 1.00 1.00)
+              (bounds 500.00 200.00)
+              (visible rect 0.00, 0.00 500.00 x 200.00)
+              (children 1
+                (GraphicsLayer
+                  (position -100.00 0.00)
+                  (bounds 200.00 200.00)
+                  (drawsContent 1)
+                  (visible rect 100.00, 0.00 100.00 x 200.00)
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+
diff --git a/LayoutTests/compositing/visible-rect/animated-from-none.html b/LayoutTests/compositing/visible-rect/animated-from-none.html
new file mode 100644 (file)
index 0000000..fccce78
--- /dev/null
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            position: relative;
+            height: 200px;
+            width: 500px;
+            border: 1px solid black;
+            overflow: hidden;
+            z-index: 0;
+        }
+        
+        .box {
+            position: absolute;
+            left: -100px;
+            width: 200px;
+            height: 200px;
+            background-color: blue;
+            -webkit-animation: move 20000000s linear;
+        }
+        
+        @-webkit-keyframes move {
+            from { -webkit-transform: none; }
+            to   { -webkit-transform: translateX(400px); }
+        }
+    </style>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function doTest()
+        {
+            document.getElementById('animated').addEventListener('webkitAnimationStart', function() {
+                if (window.internals)
+                    document.getElementById('layers').innerText = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_VISIBLE_RECTS)
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, false);
+        }
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+
+    <div class="container">
+        <div id="animated" class="box"></div>
+    </div>
+
+<pre id="layers">Layer tree goes here when testing</pre>
+</body>
+</html>
diff --git a/LayoutTests/compositing/visible-rect/animated.html b/LayoutTests/compositing/visible-rect/animated.html
new file mode 100644 (file)
index 0000000..bfbe32b
--- /dev/null
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+    <style>
+        .container {
+            position: relative;
+            height: 200px;
+            width: 500px;
+            border: 1px solid black;
+            overflow: hidden;
+            z-index: 0;
+        }
+        
+        .box {
+            position: absolute;
+            width: 200px;
+            height: 200px;
+            background-color: blue;
+            -webkit-animation: move 20000000s linear;
+        }
+        
+        @-webkit-keyframes move {
+            from { -webkit-transform: translateX(-100px); }
+            to   { -webkit-transform: translateX(300px); }
+        }
+    </style>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function doTest()
+        {
+            document.getElementById('animated').addEventListener('webkitAnimationStart', function() {
+                if (window.internals)
+                    document.getElementById('layers').innerText = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_VISIBLE_RECTS)
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, false);
+        }
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+
+    <div class="container">
+        <div id="animated" class="box"></div>
+    </div>
+
+<pre id="layers">Layer tree goes here when testing</pre>
+</body>
+</html>
index 561d96f..2e20b7b 100644 (file)
@@ -1,3 +1,41 @@
+2012-10-17  Simon Fraser  <simon.fraser@apple.com>
+
+        GraphicsLayer visible rect computation needs to use the current animating transform
+        https://bugs.webkit.org/show_bug.cgi?id=99529
+
+        Reviewed by Dean Jackson.
+
+        If we're running an accelerated animation of transform
+        on a GraphicsLayerCA, the current value of the transform won't
+        be reflected in the GraphicsLayer's m_transform. However,
+        we need the current value of the transform in order to correctly
+        compute the visible rect of this layer and descendants.
+        
+        Add a function to GraphicsLayerClient to retrieve the current
+        value of the transform from the client.
+        
+        RenderLayer's currentTransform() used to return a transform
+        with transform-origin baked in; GraphicsLayerClient needs one
+        that excludes transform-origin, so enhance RenderLayer::currentTransform()
+        to be able to produce either.
+
+        Tests: compositing/visible-rect/animated-from-none.html
+               compositing/visible-rect/animated.html
+
+        * platform/graphics/GraphicsLayerClient.h:
+        (WebCore):
+        (GraphicsLayerClient):
+        (WebCore::GraphicsLayerClient::getCurrentTransform):
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::computeVisibleRect):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::currentTransform):
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::currentTransform):
+        * rendering/RenderLayerBacking.h:
+        (RenderLayerBacking):
+
 2012-10-17  Sadrul Habib Chowdhury  <sadrul@chromium.org>
 
         plugins: Allow a plugin to dictate whether it can receive drag events or not.
index 7efee0e..df19abc 100644 (file)
 
 namespace WebCore {
 
+class FloatPoint;
 class GraphicsContext;
 class GraphicsLayer;
 class IntPoint;
 class IntRect;
-class FloatPoint;
+class TransformationMatrix;
 
 enum GraphicsLayerPaintingPhaseFlags {
     GraphicsLayerPaintBackground = (1 << 0),
@@ -69,6 +70,10 @@ public:
     virtual void paintContents(const GraphicsLayer*, GraphicsContext&, GraphicsLayerPaintingPhase, const IntRect& inClip) = 0;
     virtual void didCommitChangesForLayer(const GraphicsLayer*) const { }
 
+    // Provides current transform (taking transform-origin and animations into account). Input matrix has been
+    // initialized to identity already. Returns false if the layer has no transform.
+    virtual bool getCurrentTransform(const GraphicsLayer*, TransformationMatrix&) const { return false; }
+
     // Multiplier for backing store size, related to high DPI.
     virtual float deviceScaleFactor() const { return 1; }
     // Page scale factor.
index 3ec8343..0784800 100644 (file)
@@ -921,12 +921,13 @@ void GraphicsLayerCA::computeVisibleRect(TransformState& state)
 
     TransformationMatrix layerTransform;
     layerTransform.translate(m_position.x(), m_position.y());
-    
-    if (!transform().isIdentity()) {
+
+    TransformationMatrix currentTransform;
+    if (client() && client()->getCurrentTransform(this, currentTransform) && !currentTransform.isIdentity()) {
         FloatPoint3D absoluteAnchorPoint(anchorPoint());
         absoluteAnchorPoint.scale(size().width(), size().height(), 1);
         layerTransform.translate3d(absoluteAnchorPoint.x(), absoluteAnchorPoint.y(), absoluteAnchorPoint.z());
-        layerTransform.multiply(transform());
+        layerTransform.multiply(currentTransform);
         layerTransform.translate3d(-absoluteAnchorPoint.x(), -absoluteAnchorPoint.y(), -absoluteAnchorPoint.z());
     }
 
index c850a2f..0a9cf91 100644 (file)
@@ -597,7 +597,7 @@ void RenderLayer::updateTransform()
         dirty3DTransformedDescendantStatus();
 }
 
-TransformationMatrix RenderLayer::currentTransform() const
+TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOrigin applyOrigin) const
 {
     if (!m_transform)
         return TransformationMatrix();
@@ -606,7 +606,16 @@ TransformationMatrix RenderLayer::currentTransform() const
     if (renderer()->style()->isRunningAcceleratedAnimation()) {
         TransformationMatrix currTransform;
         RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer());
-        style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
+        style->applyTransform(currTransform, renderBox()->pixelSnappedBorderBoxRect().size(), applyOrigin);
+        makeMatrixRenderable(currTransform, canRender3DTransforms());
+        return currTransform;
+    }
+
+    // m_transform includes transform-origin, so we need to recompute the transform here.
+    if (applyOrigin == RenderStyle::ExcludeTransformOrigin) {
+        RenderBox* box = renderBox();
+        TransformationMatrix currTransform;
+        box->style()->applyTransform(currTransform, box->pixelSnappedBorderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
         makeMatrixRenderable(currTransform, canRender3DTransforms());
         return currTransform;
     }
index c3db96d..1811036 100644 (file)
@@ -595,7 +595,7 @@ public:
     // currentTransform computes a transform which takes accelerated animations into account. The
     // resulting transform has transform-origin baked in. If the layer does not have a transform,
     // returns the identity matrix.
-    TransformationMatrix currentTransform() const;
+    TransformationMatrix currentTransform(RenderStyle::ApplyTransformOrigin = RenderStyle::IncludeTransformOrigin) const;
     TransformationMatrix renderableTransform(PaintBehavior) const;
     
     // Get the perspective transform, which is applied to transformed sublayers.
index 1ef75e7..132de87 100644 (file)
@@ -1539,6 +1539,18 @@ void RenderLayerBacking::didCommitChangesForLayer(const GraphicsLayer*) const
     compositor()->didFlushChangesForLayer(m_owningLayer);
 }
 
+bool RenderLayerBacking::getCurrentTransform(const GraphicsLayer* graphicsLayer, TransformationMatrix& transform) const
+{
+    if (graphicsLayer != m_graphicsLayer)
+        return false;
+
+    if (m_owningLayer->hasTransform()) {
+        transform = m_owningLayer->currentTransform(RenderStyle::ExcludeTransformOrigin);
+        return true;
+    }
+    return false;
+}
+
 bool RenderLayerBacking::showDebugBorders(const GraphicsLayer*) const
 {
     return compositor() ? compositor()->compositorShowDebugBorders() : false;
index c041465..c040ae4 100644 (file)
@@ -148,6 +148,7 @@ public:
     virtual float deviceScaleFactor() const;
     virtual float pageScaleFactor() const;
     virtual void didCommitChangesForLayer(const GraphicsLayer*) const;
+    virtual bool getCurrentTransform(const GraphicsLayer*, TransformationMatrix&) const;
 
     virtual bool showDebugBorders(const GraphicsLayer*) const;
     virtual bool showRepaintCounter(const GraphicsLayer*) const;