Title: [246018] trunk
Revision
246018
Author
[email protected]
Date
2019-06-01 19:55:57 -0700 (Sat, 01 Jun 2019)

Log Message

Async overflow scroll on iOS paints slowly if it has a negative z-index child
https://bugs.webkit.org/show_bug.cgi?id=196508
rdar://problem/49532709

Reviewed by Dean Jackson.
Source/WebCore:

If a RenderLayerBacking had a foreground layer and a scrolled contents layer, every geometry
update would change the size and offsetFromRenderer of the foreground layer between two
states, triggering repaint.

Fix by updating the fore- and background-layers last (nothing elese has dependencies
on their geometry), and using GraphicsLayer::DontSetNeedsDisplay as we do for the
scrolled contents layer.

The test also revealed a bug where the shapeMaskLayer would get incorrect geometry when scrollbars
were visible, because it would be squished by setting the wrong bounds, so fix that.

Test: compositing/repaint/scroller-with-foreground-layer-repaints.html

* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::updateClippingStrategy):
* rendering/RenderLayerBacking.cpp:
(WebCore::RenderLayerBacking::updateGeometry):

LayoutTests:

* compositing/geometry/scroller-with-clipping-and-foreground-layers-expected.html: Added.
* compositing/geometry/scroller-with-clipping-and-foreground-layers.html: Added.
* compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt: Added.
* compositing/repaint/scroller-with-foreground-layer-repaints.html: Added.
* platform/ios-wk2/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt: Added.
* platform/mac-wk1/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246017 => 246018)


--- trunk/LayoutTests/ChangeLog	2019-06-01 21:40:04 UTC (rev 246017)
+++ trunk/LayoutTests/ChangeLog	2019-06-02 02:55:57 UTC (rev 246018)
@@ -1,5 +1,20 @@
 2019-06-01  Simon Fraser  <[email protected]>
 
+        Async overflow scroll on iOS paints slowly if it has a negative z-index child
+        https://bugs.webkit.org/show_bug.cgi?id=196508
+        rdar://problem/49532709
+
+        Reviewed by Dean Jackson.
+
+        * compositing/geometry/scroller-with-clipping-and-foreground-layers-expected.html: Added.
+        * compositing/geometry/scroller-with-clipping-and-foreground-layers.html: Added.
+        * compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt: Added.
+        * compositing/repaint/scroller-with-foreground-layer-repaints.html: Added.
+        * platform/ios-wk2/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt: Added.
+        * platform/mac-wk1/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt: Added.
+
+2019-06-01  Simon Fraser  <[email protected]>
+
         Non-composited negative z-order children should not trigger creation of a foreground layer
         https://bugs.webkit.org/show_bug.cgi?id=198455
 

Added: trunk/LayoutTests/compositing/geometry/scroller-with-clipping-and-foreground-layers-expected.html (0 => 246018)


--- trunk/LayoutTests/compositing/geometry/scroller-with-clipping-and-foreground-layers-expected.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/geometry/scroller-with-clipping-and-foreground-layers-expected.html	2019-06-02 02:55:57 UTC (rev 246018)
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        body {
+            margin: 0;
+        }
+        
+        #scroller {
+            position: relative;
+            z-index: 0;
+            width: 400px;
+            height: 400px;
+            margin: 20px;
+            overflow: scroll;
+            padding: 20px;
+            border: 30px solid orange;
+            box-sizing: border-box;
+            border-radius: 80px 200px;
+            background-color: silver;
+        }
+
+        .negative {
+            position: absolute;
+            top: 20px;
+            left: 30px;
+            z-index: 1;
+            padding: 20px;
+            background-color: gray;
+            transform: translateZ(0);
+        }
+        
+        .contents {
+            height: 1000px;
+            background: linear-gradient(green, blue);
+        }
+        
+        .masker {
+            position: absolute;
+            top: 49px;
+            left: 49px;
+            width: 342px;
+            height: 342px;
+            box-sizing: border-box;
+            border: 3px solid gray;
+            border-radius: 49px 170px;
+        }
+    </style>
+    <script>
+        window.addEventListener('load', () => {
+            scroller.scrollTo(0, 250);
+        }, false);
+    </script>
+</head>
+<body>
+    <div id="scroller">
+        <div class="negative"></div>
+        <div class="contents"></div>
+    </div>
+    <div class="masker"></div>
+</body>
+</html>
+

