⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 246367 in webkit


Ignore:
Timestamp:
Jun 12, 2019, 11:27:35 AM (7 years ago)
Author:
Antti Koivisto
Message:

(Async scrolling) Handle 'position:fixed' inside 'position:sticky' correctly.
https://bugs.webkit.org/show_bug.cgi?id=198788
<rdar://problem/51589759>

Reviewed by Simon Fraser.

Source/WebCore:

Handle 'position:fixed' inside 'position:sticky' correctly.

Also fix nested 'position:fixed' in case where there is an overflow scroller between them.

Tests: scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html

scrollingcoordinator/ios/fixed-inside-sticky-frame.html
scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html
scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html
scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html

  • page/scrolling/cocoa/ScrollingTreeFixedNode.mm:

(WebCore::ScrollingTreeFixedNode::applyLayerPositions):

Take offsets from sticky nodes into account.

  • page/scrolling/cocoa/ScrollingTreeStickyNode.h:

(WebCore::ScrollingTreeStickyNode::layer):

  • page/scrolling/cocoa/ScrollingTreeStickyNode.mm:

(WebCore::ScrollingTreeStickyNode::computeLayerPosition const):

Factor into a function.

(WebCore::ScrollingTreeStickyNode::applyLayerPositions):
(WebCore::ScrollingTreeStickyNode::scrollDeltaSinceLastCommit const):

  • rendering/RenderLayerCompositor.cpp:

(WebCore::RenderLayerCompositor::isViewportConstrainedFixedOrStickyLayer const):

We need to generate a scrolling tree node for position:fixed in nested case if there is an overflow scroller
between the layers.

LayoutTests:

  • scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html: Added.
  • scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-frame.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html: Added.
  • scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html: Added.
