- 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">
+
+ <div class="inner">
+
+ </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">
+
+ <div class="inner">
+
+ </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);
}
}