Title: [290628] trunk
Revision
290628
Author
[email protected]
Date
2022-02-28 20:54:13 -0800 (Mon, 28 Feb 2022)

Log Message

Compositing/paint invalidation with transforms
https://bugs.webkit.org/show_bug.cgi?id=233421
<rdar://problem/85814854>

Reviewed by Alan Bujtas.

Source/WebCore:

When changing transform from something like `translate(0)` to `translate3d(0, 0, 0)
scale(0.5, 0.5)`, we trigger compositing, and thus need to repaint the previous rect of the
layer in its old repaint container. However, the existing code would take the new transform
into account when computing that rect, thus dirtying a rect that is too small.

To fix this, we need to use the cached repaint rects on RenderLayer for this repaint.
However, doing so revealed a bug (via
compositing/shared-backing/repaint-into-shared-backing.html) in how we compute repaint
cached repaint rects in the presence of shared backing. During a compositing update, if a
layer's composited state changed, we'd call computeRepaintRectsIncludingDescendants(), which
computes rect relative to the layer's repaint container. But at this time, the state of
backing sharing in BackingSharingState is in flux (we essentially don't know yet if a layer
can use shared backing). So we may compute and cache repaint rects relative to the wrong
container.

To fix this, leverage the existing m_layersPendingRepaint logic, and delay computing the
repaint rects until we've established our final backing sharing configuration.

Tests: compositing/repaint/composite-and-scale-change.html
       compositing/shared-backing/repaint-into-shared-backing-become-composited.html

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::setBackingProviderLayer):
(WebCore::RenderLayer::calculateClipRects const):
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::BackingSharingState::issuePendingRepaints):
(WebCore::RenderLayerCompositor::updateBacking):

LayoutTests:

* compositing/repaint/composite-and-scale-change-expected.txt: Added.
* compositing/repaint/composite-and-scale-change.html: Added.
    Test that dumps repaint rects.
* compositing/shared-backing/repaint-into-shared-backing-become-composited-expected.html: Added.
* compositing/shared-backing/repaint-into-shared-backing-become-composited.html: Added.
    Companion to repaint-into-shared-backing.html but toggles compositing in the other
    direction.
* platform/gtk/compositing/repaint/composite-and-scale-change-actual.txt: Added.
* platform/mac-wk1/compositing/repaint/composite-and-scale-change-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (290627 => 290628)


--- trunk/LayoutTests/ChangeLog	2022-03-01 03:24:36 UTC (rev 290627)
+++ trunk/LayoutTests/ChangeLog	2022-03-01 04:54:13 UTC (rev 290628)
@@ -1,5 +1,23 @@
 2022-02-28  Simon Fraser  <[email protected]>
 
+        Compositing/paint invalidation with transforms
+        https://bugs.webkit.org/show_bug.cgi?id=233421
+        <rdar://problem/85814854>
+
+        Reviewed by Alan Bujtas.
+        
+        * compositing/repaint/composite-and-scale-change-expected.txt: Added.
+        * compositing/repaint/composite-and-scale-change.html: Added.
+            Test that dumps repaint rects.
+        * compositing/shared-backing/repaint-into-shared-backing-become-composited-expected.html: Added.
+        * compositing/shared-backing/repaint-into-shared-backing-become-composited.html: Added.
+            Companion to repaint-into-shared-backing.html but toggles compositing in the other
+            direction.
+        * platform/gtk/compositing/repaint/composite-and-scale-change-actual.txt: Added.
+        * platform/mac-wk1/compositing/repaint/composite-and-scale-change-expected.txt: Added.
+
+2022-02-28  Simon Fraser  <[email protected]>
+
         No animation when scroll snap scroller is navigated with the keyboard
         https://bugs.webkit.org/show_bug.cgi?id=236244
 

Added: trunk/LayoutTests/compositing/repaint/composite-and-scale-change-expected.txt (0 => 290628)