Added: trunk/LayoutTests/compositing/geometry/scroller-with-clipping-and-foreground-layers.html (0 => 246018)


--- trunk/LayoutTests/compositing/geometry/scroller-with-clipping-and-foreground-layers.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/geometry/scroller-with-clipping-and-foreground-layers.html	2019-06-02 02:55:57 UTC (rev 246018)
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        body {
+            margin: 0;
+        }
+        
+        #scroller {
+            position: relative;
+            z-index: 0;
+            width: 400px;
+            height: 400px;
+            margin: 20px;
+            overflow: scroll;
+            padding: 20px;
+            border: 30px solid orange;
+            box-sizing: border-box;
+            border-radius: 80px 200px;
+            background-color: silver;
+        }
+
+        .negative {
+            position: absolute;
+            top: 20px;
+            left: 30px;
+            z-index: -1;
+            padding: 20px;
+            background-color: gray;
+            transform: translateZ(0);
+        }
+        
+        .contents {
+            height: 1000px;
+            background: linear-gradient(green, blue);
+        }
+        
+        .masker {
+            position: absolute;
+            top: 49px;
+            left: 49px;
+            width: 342px;
+            height: 342px;
+            box-sizing: border-box;
+            border: 3px solid gray;
+            border-radius: 49px 170px;
+        }
+    </style>
+    <script>
+        window.addEventListener('load', () => {
+            scroller.scrollTo(0, 250);
+        }, false);
+    </script>
+</head>
+<body>
+    <div id="scroller">
+        <div class="negative"></div>
+        <div class="contents"></div>
+    </div>
+    <div class="masker"></div>
+</body>
+</html>
+

Added: trunk/LayoutTests/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt (0 => 246018)


