Changeset 245656 in webkit


Ignore:
Timestamp:
May 22, 2019 3:58:25 PM (5 years ago)
Author:
Simon Fraser
Message:

Fix scrolling tree state for more obscure combinations of positioning and paint order
https://bugs.webkit.org/show_bug.cgi?id=198139

Reviewed by Antti Koivisto.

Source/WebCore:

There were three places in RenderLayerCompositor that used a version of ancestor
layer traversal looking at containing blocks, and all three had issues. So make a
shared function to do the ancestor walk, and use it thrice.

isScrolledByOverflowScrollLayer() fumbled containingBlockCanSkipLayers, so failed
to create a scrolling tree node for a composited layer inside position:fixed in
overflow (tested by composited-in-absolute-in-overflow.html).

collectStationaryLayerRelatedOverflowNodes() failed to handle nested
overflow:scroll; it needs to find all the composited scrollers that affect the
position of the given layer relative to its compositing ancestor, which may be the
scroller, or a descendant of the scroller. However, it didn't walk up far enough
and find more that one ancestor. Tested by absolute-in-nested-sc-scrollers.html.

enclosingClippingScopes() was OK but now uses the share function.

Tests: scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers.html

scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow.html

  • rendering/RenderLayerCompositor.cpp:

(WebCore::traverseAncestorLayers):
(WebCore::enclosingClippingScopes):
(WebCore::isScrolledByOverflowScrollLayer):
(WebCore::collectStationaryLayerRelatedOverflowNodes):
(WebCore::collectRelatedCoordinatedScrollingNodes):

LayoutTests:

  • platform/ios-wk2/scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers-expected.txt: Added.
  • platform/ios-wk2/scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow-expected.txt: Added.
  • scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers-expected.txt: Added.
  • scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers.html: Added.
  • scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow-expected.txt: Added.
  • scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow.html: Added.