--- trunk/LayoutTests/compositing/repaint/composite-and-scale-change-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/compositing/repaint/composite-and-scale-change-expected.txt	2022-03-01 04:54:13 UTC (rev 290628)
@@ -0,0 +1,24 @@
+(repaint rects
+  (rect 30 20 440 440)
+)
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 30.00 20.00)
+          (anchor 0.00 0.00)
+          (bounds 440.00 440.00)
+          (contentsOpaque 1)
+          (drawsContent 1)
+          (transform [0.50 0.00 0.00 0.00] [0.00 0.50 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/compositing/repaint/composite-and-scale-change.html (0 => 290628)


--- trunk/LayoutTests/compositing/repaint/composite-and-scale-change.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/repaint/composite-and-scale-change.html	2022-03-01 04:54:13 UTC (rev 290628)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+    .box {
+        position: absolute;
+        z-index: 1;
+        top: 20px;
+        left: 30px;
+        height: 400px;
+        width: 400px;
+        border: 20px solid green;
+        transform: translate(0);
+        transform-origin: top left;
+        background-color: blue;
+    }
+    
+    body.changed .box {
+        transform: translate3d(0, 0, 0) scale(0.5, 0.5);
+    }
+    </style>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        window.addEventListener('load', () => {
+            setTimeout(() => {
+                if (window.internals)
+                    window.internals.startTrackingRepaints();
+
+                document.body.classList.add('changed');
+
+                if (window.internals)
+                    document.getElementById('layers').textContent = window.internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_REPAINT_RECTS);
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, 0);
+        }, false);
+    </script>
+</head>
+<body>
+    <div class="box"></div>
+<pre id="layers"></pre>
+</body>
+</html>

Added: trunk/LayoutTests/compositing/shared-backing/repaint-into-shared-backing-become-composited-expected.html (0 => 290628)


--- trunk/LayoutTests/compositing/shared-backing/repaint-into-shared-backing-become-composited-expected.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/shared-backing/repaint-into-shared-backing-become-composited-expected.html	2022-03-01 04:54:13 UTC (rev 290628)
@@ -0,0 +1,53 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <style>
+        .container {
+            padding: 10px;
+            margin: 10px;
+            border: 2px solid black;
+            height: 400px;
+            width: 500px;
+            overflow-y: hidden;
+        }
+
+        .wrapper {
+            position: relative;
+            width: 2000px;
+            z-index: 1;
+        }
+
+        .positioned {
+            position: absolute;
+            left: 0;
+            top: 0;
+            background-color: silver;
+            z-index: 2;
+            padding: 20px;
+            width: 100%;
+            height: 250px;
+            overflow: hidden;
+        }
+
+       .inner {
+            position: relative;
+            width: 300px;
+            height: 200px;
+            background-color: green;
+            transform: translateZ(0);
+        }
+    </style>
+</head>
+<body>
+<div class="container">
+    <div class="wrapper">
+        <div class="positioned">
+            &nbsp;
+            <div class="inner">
+                &nbsp;
+            </div>
+        </div>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/compositing/shared-backing/repaint-into-shared-backing-become-composited.html (0 => 290628)


--- trunk/LayoutTests/compositing/shared-backing/repaint-into-shared-backing-become-composited.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/shared-backing/repaint-into-shared-backing-become-composited.html	2022-03-01 04:54:13 UTC (rev 290628)
@@ -0,0 +1,71 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <style>
+        .container {
+            padding: 10px;
+            margin: 10px;
+            border: 2px solid black;
+            height: 400px;
+            width: 500px;
+            overflow-y: hidden;
+        }
+
+        .wrapper {
+            position: relative;
+            width: 2000px;
+            z-index: 1;
+        }
+
+        .positioned {
+            position: absolute;
+            left: 0;
+            top: 0;
+            background-color: silver;
+            z-index: 2;
+            padding: 20px;
+            width: 100%;
+            height: 250px;
+            overflow: hidden;
+        }
+
+       .inner {
+            position: relative;
+            width: 300px;
+            height: 200px;
+            background-color: green;
+            transform: translate(0px, 0px);
+        }
+        
+        body.changed .inner {
+            transform: translateZ(0);
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        window.addEventListener('load', () => {
+            requestAnimationFrame(() => {
+                requestAnimationFrame(() => {
+                    document.body.classList.add('changed');
+                    if (window.testRunner)
+                        testRunner.notifyDone();
+                });
+            });
+        }, false);
+    </script>
+</head>
+<body>
+<div class="container">
+    <div class="wrapper">
+        <div class="positioned">
+            &nbsp;
+            <div class="inner">
+                &nbsp;
+            </div>
+        </div>
+    </div>
+</div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/platform/gtk/compositing/repaint/composite-and-scale-change-actual.txt (0 => 290628)


--- trunk/LayoutTests/platform/gtk/compositing/repaint/composite-and-scale-change-actual.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/gtk/compositing/repaint/composite-and-scale-change-actual.txt	2022-03-01 04:54:13 UTC (rev 290628)
@@ -0,0 +1,29 @@
+(repaint rects
+  (rect 30 20 440 440)
+  (rect 0 0 800 600)
+  (rect 0 0 800 13)
+)
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 30.00 20.00)
+          (anchor 0.00 0.00)
+          (bounds 440.00 440.00)
+          (contentsOpaque 1)
+          (drawsContent 1)
+          (transform [0.50 0.00 0.00 0.00] [0.00 0.50 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
+          (repaint rects
+            (rect 0.00 0.00 440.00 440.00)
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/platform/mac-wk1/compositing/repaint/composite-and-scale-change-expected.txt (0 => 290628)


--- trunk/LayoutTests/platform/mac-wk1/compositing/repaint/composite-and-scale-change-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac-wk1/compositing/repaint/composite-and-scale-change-expected.txt	2022-03-01 04:54:13 UTC (rev 290628)
@@ -0,0 +1,26 @@
+(repaint rects
+  (rect 30 20 440 440)
+  (rect 0 0 800 600)
+  (rect 0 0 800 13)
+)
+(GraphicsLayer
+  (anchor 0.00 0.00)
+  (bounds 800.00 600.00)
+  (children 1
+    (GraphicsLayer
+      (bounds 800.00 600.00)
+      (contentsOpaque 1)
+      (children 1
+        (GraphicsLayer
+          (position 30.00 20.00)
+          (anchor 0.00 0.00)
+          (bounds 440.00 440.00)
+          (contentsOpaque 1)
+          (drawsContent 1)
+          (transform [0.50 0.00 0.00 0.00] [0.00 0.50 0.00 0.00] [0.00 0.00 1.00 0.00] [0.00 0.00 0.00 1.00])
+        )
+      )
+    )
+  )
+)
+

Modified: trunk/Source/WebCore/ChangeLog (290627 => 290628)


--- trunk/Source/WebCore/ChangeLog	2022-03-01 03:24:36 UTC (rev 290627)
+++ trunk/Source/WebCore/ChangeLog	2022-03-01 04:54:13 UTC (rev 290628)
@@ -1,5 +1,41 @@
 2022-02-28  Simon Fraser  <[email protected]>
 
+        Compositing/paint invalidation with transforms
+        https://bugs.webkit.org/show_bug.cgi?id=233421
+        <rdar://problem/85814854>
+
+        Reviewed by Alan Bujtas.
+        
+        When changing transform from something like `translate(0)` to `translate3d(0, 0, 0)
+        scale(0.5, 0.5)`, we trigger compositing, and thus need to repaint the previous rect of the
+        layer in its old repaint container. However, the existing code would take the new transform
+        into account when computing that rect, thus dirtying a rect that is too small.
+
+        To fix this, we need to use the cached repaint rects on RenderLayer for this repaint.
+        However, doing so revealed a bug (via
+        compositing/shared-backing/repaint-into-shared-backing.html) in how we compute repaint
+        cached repaint rects in the presence of shared backing. During a compositing update, if a
+        layer's composited state changed, we'd call computeRepaintRectsIncludingDescendants(), which
+        computes rect relative to the layer's repaint container. But at this time, the state of
+        backing sharing in BackingSharingState is in flux (we essentially don't know yet if a layer
+        can use shared backing). So we may compute and cache repaint rects relative to the wrong
+        container.
+
+        To fix this, leverage the existing m_layersPendingRepaint logic, and delay computing the
+        repaint rects until we've established our final backing sharing configuration.
+
+        Tests: compositing/repaint/composite-and-scale-change.html
+               compositing/shared-backing/repaint-into-shared-backing-become-composited.html
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::setBackingProviderLayer):
+        (WebCore::RenderLayer::calculateClipRects const):
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::BackingSharingState::issuePendingRepaints):
+        (WebCore::RenderLayerCompositor::updateBacking):
+
+2022-02-28  Simon Fraser  <[email protected]>
+
         No animation when scroll snap scroller is navigated with the keyboard
         https://bugs.webkit.org/show_bug.cgi?id=236244
 

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (290627 => 290628)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2022-03-01 03:24:36 UTC (rev 290627)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2022-03-01 04:54:13 UTC (rev 290628)
@@ -1963,8 +1963,10 @@
     if (backingProvider == m_backingProviderLayer)
         return;
 
-    if (!renderer().renderTreeBeingDestroyed())
+    if (!renderer().renderTreeBeingDestroyed()) {
         clearClipRectsIncludingDescendants();
+        clearRepaintRects();
+    }
 
     m_backingProviderLayer = backingProvider;
 }
@@ -5308,7 +5310,8 @@
 // Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
 void RenderLayer::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer)
 {
-    renderer().repaintUsingContainer(repaintContainer, renderer().clippedOverflowRectForRepaint(repaintContainer));
+    auto clippedOverflowRect = m_repaintRectsValid ? m_repaintRects.clippedOverflowRect : renderer().clippedOverflowRectForRepaint(repaintContainer);
+    renderer().repaintUsingContainer(repaintContainer, clippedOverflowRect);
 
     for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) {
         if (!curr->isComposited())

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (290627 => 290628)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2022-03-01 03:24:36 UTC (rev 290627)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2022-03-01 04:54:13 UTC (rev 290628)
@@ -371,6 +371,7 @@
 {
     for (auto& layer : m_layersPendingRepaint) {
         LOG_WITH_STREAM(Compositing, stream << "Issuing postponed repaint of layer " << &layer);
+        layer.computeRepaintRectsIncludingDescendants();
         layer.compositor().repaintOnCompositingChange(layer);
     }
     
@@ -1791,8 +1792,12 @@
         requiresCompositingForPosition(rendererForCompositingTests(layer), layer, queryData);
     }
 
+    auto repaintTargetsSharedBacking = [&](RenderLayer& layer) {
+        return backingSharingState && layerRepaintTargetsBackingSharingLayer(layer, *backingSharingState);
+    };
+    
     auto repaintLayer = [&](RenderLayer& layer) {
-        if (backingSharingState && layerRepaintTargetsBackingSharingLayer(layer, *backingSharingState)) {
+        if (repaintTargetsSharedBacking(layer)) {
             LOG_WITH_STREAM(Compositing, stream << "Layer " << &layer << " needs to repaint into potential backing-sharing layer, postponing repaint");
             backingSharingState->addLayerNeedingRepaint(layer);
         } else
@@ -1853,10 +1858,12 @@
             layerChanged = true;
 
             // This layer and all of its descendants have cached repaints rects that are relative to
-            // the repaint container, so change when compositing changes; we need to update them here.
-            layer.computeRepaintRectsIncludingDescendants();
+            // the repaint container, so change when compositing changes; we need to update them here,
+            // as long as shared backing isn't going to change our repaint container.
+            if (!repaintTargetsSharedBacking(layer))
+                layer.computeRepaintRectsIncludingDescendants();
 
-            // If we need to repaint, do so now that we've removed the backing
+            // If we need to repaint, do so now that we've removed the backing.
             repaintLayer(layer);
         }
     }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to