[Async overflow scrolling] Flashes of missing layer backing store when scrolling...
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 May 2019 18:55:14 +0000 (18:55 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 31 May 2019 18:55:14 +0000 (18:55 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198363

Reviewed by Tim Horton.

Source/WebCore:

When the contents of an overflow:scroll did not use a tiled backing layer, GraphicsLayerCA::adjustCoverageRect()
would do no coverage rect expansion for scrolling, which meant that backing store attachment for
descendant layers would just use the visible rect from their scrolling ancestor which made it easy
to scroll into view a layer whose backing store was not yet attached.

Since this only affects non-tiled layers, re-use the generic TileController::adjustTileCoverageRect()
code by moving it down to GraphicsLayer, and call it for a scrolled contents layer which does not
have tiled backing.

Tested by fast/scrolling/ios/reconcile-layer-position-recursive.html

* platform/graphics/GraphicsLayer.cpp:
(WebCore::GraphicsLayer::adjustCoverageRectForMovement):
* platform/graphics/GraphicsLayer.h:
* platform/graphics/ca/GraphicsLayerCA.cpp:
(WebCore::GraphicsLayerCA::adjustCoverageRect const):
* platform/graphics/ca/TileController.cpp:
(WebCore::TileController::adjustTileCoverageRect):

LayoutTests:

Reset results.

* fast/scrolling/ios/reconcile-layer-position-recursive-expected.txt:
* tiled-drawing/tiled-backing-in-window-expected.txt:

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

LayoutTests/ChangeLog
LayoutTests/fast/scrolling/ios/reconcile-layer-position-recursive-expected.txt
LayoutTests/tiled-drawing/tiled-backing-in-window-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/GraphicsLayer.cpp
Source/WebCore/platform/graphics/GraphicsLayer.h
Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp
Source/WebCore/platform/graphics/ca/TileController.cpp

index 5889297..5a75362 100644 (file)
@@ -8,6 +8,18 @@
         * webgpu/whlsl-store-to-property-updates-properly-expected.html: Added.
         * webgpu/whlsl-store-to-property-updates-properly.html: Added.
 
+2019-05-31  Simon Fraser  <simon.fraser@apple.com>
+
+        [Async overflow scrolling] Flashes of missing layer backing store when scrolling an overflow
+        https://bugs.webkit.org/show_bug.cgi?id=198363
+
+        Reviewed by Tim Horton.
+
+        Reset results.
+
+        * fast/scrolling/ios/reconcile-layer-position-recursive-expected.txt:
+        * tiled-drawing/tiled-backing-in-window-expected.txt:
+
 2019-05-31  Ryan Haddad  <ryanhaddad@apple.com>
 
         Unreviewed, rolling out r245946.
index fb10f4e..be96bc5 100644 (file)
@@ -39,7 +39,7 @@
                   (bounds 300.00 510.00)
                   (drawsContent 1)
                   (visible rect 0.00, 13.00 300.00 x 287.00)
-                  (coverage rect 0.00, 13.00 300.00 x 287.00)
+                  (coverage rect 0.00, 12.00 300.00 x 288.00)
                   (intersects coverage rect 1)
                   (contentsScale 2.00)
                   (children 1
@@ -48,7 +48,7 @@
                       (bounds 210.00 410.00)
                       (drawsContent 1)
                       (visible rect 0.00, 0.00 210.00 x 250.00)
-                      (coverage rect -50.00, -37.00 300.00 x 287.00)
+                      (coverage rect -50.00, -38.00 300.00 x 288.00)
                       (intersects coverage rect 1)
                       (contentsScale 2.00)
                       (children 1
index d5cd7fb..e70ad4c 100644 (file)
@@ -63,7 +63,7 @@ Tiled box
           (usingTiledLayer 1)
           (drawsContent 1)
           (visible rect 0.00, 0.00 777.00 x 200.00)
-          (coverage rect -8.00, -8.00 785.00 x 585.00)
+          (coverage rect 0.00, 0.00 777.00 x 200.00)
           (intersects coverage rect 1)
           (contentsScale 1.00)
           (tile cache coverage 0, 0 1024 x 200)
index 6e08b29..905a884 100644 (file)
         * Modules/webgpu/WHLSL/Metal/WHLSLFunctionWriter.cpp:
         (WebCore::WHLSL::Metal::FunctionDefinitionWriter::visit):
 
+2019-05-31  Simon Fraser  <simon.fraser@apple.com>
+
+        [Async overflow scrolling] Flashes of missing layer backing store when scrolling an overflow
+        https://bugs.webkit.org/show_bug.cgi?id=198363
+
+        Reviewed by Tim Horton.
+
+        When the contents of an overflow:scroll did not use a tiled backing layer, GraphicsLayerCA::adjustCoverageRect()
+        would do no coverage rect expansion for scrolling, which meant that backing store attachment for
+        descendant layers would just use the visible rect from their scrolling ancestor which made it easy
+        to scroll into view a layer whose backing store was not yet attached.
+        
+        Since this only affects non-tiled layers, re-use the generic TileController::adjustTileCoverageRect()
+        code by moving it down to GraphicsLayer, and call it for a scrolled contents layer which does not
+        have tiled backing.
+        
+        Tested by fast/scrolling/ios/reconcile-layer-position-recursive.html
+
+        * platform/graphics/GraphicsLayer.cpp:
+        (WebCore::GraphicsLayer::adjustCoverageRectForMovement):
+        * platform/graphics/GraphicsLayer.h:
+        * platform/graphics/ca/GraphicsLayerCA.cpp:
+        (WebCore::GraphicsLayerCA::adjustCoverageRect const):
+        * platform/graphics/ca/TileController.cpp:
+        (WebCore::TileController::adjustTileCoverageRect):
+
 2019-05-31  Geoffrey Garen  <ggaren@apple.com>
 
         Some WeakPtr cleanup
index 5568f4a..0bfd94c 100644 (file)
@@ -502,6 +502,64 @@ void GraphicsLayer::paintGraphicsLayerContents(GraphicsContext& context, const F
     client().paintContents(this, context, m_paintingPhase, clipRect, layerPaintBehavior);
 }
 
+FloatRect GraphicsLayer::adjustCoverageRectForMovement(const FloatRect& coverageRect, const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect)
+{
+    // If the old visible rect is empty, we have no information about how the visible area is changing
+    // (maybe the layer was just created), so don't attempt to expand. Also don't attempt to expand if the rects don't overlap.
+    if (previousVisibleRect.isEmpty() || !currentVisibleRect.intersects(previousVisibleRect))
+        return unionRect(coverageRect, currentVisibleRect);
+
+    const float paddingMultiplier = 2;
+
+    float leftEdgeDelta = paddingMultiplier * (currentVisibleRect.x() - previousVisibleRect.x());
+    float rightEdgeDelta = paddingMultiplier * (currentVisibleRect.maxX() - previousVisibleRect.maxX());
+
+    float topEdgeDelta = paddingMultiplier * (currentVisibleRect.y() - previousVisibleRect.y());
+    float bottomEdgeDelta = paddingMultiplier * (currentVisibleRect.maxY() - previousVisibleRect.maxY());
+    
+    FloatRect expandedRect = currentVisibleRect;
+
+    // More exposed on left side.
+    if (leftEdgeDelta < 0) {
+        float newLeft = expandedRect.x() + leftEdgeDelta;
+        // Pad to the left, but don't reduce padding that's already in the backing store (since we're still exposing to the left).
+        if (newLeft < previousVisibleRect.x())
+            expandedRect.shiftXEdgeTo(newLeft);
+        else
+            expandedRect.shiftXEdgeTo(previousVisibleRect.x());
+    }
+
+    // More exposed on right.
+    if (rightEdgeDelta > 0) {
+        float newRight = expandedRect.maxX() + rightEdgeDelta;
+        // Pad to the right, but don't reduce padding that's already in the backing store (since we're still exposing to the right).
+        if (newRight > previousVisibleRect.maxX())
+            expandedRect.setWidth(newRight - expandedRect.x());
+        else
+            expandedRect.setWidth(previousVisibleRect.maxX() - expandedRect.x());
+    }
+
+    // More exposed at top.
+    if (topEdgeDelta < 0) {
+        float newTop = expandedRect.y() + topEdgeDelta;
+        if (newTop < previousVisibleRect.y())
+            expandedRect.shiftYEdgeTo(newTop);
+        else
+            expandedRect.shiftYEdgeTo(previousVisibleRect.y());
+    }
+
+    // More exposed on bottom.
+    if (bottomEdgeDelta > 0) {
+        float newBottom = expandedRect.maxY() + bottomEdgeDelta;
+        if (newBottom > previousVisibleRect.maxY())
+            expandedRect.setHeight(newBottom - expandedRect.y());
+        else
+            expandedRect.setHeight(previousVisibleRect.maxY() - expandedRect.y());
+    }
+    
+    return unionRect(coverageRect, expandedRect);
+}
+
 String GraphicsLayer::animationNameForTransition(AnimatedPropertyID property)
 {
     // | is not a valid identifier character in CSS, so this can never conflict with a keyframe identifier.
index e48434e..295308d 100644 (file)
@@ -576,6 +576,8 @@ public:
     // for example to allocate new tiles.
     virtual bool visibleRectChangeRequiresFlush(const FloatRect& /* clipRect */) const { return false; }
 
+    static FloatRect adjustCoverageRectForMovement(const FloatRect& coverageRect, const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect);
+
     // Return a string with a human readable form of the layer tree, If debug is true
     // pointers for the layers and timing data will be included in the returned string.
     WEBCORE_EXPORT String layerTreeAsText(LayerTreeAsTextBehavior = LayerTreeAsTextBehaviorNormal) const;
index a81ff69..33a33d4 100644 (file)
@@ -1450,6 +1450,10 @@ bool GraphicsLayerCA::adjustCoverageRect(VisibleAndCoverageRects& rects, const F
     case Type::ScrolledContents:
         if (m_layer->usesTiledBackingLayer())
             coverageRect = tiledBacking()->adjustTileCoverageRectForScrolling(coverageRect, size(), oldVisibleRect, rects.visibleRect, pageScaleFactor() * deviceScaleFactor());
+        else {
+            // Even if we don't have tiled backing, we want to expand coverage so that contained layers get attached backing store.
+            coverageRect = adjustCoverageRectForMovement(coverageRect, oldVisibleRect, rects.visibleRect);
+        }
         break;
     case Type::Normal:
         if (m_layer->usesTiledBackingLayer())
index 7ffef81..75fe759 100644 (file)
@@ -28,6 +28,7 @@
 
 #if USE(CG)
 
+#include "GraphicsLayer.h"
 #include "IntRect.h"
 #include "Logging.h"
 #include "PlatformCALayer.h"
@@ -364,65 +365,11 @@ IntRect TileController::boundsAtLastRevalidateWithoutMargin() const
 
 FloatRect TileController::adjustTileCoverageRect(const FloatRect& coverageRect, const FloatRect& previousVisibleRect, const FloatRect& currentVisibleRect, bool sizeChanged)
 {
-    // If the old visible rect is empty, we have no information about how the visible area is changing
-    // (maybe the layer was just created), so don't attempt to expand. Also don't attempt to expand
-    // if the size changed or the rects don't overlap.
-    if (previousVisibleRect.isEmpty() || sizeChanged  || !currentVisibleRect.intersects(previousVisibleRect))
+    if (sizeChanged || MemoryPressureHandler::singleton().isUnderMemoryPressure())
         return unionRect(coverageRect, currentVisibleRect);
 
-    if (MemoryPressureHandler::singleton().isUnderMemoryPressure())
-        return unionRect(coverageRect, currentVisibleRect);
-
-    const float paddingMultiplier = 2;
-
-    float leftEdgeDelta = paddingMultiplier * (currentVisibleRect.x() - previousVisibleRect.x());
-    float rightEdgeDelta = paddingMultiplier * (currentVisibleRect.maxX() - previousVisibleRect.maxX());
-
-    float topEdgeDelta = paddingMultiplier * (currentVisibleRect.y() - previousVisibleRect.y());
-    float bottomEdgeDelta = paddingMultiplier * (currentVisibleRect.maxY() - previousVisibleRect.maxY());
-    
-    FloatRect expandedRect = currentVisibleRect;
-
-    // More exposed on left side.
-    if (leftEdgeDelta < 0) {
-        float newLeft = expandedRect.x() + leftEdgeDelta;
-        // Pad to the left, but don't reduce padding that's already in the backing store (since we're still exposing to the left).
-        if (newLeft < previousVisibleRect.x())
-            expandedRect.shiftXEdgeTo(newLeft);
-        else
-            expandedRect.shiftXEdgeTo(previousVisibleRect.x());
-    }
-
-    // More exposed on right.
-    if (rightEdgeDelta > 0) {
-        float newRight = expandedRect.maxX() + rightEdgeDelta;
-        // Pad to the right, but don't reduce padding that's already in the backing store (since we're still exposing to the right).
-        if (newRight > previousVisibleRect.maxX())
-            expandedRect.setWidth(newRight - expandedRect.x());
-        else
-            expandedRect.setWidth(previousVisibleRect.maxX() - expandedRect.x());
-    }
-
-    // More exposed at top.
-    if (topEdgeDelta < 0) {
-        float newTop = expandedRect.y() + topEdgeDelta;
-        if (newTop < previousVisibleRect.y())
-            expandedRect.shiftYEdgeTo(newTop);
-        else
-            expandedRect.shiftYEdgeTo(previousVisibleRect.y());
-    }
-
-    // More exposed on bottom.
-    if (bottomEdgeDelta > 0) {
-        float newBottom = expandedRect.maxY() + bottomEdgeDelta;
-        if (newBottom > previousVisibleRect.maxY())
-            expandedRect.setHeight(newBottom - expandedRect.y());
-        else
-            expandedRect.setHeight(previousVisibleRect.maxY() - expandedRect.y());
-    }
-    
-    expandedRect.intersect(boundsWithoutMargin());
-    return unionRect(coverageRect, expandedRect);
+    auto expandedCoverageRect = GraphicsLayer::adjustCoverageRectForMovement(coverageRect, previousVisibleRect, currentVisibleRect);
+    return intersection(expandedCoverageRect, boundsWithoutMargin());
 }
 
 #if !PLATFORM(IOS_FAMILY)