Location:
trunk
Files:
6 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r245651 r245656  
     12019-05-22  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Fix scrolling tree state for more obscure combinations of positioning and paint order
     4        https://bugs.webkit.org/show_bug.cgi?id=198139
     5
     6        Reviewed by Antti Koivisto.
     7
     8        * platform/ios-wk2/scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers-expected.txt: Added.
     9        * platform/ios-wk2/scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow-expected.txt: Added.
     10        * scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers-expected.txt: Added.
     11        * scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers.html: Added.
     12        * scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow-expected.txt: Added.
     13        * scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow.html: Added.
     14
    1152019-05-22  Simon Fraser  <simon.fraser@apple.com>
    216
  • trunk/Source/WebCore/ChangeLog

    r245651 r245656  
     12019-05-22  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Fix scrolling tree state for more obscure combinations of positioning and paint order
     4        https://bugs.webkit.org/show_bug.cgi?id=198139
     5
     6        Reviewed by Antti Koivisto.
     7
     8        There were three places in RenderLayerCompositor that used a version of ancestor
     9        layer traversal looking at containing blocks, and all three had issues. So make a
     10        shared function to do the ancestor walk, and use it thrice.
     11
     12        isScrolledByOverflowScrollLayer() fumbled containingBlockCanSkipLayers, so failed
     13        to create a scrolling tree node for a composited layer inside position:fixed in
     14        overflow (tested by composited-in-absolute-in-overflow.html).
     15
     16        collectStationaryLayerRelatedOverflowNodes() failed to handle nested
     17        overflow:scroll; it needs to find all the composited scrollers that affect the
     18        position of the given layer relative to its compositing ancestor, which may be the
     19        scroller, or a descendant of the scroller. However, it didn't walk up far enough
     20        and find more that one ancestor. Tested by absolute-in-nested-sc-scrollers.html.
     21
     22        enclosingClippingScopes() was OK but now uses the share function.
     23
     24        Tests: scrollingcoordinator/scrolling-tree/absolute-in-nested-sc-scrollers.html
     25               scrollingcoordinator/scrolling-tree/composited-in-absolute-in-overflow.html
     26
     27        * rendering/RenderLayerCompositor.cpp:
     28        (WebCore::traverseAncestorLayers):
     29        (WebCore::enclosingClippingScopes):
     30        (WebCore::isScrolledByOverflowScrollLayer):
     31        (WebCore::collectStationaryLayerRelatedOverflowNodes):
     32        (WebCore::collectRelatedCoordinatedScrollingNodes):
     33
    1342019-05-22  Simon Fraser  <simon.fraser@apple.com>
    235
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r245651 r245656  
    17951795}
    17961796
     1797enum class AncestorTraversal { Continue, Stop };
     1798
     1799// This is a simplified version of containing block walking that only handles absolute position.
     1800template <typename Function>
     1801static AncestorTraversal traverseAncestorLayers(const RenderLayer& layer, Function&& function)
     1802{
     1803    bool containingBlockCanSkipLayers = layer.renderer().isAbsolutelyPositioned();
     1804    RenderLayer* nextPaintOrderParent = layer.paintOrderParent();
     1805
     1806    for (const auto* ancestorLayer = layer.parent(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
     1807        bool inContainingBlockChain = true;
     1808
     1809        if (containingBlockCanSkipLayers)
     1810            inContainingBlockChain = ancestorLayer->renderer().canContainAbsolutelyPositionedObjects();
     1811
     1812        if (function(*ancestorLayer, inContainingBlockChain, ancestorLayer == nextPaintOrderParent) == AncestorTraversal::Stop)
     1813            return AncestorTraversal::Stop;
     1814
     1815        if (inContainingBlockChain)
     1816            containingBlockCanSkipLayers = ancestorLayer->renderer().isAbsolutelyPositioned();
     1817       
     1818        if (ancestorLayer == nextPaintOrderParent)
     1819            nextPaintOrderParent = ancestorLayer->paintOrderParent();
     1820    }
     1821   
     1822    return AncestorTraversal::Continue;
     1823}
     1824
    17971825static bool createsClippingScope(const RenderLayer& layer)
    17981826{
     
    18081836        return clippingScopes;
    18091837
    1810     bool containingBlockCanSkipLayers = layer.renderer().isAbsolutelyPositioned();
    1811     for (const auto* ancestorLayer = layer.parent(); ancestorLayer; ancestorLayer = ancestorLayer->parent()) {
    1812         bool inContainingBlockChain = true;
    1813         if (containingBlockCanSkipLayers) {
    1814             inContainingBlockChain = ancestorLayer->renderer().canContainAbsolutelyPositionedObjects();
    1815             if (inContainingBlockChain)
    1816                 containingBlockCanSkipLayers = ancestorLayer->renderer().isAbsolutelyPositioned();
    1817         }
    1818        
    1819         if (inContainingBlockChain && createsClippingScope(*ancestorLayer)) {
     1838    traverseAncestorLayers(layer, [&](const RenderLayer& ancestorLayer, bool inContainingBlockChain, bool) {
     1839        if (inContainingBlockChain && createsClippingScope(ancestorLayer)) {
    18201840            LayoutRect clipRect;
    1821             if (is<RenderBox>(ancestorLayer->renderer())) {
     1841            if (is<RenderBox>(ancestorLayer.renderer())) {
    18221842                // FIXME: This is expensive. Broken with transforms.
    1823                 LayoutPoint offsetFromRoot = ancestorLayer->convertToLayerCoords(&rootLayer, { });
    1824                 clipRect = downcast<RenderBox>(ancestorLayer->renderer()).overflowClipRect(offsetFromRoot);
     1843                LayoutPoint offsetFromRoot = ancestorLayer.convertToLayerCoords(&rootLayer, { });
     1844                clipRect = downcast<RenderBox>(ancestorLayer.renderer()).overflowClipRect(offsetFromRoot);
    18251845            }
    18261846
    1827             LayerOverlapMap::LayerAndBounds layerAndBounds { const_cast<RenderLayer&>(*ancestorLayer), clipRect };
     1847            LayerOverlapMap::LayerAndBounds layerAndBounds { const_cast<RenderLayer&>(ancestorLayer), clipRect };
    18281848            clippingScopes.insert(1, layerAndBounds); // Order is roots to leaves.
    18291849        }
    1830     }
     1850        return AncestorTraversal::Continue;
     1851    });
    18311852
    18321853    return clippingScopes;
     
    30413062}
    30423063
    3043 // Return true if overflowScrollLayer is in layer's containing block chain.
    30443064static bool isScrolledByOverflowScrollLayer(const RenderLayer& layer, const RenderLayer& overflowScrollLayer)
    30453065{
    3046     bool containingBlockCanSkipLayers = layer.renderer().isAbsolutelyPositioned();
    3047 
    3048     for (const auto* currLayer = layer.parent(); currLayer; currLayer = currLayer->parent()) {
    3049         bool inContainingBlockChain = true;
    3050         if (containingBlockCanSkipLayers) {
    3051             inContainingBlockChain = currLayer->renderer().canContainAbsolutelyPositionedObjects();
    3052             if (inContainingBlockChain)
    3053                 containingBlockCanSkipLayers = currLayer->renderer().isAbsolutelyPositioned();
    3054         }
    3055 
    3056         if (currLayer == &overflowScrollLayer)
    3057             return inContainingBlockChain;
    3058     }
    3059 
    3060     return false;
     3066    bool scrolledByOverflowScroll = false;
     3067    traverseAncestorLayers(layer, [&](const RenderLayer& ancestorLayer, bool inContainingBlockChain, bool) {
     3068        if (&ancestorLayer == &overflowScrollLayer) {
     3069            scrolledByOverflowScroll = inContainingBlockChain;
     3070            return AncestorTraversal::Stop;
     3071        }
     3072        return AncestorTraversal::Continue;
     3073    });
     3074    return scrolledByOverflowScroll;
    30613075}
    30623076
     
    30843098}
    30853099
    3086 static void collectStationaryLayerRelatedOverflowNodes(const RenderLayer& layer, const RenderLayer& /*compositedAncestor*/, Vector<ScrollingNodeID>& scrollingNodes)
     3100static void collectStationaryLayerRelatedOverflowNodes(const RenderLayer& layer, const RenderLayer&, Vector<ScrollingNodeID>& scrollingNodes)
    30873101{
    30883102    ASSERT(layer.isComposited());
     
    30983112
    30993113    ASSERT(layer.renderer().isAbsolutelyPositioned());
    3100     bool containingBlockCanSkipLayers = true;
    3101 
    3102     for (const auto* currLayer = layer.parent(); currLayer; currLayer = currLayer->parent()) {
    3103         bool inContainingBlockChain = true;
    3104         if (containingBlockCanSkipLayers) {
    3105             inContainingBlockChain = currLayer->renderer().canContainAbsolutelyPositionedObjects();
    3106             if (inContainingBlockChain)
    3107                 containingBlockCanSkipLayers = currLayer->renderer().isAbsolutelyPositioned();
    3108         }
    3109 
    3110         if (currLayer->hasCompositedScrollableOverflow()) {
    3111             appendOverflowLayerNodeID(*currLayer);
    3112             break;
    3113         }
    3114     }
    3115 }
    3116 
     3114
     3115    // Collect all the composited scrollers which affect the position of this layer relative to its compositing ancestor (which might be inside the scroller or the scroller itself).
     3116    bool seenPaintOrderAncestor = false;
     3117    traverseAncestorLayers(layer, [&](const RenderLayer& ancestorLayer, bool isContainingBlockChain, bool isPaintOrderAncestor) {
     3118        seenPaintOrderAncestor |= isPaintOrderAncestor;
     3119        if (isContainingBlockChain && isPaintOrderAncestor)
     3120            return AncestorTraversal::Stop;
     3121
     3122        if (seenPaintOrderAncestor && !isContainingBlockChain && ancestorLayer.hasCompositedScrollableOverflow())
     3123            appendOverflowLayerNodeID(ancestorLayer);
     3124
     3125        return AncestorTraversal::Continue;
     3126    });
     3127}
    31173128
    31183129ScrollPositioningBehavior RenderLayerCompositor::computeCoordinatedPositioningForLayer(const RenderLayer& layer) const
     
    31833194    case ScrollPositioningBehavior::Stationary: {
    31843195        ASSERT(layer.renderer().isAbsolutelyPositioned());
    3185         // Collect all the composited scrollers between this layer and its composited ancestor.
    31863196        auto* compositedAncestor = layer.ancestorCompositingLayer();
    31873197        if (!compositedAncestor)
Note: See TracChangeset for help on using the changeset viewer.