Location:
trunk
Files:
10 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r246363 r246367  
     12019-06-12  Antti Koivisto  <antti@apple.com>
     2
     3        (Async scrolling) Handle 'position:fixed' inside 'position:sticky' correctly.
     4        https://bugs.webkit.org/show_bug.cgi?id=198788
     5        <rdar://problem/51589759>
     6
     7        Reviewed by Simon Fraser.
     8
     9        * scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed-expected.html: Added.
     10        * scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html: Added.
     11        * scrollingcoordinator/ios/fixed-inside-sticky-frame-expected.html: Added.
     12        * scrollingcoordinator/ios/fixed-inside-sticky-frame.html: Added.
     13        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2-expected.html: Added.
     14        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html: Added.
     15        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-expected.html: Added.
     16        * scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html: Added.
     17        * scrollingcoordinator/ios/fixed-inside-sticky-stacking-context-expected.html: Added.
     18        * scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html: Added.
     19
    1202019-06-12  Youenn Fablet  <youenn@apple.com>
    221
  • trunk/Source/WebCore/ChangeLog

    r246362 r246367  
     12019-06-12  Antti Koivisto  <antti@apple.com>
     2
     3        (Async scrolling) Handle 'position:fixed' inside 'position:sticky' correctly.
     4        https://bugs.webkit.org/show_bug.cgi?id=198788
     5        <rdar://problem/51589759>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Handle 'position:fixed' inside 'position:sticky' correctly.
     10
     11        Also fix nested 'position:fixed' in case where there is an overflow scroller between them.
     12
     13        Tests: scrollingcoordinator/ios/fixed-inside-overflow-inside-fixed.html
     14               scrollingcoordinator/ios/fixed-inside-sticky-frame.html
     15               scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context-2.html
     16               scrollingcoordinator/ios/fixed-inside-sticky-no-stacking-context.html
     17               scrollingcoordinator/ios/fixed-inside-sticky-stacking-context.html
     18
     19        * page/scrolling/cocoa/ScrollingTreeFixedNode.mm:
     20        (WebCore::ScrollingTreeFixedNode::applyLayerPositions):
     21
     22        Take offsets from sticky nodes into account.
     23
     24        * page/scrolling/cocoa/ScrollingTreeStickyNode.h:
     25        (WebCore::ScrollingTreeStickyNode::layer):
     26        * page/scrolling/cocoa/ScrollingTreeStickyNode.mm:
     27        (WebCore::ScrollingTreeStickyNode::computeLayerPosition const):
     28
     29        Factor into a function.
     30
     31        (WebCore::ScrollingTreeStickyNode::applyLayerPositions):
     32        (WebCore::ScrollingTreeStickyNode::scrollDeltaSinceLastCommit const):
     33        * rendering/RenderLayerCompositor.cpp:
     34        (WebCore::RenderLayerCompositor::isViewportConstrainedFixedOrStickyLayer const):
     35
     36        We need to generate a scrolling tree node for position:fixed in nested case if there is an overflow scroller
     37        between the layers.
     38
    1392019-06-12  Truitt Savell  <tsavell@apple.com>
    240
  • trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeFixedNode.mm

    r246197 r246367  
    3535#import "ScrollingTreeOverflowScrollingNode.h"
    3636#import "ScrollingTreePositionedNode.h"
     37#import "ScrollingTreeStickyNode.h"
    3738#import "WebCoreCALayerExtras.h"
    3839#import <wtf/text/TextStream.h>
     
    7172    auto computeLayerPosition = [&] {
    7273        FloatSize overflowScrollDelta;
     74        ScrollingTreeStickyNode* lastStickyNode = nullptr;
    7375        for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
    74             if (is<ScrollingTreePositionedNode>(*ancestor)) {
    75                 auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
    76                 if (positioningAncestor.layer() != m_layer)
    77                     overflowScrollDelta -= positioningAncestor.scrollDeltaSinceLastCommit();
    78             }
    79 
    8076            if (is<ScrollingTreeFrameScrollingNode>(*ancestor)) {
    8177                // Fixed nodes are positioned relative to the containing frame scrolling node.
     
    8985                auto& overflowNode = downcast<ScrollingTreeOverflowScrollingNode>(*ancestor);
    9086                overflowScrollDelta -= overflowNode.scrollDeltaSinceLastCommit();
     87                continue;
     88            }
     89
     90            if (is<ScrollingTreePositionedNode>(*ancestor)) {
     91                auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
     92                // See if sticky node already handled this positioning node.
     93                // FIXME: Include positioning node information to sticky/fixed node to avoid these tests.
     94                if (lastStickyNode && lastStickyNode->layer() == positioningAncestor.layer())
     95                    continue;
     96                if (positioningAncestor.layer() != m_layer)
     97                    overflowScrollDelta -= positioningAncestor.scrollDeltaSinceLastCommit();
     98                continue;
     99            }
     100
     101            if (is<ScrollingTreeStickyNode>(*ancestor)) {
     102                auto& stickyNode = downcast<ScrollingTreeStickyNode>(*ancestor);
     103                overflowScrollDelta += stickyNode.scrollDeltaSinceLastCommit();
     104                lastStickyNode = &stickyNode;
     105                continue;
     106            }
     107
     108            if (is<ScrollingTreeFixedNode>(*ancestor)) {
     109                // The ancestor fixed node has already applied the needed corrections to say put.
     110                return m_constraints.layerPositionAtLastLayout() - overflowScrollDelta;
    91111            }
    92112        }
  • trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.h

    r245818 r246367  
    4242    virtual ~ScrollingTreeStickyNode();
    4343
     44    FloatSize scrollDeltaSinceLastCommit() const;
     45
     46    CALayer *layer() { return m_layer.get(); }
     47
    4448private:
    4549    ScrollingTreeStickyNode(ScrollingTree&, ScrollingNodeID);
     
    4751    void commitStateBeforeChildren(const ScrollingStateNode&) override;
    4852    void applyLayerPositions() override;
     53
     54    FloatPoint computeLayerPosition() const;
    4955
    5056    void dumpProperties(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const override;
  • trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm

    r246197 r246367  
    6767}
    6868
    69 void ScrollingTreeStickyNode::applyLayerPositions()
     69FloatPoint ScrollingTreeStickyNode::computeLayerPosition() const
    7070{
    7171    auto computeLayerPositionForScrollingNode = [&](ScrollingTreeNode& scrollingNode) {
     
    8181    };
    8282
    83     auto computeLayerPosition = [&] {
    84         for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
    85             if (is<ScrollingTreePositionedNode>(*ancestor)) {
    86                 auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
     83    for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
     84        if (is<ScrollingTreePositionedNode>(*ancestor)) {
     85            auto& positioningAncestor = downcast<ScrollingTreePositionedNode>(*ancestor);
    8786
    88                 // FIXME: Do we need to do anything for ScrollPositioningBehavior::Stationary?
    89                 if (positioningAncestor.scrollPositioningBehavior() == ScrollPositioningBehavior::Moves) {
    90                     if (positioningAncestor.relatedOverflowScrollingNodes().isEmpty())
    91                         break;
    92                     auto overflowNode = scrollingTree().nodeForID(positioningAncestor.relatedOverflowScrollingNodes()[0]);
    93                     if (!overflowNode)
    94                         break;
     87            // FIXME: Do we need to do anything for ScrollPositioningBehavior::Stationary?
     88            if (positioningAncestor.scrollPositioningBehavior() == ScrollPositioningBehavior::Moves) {
     89                if (positioningAncestor.relatedOverflowScrollingNodes().isEmpty())
     90                    break;
     91                auto overflowNode = scrollingTree().nodeForID(positioningAncestor.relatedOverflowScrollingNodes()[0]);
     92                if (!overflowNode)
     93                    break;
    9594
    96                     auto position = computeLayerPositionForScrollingNode(*overflowNode);
     95                auto position = computeLayerPositionForScrollingNode(*overflowNode);
    9796
    98                     if (positioningAncestor.layer() == m_layer) {
    99                         // We'll also do the adjustment the positioning node would do.
    100                         position -= positioningAncestor.scrollDeltaSinceLastCommit();
    101                     }
    102                    
    103                     return position;
     97                if (positioningAncestor.layer() == m_layer) {
     98                    // We'll also do the adjustment the positioning node would do.
     99                    position -= positioningAncestor.scrollDeltaSinceLastCommit();
    104100                }
    105             }
    106             if (is<ScrollingTreeScrollingNode>(*ancestor))
    107                 return computeLayerPositionForScrollingNode(*ancestor);
    108101
    109             if (is<ScrollingTreeFixedNode>(*ancestor) || is<ScrollingTreeStickyNode>(*ancestor)) {
    110                 // FIXME: Do we need scrolling tree nodes at all for nested cases?
    111                 return m_constraints.layerPositionAtLastLayout();
     102                return position;
    112103            }
    113104        }
    114         ASSERT_NOT_REACHED();
    115         return m_constraints.layerPositionAtLastLayout();
    116     };
     105        if (is<ScrollingTreeScrollingNode>(*ancestor))
     106            return computeLayerPositionForScrollingNode(*ancestor);
    117107
     108        if (is<ScrollingTreeFixedNode>(*ancestor) || is<ScrollingTreeStickyNode>(*ancestor)) {
     109            // FIXME: Do we need scrolling tree nodes at all for nested cases?
     110            return m_constraints.layerPositionAtLastLayout();
     111        }
     112    }
     113    ASSERT_NOT_REACHED();
     114    return m_constraints.layerPositionAtLastLayout();
     115}
     116
     117void ScrollingTreeStickyNode::applyLayerPositions()
     118{
    118119    auto layerPosition = computeLayerPosition();
    119120
     
    121122
    122123    [m_layer _web_setLayerTopLeftPosition:layerPosition - m_constraints.alignmentOffset()];
     124}
     125
     126FloatSize ScrollingTreeStickyNode::scrollDeltaSinceLastCommit() const
     127{
     128    auto layerPosition = computeLayerPosition();
     129    return layerPosition - m_constraints.layerPositionAtLastLayout();
    123130}
    124131
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r246278 r246367  
    30533053
    30543054    // FIXME: Handle fixed inside of a transform, which should not behave as fixed.
    3055     for (auto* stackingContext = layer.stackingContext(); stackingContext; stackingContext = stackingContext->stackingContext()) {
    3056         if (stackingContext->isComposited() && stackingContext->renderer().isFixedPositioned())
     3055    for (auto* ancestor = layer.parent(); ancestor; ancestor = ancestor->parent()) {
     3056        if (ancestor->hasCompositedScrollableOverflow())
     3057            return true;
     3058        if (ancestor->isStackingContext() && ancestor->isComposited() && ancestor->renderer().isFixedPositioned())
    30573059            return false;
    30583060    }
Note: See TracChangeset for help on using the changeset viewer.