--- trunk/LayoutTests/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt	2019-06-02 02:55:57 UTC (rev 246018)
@@ -0,0 +1,54 @@
+Scrolled contents
+(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 8.00 8.00)
+          (bounds 322.00 322.00)
+          (drawsContent 1)
+          (repaint rects
+            (rect 306.00 1.00 15.00 104.00)
+            (rect 306.00 60.00 15.00 91.00)
+            (rect 306.00 105.00 15.00 201.00)
+          )
+          (children 1
+            (GraphicsLayer
+              (offsetFromRenderer width=1 height=1)
+              (position 1.00 1.00)
+              (bounds 305.00 305.00)
+              (children 1
+                (GraphicsLayer
+                  (offsetFromRenderer width=1 height=1)
+                  (scrollOffset (0,200))
+                  (position 0.00 -200.00)
+                  (anchor 0.00 0.00)
+                  (bounds 305.00 1020.00)
+                  (drawsContent 1)
+                  (children 2
+                    (GraphicsLayer
+                      (position 30.00 50.00)
+                      (bounds 102.00 102.00)
+                      (contentsOpaque 1)
+                      (drawsContent 1)
+                    )
+                    (GraphicsLayer
+                      (offsetFromRenderer width=1 height=-199)
+                      (bounds 305.00 1020.00)
+                      (drawsContent 1)
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/compositing/repaint/scroller-with-foreground-layer-repaints.html (0 => 246018)


--- trunk/LayoutTests/compositing/repaint/scroller-with-foreground-layer-repaints.html	                        (rev 0)
+++ trunk/LayoutTests/compositing/repaint/scroller-with-foreground-layer-repaints.html	2019-06-02 02:55:57 UTC (rev 246018)
@@ -0,0 +1,57 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ internal:AsyncOverflowScrollingEnabled=true ] --><html>
+<head>
+    <style>
+        #scroller {
+            position: relative;
+            z-index: 0;
+            width: 300px;
+            height: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            padding: 10px;
+        }
+
+        .contents {
+            height: 1000px;
+        }
+        
+        .negative {
+            position: absolute;
+            z-index: -1;
+            top: 50px;
+            left: 30px;
+            width: 100px;
+            height: 100px;
+            background-color: blue;
+            border: 1px solid green;
+            transform: translateZ(0);
+        }
+    </style>
+    <script>
+        if (window.testRunner) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        window.addEventListener('load', () => {
+            setTimeout(() => {
+                if (window.internals)
+                    internals.startTrackingRepaints();
+            
+                scroller.scrollTo(0, 200);
+                document.getElementById('layers').textContent = internals.layerTreeAsText(document, internals.LAYER_TREE_INCLUDES_REPAINT_RECTS);
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            }, 0);
+        }, false);
+    </script>
+</head>
+<body>
+    <div id="scroller">
+        <div class="negative"></div>
+        <div class="contents">Scrolled contents</div>
+    </div>
+<pre id="layers"></pre>
+</body>
+</html>

Added: trunk/LayoutTests/platform/ios-wk2/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt (0 => 246018)


--- trunk/LayoutTests/platform/ios-wk2/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/ios-wk2/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt	2019-06-02 02:55:57 UTC (rev 246018)
@@ -0,0 +1,49 @@
+Scrolled contents
+(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 8.00 8.00)
+          (bounds 322.00 322.00)
+          (drawsContent 1)
+          (children 1
+            (GraphicsLayer
+              (offsetFromRenderer width=1 height=1)
+              (position 1.00 1.00)
+              (bounds origin 0.00 200.00)
+              (bounds 320.00 320.00)
+              (children 1
+                (GraphicsLayer
+                  (offsetFromRenderer width=1 height=1)
+                  (scrollOffset (0,200))
+                  (anchor 0.00 0.00)
+                  (bounds 320.00 1020.00)
+                  (drawsContent 1)
+                  (children 2
+                    (GraphicsLayer
+                      (position 30.00 50.00)
+                      (bounds 102.00 102.00)
+                      (contentsOpaque 1)
+                      (drawsContent 1)
+                    )
+                    (GraphicsLayer
+                      (offsetFromRenderer width=1 height=-199)
+                      (bounds 320.00 1020.00)
+                      (drawsContent 1)
+                    )
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+

Added: trunk/LayoutTests/platform/mac-wk1/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt (0 => 246018)


--- trunk/LayoutTests/platform/mac-wk1/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/platform/mac-wk1/compositing/repaint/scroller-with-foreground-layer-repaints-expected.txt	2019-06-02 02:55:57 UTC (rev 246018)
@@ -0,0 +1,48 @@
+Scrolled contents
+(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 8.00 8.00)
+          (bounds 322.00 322.00)
+          (drawsContent 1)
+          (repaint rects
+            (rect 0.00 0.00 322.00 322.00)
+            (rect 306.00 1.00 15.00 104.00)
+            (rect 306.00 60.00 15.00 91.00)
+            (rect 306.00 105.00 15.00 201.00)
+          )
+          (children 1
+            (GraphicsLayer
+              (offsetFromRenderer width=1 height=1)
+              (position 1.00 1.00)
+              (bounds 305.00 305.00)
+              (children 2
+                (GraphicsLayer
+                  (position 30.00 -150.00)
+                  (bounds 102.00 102.00)
+                  (contentsOpaque 1)
+                  (drawsContent 1)
+                )
+                (GraphicsLayer
+                  (offsetFromRenderer width=1 height=1)
+                  (bounds 305.00 305.00)
+                  (drawsContent 1)
+                  (repaint rects
+                    (rect 0.00 0.00 305.00 305.00)
+                  )
+                )
+              )
+            )
+          )
+        )
+      )
+    )
+  )
+)
+

Modified: trunk/Source/WebCore/ChangeLog (246017 => 246018)


--- trunk/Source/WebCore/ChangeLog	2019-06-01 21:40:04 UTC (rev 246017)
+++ trunk/Source/WebCore/ChangeLog	2019-06-02 02:55:57 UTC (rev 246018)
@@ -1,5 +1,31 @@
 2019-06-01  Simon Fraser  <[email protected]>
 
+        Async overflow scroll on iOS paints slowly if it has a negative z-index child
+        https://bugs.webkit.org/show_bug.cgi?id=196508
+        rdar://problem/49532709
+
+        Reviewed by Dean Jackson.
+        
+        If a RenderLayerBacking had a foreground layer and a scrolled contents layer, every geometry
+        update would change the size and offsetFromRenderer of the foreground layer between two
+        states, triggering repaint.
+
+        Fix by updating the fore- and background-layers last (nothing elese has dependencies
+        on their geometry), and using GraphicsLayer::DontSetNeedsDisplay as we do for the
+        scrolled contents layer.
+        
+        The test also revealed a bug where the shapeMaskLayer would get incorrect geometry when scrollbars
+        were visible, because it would be squished by setting the wrong bounds, so fix that.
+
+        Test: compositing/repaint/scroller-with-foreground-layer-repaints.html
+
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::updateClippingStrategy):
+        * rendering/RenderLayerBacking.cpp:
+        (WebCore::RenderLayerBacking::updateGeometry):
+
+2019-06-01  Simon Fraser  <[email protected]>
+
         Non-composited negative z-order children should not trigger creation of a foreground layer
         https://bugs.webkit.org/show_bug.cgi?id=198455
 

Modified: trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp (246017 => 246018)


--- trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2019-06-01 21:40:04 UTC (rev 246017)
+++ trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp	2019-06-02 02:55:57 UTC (rev 246018)
@@ -2598,18 +2598,18 @@
 
     if (!shapeMaskLayer) {
         shapeMaskLayer = createPlatformCALayer(PlatformCALayer::LayerTypeShapeLayer, this);
-        shapeMaskLayer->setAnchorPoint(FloatPoint3D());
+        shapeMaskLayer->setAnchorPoint({ });
         shapeMaskLayer->setName("shape mask");
     }
     
-    shapeMaskLayer->setPosition(FloatPoint());
-    shapeMaskLayer->setBounds(clippingLayer.bounds());
+    shapeMaskLayer->setPosition(roundedRect.rect().location() - offsetFromRenderer());
+    FloatRect shapeBounds({ }, roundedRect.rect().size());
+    shapeMaskLayer->setBounds(shapeBounds);
+    FloatRoundedRect offsetRoundedRect(shapeBounds, roundedRect.radii());
+    shapeMaskLayer->setShapeRoundedRect(offsetRoundedRect);
 
     clippingLayer.setCornerRadius(0);
     clippingLayer.setMask(shapeMaskLayer.get());
-    
-    FloatRoundedRect offsetRoundedRect(clippingLayer.bounds(), roundedRect.radii());
-    shapeMaskLayer->setShapeRoundedRect(offsetRoundedRect);
 }
 
 void GraphicsLayerCA::updateContentsRects()

Modified: trunk/Source/WebCore/rendering/RenderLayerBacking.cpp (246017 => 246018)


--- trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2019-06-01 21:40:04 UTC (rev 246017)
+++ trunk/Source/WebCore/rendering/RenderLayerBacking.cpp	2019-06-02 02:55:57 UTC (rev 246018)
@@ -1204,39 +1204,6 @@
             m_contentsContainmentLayer->setAnchorPoint(FloatPoint3D(0.5, 0.5, 0));
     }
 
-    if (m_foregroundLayer) {
-        FloatPoint foregroundPosition;
-        FloatSize foregroundSize = primaryGraphicsLayerRect.size();
-        FloatSize foregroundOffset = m_graphicsLayer->offsetFromRenderer();
-        if (hasClippingLayer()) {
-            // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
-            // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
-            foregroundSize = FloatSize(clippingBox.size());
-            foregroundOffset = toFloatSize(clippingBox.location());
-        }
-
-        m_foregroundLayer->setPosition(foregroundPosition);
-        m_foregroundLayer->setSize(foregroundSize);
-        m_foregroundLayer->setOffsetFromRenderer(foregroundOffset);
-    }
-
-    if (m_backgroundLayer) {
-        FloatPoint backgroundPosition;
-        FloatSize backgroundSize = primaryGraphicsLayerRect.size();
-        if (backgroundLayerPaintsFixedRootBackground()) {
-            const FrameView& frameView = renderer().view().frameView();
-            backgroundPosition = frameView.scrollPositionForFixedPosition();
-            backgroundSize = frameView.layoutSize();
-        } else {
-            auto boundingBox = renderer().objectBoundingBox();
-            backgroundPosition = boundingBox.location();
-            backgroundSize = boundingBox.size();
-        }
-        m_backgroundLayer->setPosition(backgroundPosition);
-        m_backgroundLayer->setSize(backgroundSize);
-        m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
-    }
-
     if (m_owningLayer.reflectionLayer() && m_owningLayer.reflectionLayer()->isComposited()) {
         auto* reflectionBacking = m_owningLayer.reflectionLayer()->backing();
         reflectionBacking->updateGeometry();
@@ -1282,15 +1249,50 @@
         m_scrolledContentsLayer->setSize(scrollSize);
         m_scrolledContentsLayer->setScrollOffset(scrollOffset, GraphicsLayer::DontSetNeedsDisplay);
         m_scrolledContentsLayer->setOffsetFromRenderer(toLayoutSize(paddingBoxIncludingScrollbar.location()), GraphicsLayer::DontSetNeedsDisplay);
-
-        if (m_foregroundLayer) {
-            m_foregroundLayer->setSize(m_scrolledContentsLayer->size());
-            m_foregroundLayer->setOffsetFromRenderer(m_scrolledContentsLayer->offsetFromRenderer() - toLayoutSize(m_scrolledContentsLayer->scrollOffset()));
-        }
         
         adjustTiledBackingCoverage();
     }
 
+    if (m_foregroundLayer) {
+        FloatSize foregroundSize;
+        FloatSize foregroundOffset;
+        GraphicsLayer::ShouldSetNeedsDisplay needsDisplayOnOffsetChange = GraphicsLayer::SetNeedsDisplay;
+        if (m_scrolledContentsLayer) {
+            foregroundSize = m_scrolledContentsLayer->size();
+            foregroundOffset = m_scrolledContentsLayer->offsetFromRenderer() - toLayoutSize(m_scrolledContentsLayer->scrollOffset());
+            needsDisplayOnOffsetChange = GraphicsLayer::DontSetNeedsDisplay;
+        } else if (hasClippingLayer()) {
+            // If we have a clipping layer (which clips descendants), then the foreground layer is a child of it,
+            // so that it gets correctly sorted with children. In that case, position relative to the clipping layer.
+            foregroundSize = FloatSize(clippingBox.size());
+            foregroundOffset = toFloatSize(clippingBox.location());
+        } else {
+            foregroundSize = primaryGraphicsLayerRect.size();
+            foregroundOffset = m_graphicsLayer->offsetFromRenderer();
+        }
+
+        m_foregroundLayer->setPosition({ });
+        m_foregroundLayer->setSize(foregroundSize);
+        m_foregroundLayer->setOffsetFromRenderer(foregroundOffset, needsDisplayOnOffsetChange);
+    }
+
+    if (m_backgroundLayer) {
+        FloatPoint backgroundPosition;
+        FloatSize backgroundSize = primaryGraphicsLayerRect.size();
+        if (backgroundLayerPaintsFixedRootBackground()) {
+            const FrameView& frameView = renderer().view().frameView();
+            backgroundPosition = frameView.scrollPositionForFixedPosition();
+            backgroundSize = frameView.layoutSize();
+        } else {
+            auto boundingBox = renderer().objectBoundingBox();
+            backgroundPosition = boundingBox.location();
+            backgroundSize = boundingBox.size();
+        }
+        m_backgroundLayer->setPosition(backgroundPosition);
+        m_backgroundLayer->setSize(backgroundSize);
+        m_backgroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
+    }
+
     // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store.
     LayoutRect ancestorCompositedBounds = compositedAncestor ? compositedAncestor->backing()->compositedBounds() : LayoutRect();
     setRequiresOwnBackingStore(compositor().requiresOwnBackingStore(m_owningLayer, compositedAncestor,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to