Title: [284084] trunk
Revision
284084
Author
[email protected]
Date
2021-10-13 00:59:14 -0700 (Wed, 13 Oct 2021)

Log Message

Sticky element inside another sticky element does not redraw properly on scroll
https://bugs.webkit.org/show_bug.cgi?id=199915
<rdar://problem/53375284>

Reviewed by Simon Fraser.

When calculating layer position for sticky nodes in the scrolling tree, take into
account situations where the sticky parents of sticky nodes don't stick (due to
sizing). This was handled properly in layout, but not in the scrolling tree, which
caused these kinds of nodes to jump around.

Source/WebCore:

Test: scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html

* page/scrolling/ScrollingStateStickyNode.cpp:
(WebCore::ScrollingStateStickyNode::computeLayerPosition const):
(WebCore::ScrollingStateStickyNode::scrollDeltaSinceLastCommit const):
* page/scrolling/ScrollingStateStickyNode.h:
* page/scrolling/cocoa/ScrollingTreeStickyNode.mm:
(WebCore::ScrollingTreeStickyNode::computeLayerPosition const):
* page/scrolling/nicosia/ScrollingTreeStickyNode.cpp:
(WebCore::ScrollingTreeStickyNode::computeLayerPosition const):
(WebCore::ScrollingTreeStickyNode::scrollDeltaSinceLastCommit const):
* page/scrolling/nicosia/ScrollingTreeStickyNode.h:

LayoutTests:

* scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent-expected.html: Added.
* scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (284083 => 284084)


--- trunk/LayoutTests/ChangeLog	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/LayoutTests/ChangeLog	2021-10-13 07:59:14 UTC (rev 284084)
@@ -1,3 +1,19 @@
+2021-10-13  Martin Robinson  <[email protected]>
+
+        Sticky element inside another sticky element does not redraw properly on scroll
+        https://bugs.webkit.org/show_bug.cgi?id=199915
+        <rdar://problem/53375284>
+
+        Reviewed by Simon Fraser.
+
+        When calculating layer position for sticky nodes in the scrolling tree, take into
+        account situations where the sticky parents of sticky nodes don't stick (due to
+        sizing). This was handled properly in layout, but not in the scrolling tree, which
+        caused these kinds of nodes to jump around.
+
+        * scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent-expected.html: Added.
+        * scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html: Added.
+
 2021-10-12  Arcady Goldmints-Orlov  <[email protected]>
 
         [GTK] Update test expectations for CSS web platform tests.

Added: trunk/LayoutTests/scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent-expected.html (0 => 284084)


--- trunk/LayoutTests/scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent-expected.html	2021-10-13 07:59:14 UTC (rev 284084)
@@ -0,0 +1,30 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ AsyncOverflowScrollingEnabled=true ] -->
+<html>
+    <head>
+        <style>
+            html, body {
+                margin: 0px;
+            }
+            ::-webkit-scrollbar {
+                display: none;
+            }
+            .sticky {
+                position: sticky;
+                top: 0px;
+            }
+            .parent {
+                height: 150vh;
+            }
+            .child {
+                background: green;
+                height: 4vh;
+                width: 4vh;
+            }
+        <script src=""
+        </style>
+    </head>
+    <body>
+    <div class="parent">
+        <div class="sticky child"></div>
+    </body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html (0 => 284084)


--- trunk/LayoutTests/scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html	2021-10-13 07:59:14 UTC (rev 284084)
@@ -0,0 +1,67 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ AsyncOverflowScrollingEnabled=true ] -->
+<html class="reftest-wait">
+    <head>
+        <style>
+            html, body {
+                margin: 0px;
+            }
+            ::-webkit-scrollbar {
+                display: none;
+            }
+            .sticky {
+                position: sticky;
+                top: 0px;
+            }
+            .parent {
+                height: 150vh;
+            }
+            .child {
+                background: green;
+                height: 4vh;
+                width: 4vh;
+            }
+        </style>
+        <script src=""
+        <script>
+            async function runTest() {
+                if (!window.testRunner) {
+                    return;
+                }
+
+                try {
+                    await UIHelper.delayFor(0);
+
+                    eventSender.monitorWheelEvents();
+                    eventSender.mouseMoveTo(10, 10);
+
+                    // `direction` is a two-element array with a one in the appropriate direction.
+                    let scrollMotions = [
+                        [0, -1, 'began', 'none'],
+                        [0, -1, 'changed', 'none'],
+                        [0, -1, 'changed', 'none'],
+                        [0, -1, 'changed', 'none'],
+                        [0, 0, 'ended', 'none'],
+                        [0, -1, 'none', 'begin'],
+                        [0, -1, 'none', 'continue'],
+                        [0, 0, 'none', 'end'],
+                    ];
+                    scrollMotions.forEach((callArguments) => {
+                        eventSender.mouseScrollByWithWheelAndMomentumPhases(...callArguments);
+                    });
+
+                    await UIHelper.waitForScrollCompletion();
+                } catch (e) {
+                    console.log(e);
+                } finally {
+                    document.documentElement.classList.remove("reftest-wait");$
+                }
+            }
+        </script>
+    </head>
+    <body _onload_="runTest();">
+    <div class="sticky parent">
+        <div class="sticky child"></div>
+    </div>
+    <div id="console"></div>
+    </body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (284083 => 284084)


--- trunk/Source/WebCore/ChangeLog	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/Source/WebCore/ChangeLog	2021-10-13 07:59:14 UTC (rev 284084)
@@ -1,3 +1,29 @@
+2021-10-13  Martin Robinson  <[email protected]>
+
+        Sticky element inside another sticky element does not redraw properly on scroll
+        https://bugs.webkit.org/show_bug.cgi?id=199915
+        <rdar://problem/53375284>
+
+        Reviewed by Simon Fraser.
+
+        When calculating layer position for sticky nodes in the scrolling tree, take into
+        account situations where the sticky parents of sticky nodes don't stick (due to
+        sizing). This was handled properly in layout, but not in the scrolling tree, which
+        caused these kinds of nodes to jump around.
+
+        Test: scrollingcoordinator/mac/nested-sticky-with-nonsticking-sticky-parent.html
+
+        * page/scrolling/ScrollingStateStickyNode.cpp:
+        (WebCore::ScrollingStateStickyNode::computeLayerPosition const):
+        (WebCore::ScrollingStateStickyNode::scrollDeltaSinceLastCommit const):
+        * page/scrolling/ScrollingStateStickyNode.h:
+        * page/scrolling/cocoa/ScrollingTreeStickyNode.mm:
+        (WebCore::ScrollingTreeStickyNode::computeLayerPosition const):
+        * page/scrolling/nicosia/ScrollingTreeStickyNode.cpp:
+        (WebCore::ScrollingTreeStickyNode::computeLayerPosition const):
+        (WebCore::ScrollingTreeStickyNode::scrollDeltaSinceLastCommit const):
+        * page/scrolling/nicosia/ScrollingTreeStickyNode.h:
+
 2021-10-12  Jer Noble  <[email protected]>
 
         [Build-time perf] Forward-declare more things in Document.h

Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp (284083 => 284084)


--- trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.cpp	2021-10-13 07:59:14 UTC (rev 284084)
@@ -86,6 +86,7 @@
 FloatPoint ScrollingStateStickyNode::computeLayerPosition(const LayoutRect& viewportRect) const
 {
     // This logic follows ScrollingTreeStickyNode::computeLayerPosition().
+    FloatSize offsetFromStickyAncestors;
     auto computeLayerPositionForScrollingNode = [&](ScrollingStateNode& scrollingStateNode) {
         FloatRect constrainingRect;
         if (is<ScrollingStateFrameScrollingNode>(scrollingStateNode))
@@ -94,6 +95,7 @@
             auto& overflowScrollingNode = downcast<ScrollingStateOverflowScrollingNode>(scrollingStateNode);
             constrainingRect = FloatRect(overflowScrollingNode.scrollPosition(), m_constraints.constrainingRectAtLastLayout().size());
         }
+        constrainingRect.move(offsetFromStickyAncestors);
         return m_constraints.layerPositionForConstrainingRect(constrainingRect);
     };
 
@@ -110,7 +112,10 @@
         if (is<ScrollingStateScrollingNode>(*ancestor))
             return computeLayerPositionForScrollingNode(*ancestor);
 
-        if (is<ScrollingStateFixedNode>(*ancestor) || is<ScrollingStateStickyNode>(*ancestor)) {
+        if (is<ScrollingStateStickyNode>(*ancestor))
+            offsetFromStickyAncestors += downcast<ScrollingStateStickyNode>(*ancestor).scrollDeltaSinceLastCommit(viewportRect);
+
+        if (is<ScrollingStateFixedNode>(*ancestor)) {
             // FIXME: Do we need scrolling tree nodes at all for nested cases?
             return m_constraints.layerPositionAtLastLayout();
         }
@@ -143,6 +148,12 @@
     }
 }
 
+FloatSize ScrollingStateStickyNode::scrollDeltaSinceLastCommit(const LayoutRect& viewportRect) const
+{
+    auto layerPosition = computeLayerPosition(viewportRect);
+    return layerPosition - m_constraints.layerPositionAtLastLayout();
+}
+
 void ScrollingStateStickyNode::dumpProperties(TextStream& ts, ScrollingStateTreeAsTextBehavior behavior) const
 {
     ts << "Sticky node";

Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h (284083 => 284084)


--- trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateStickyNode.h	2021-10-13 07:59:14 UTC (rev 284084)
@@ -53,6 +53,7 @@
 
     FloatPoint computeLayerPosition(const LayoutRect& viewportRect) const;
     void reconcileLayerPositionForViewportRect(const LayoutRect& viewportRect, ScrollingLayerPositionAction) final;
+    FloatSize scrollDeltaSinceLastCommit(const LayoutRect& viewportRect) const;
 
     void dumpProperties(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const final;
     OptionSet<ScrollingStateNode::Property> applicableProperties() const final;

Modified: trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm (284083 => 284084)


--- trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreeStickyNode.mm	2021-10-13 07:59:14 UTC (rev 284084)
@@ -69,6 +69,7 @@
 
 FloatPoint ScrollingTreeStickyNode::computeLayerPosition() const
 {
+    FloatSize offsetFromStickyAncestors;
     auto computeLayerPositionForScrollingNode = [&](ScrollingTreeNode& scrollingNode) {
         FloatRect constrainingRect;
         if (is<ScrollingTreeFrameScrollingNode>(scrollingNode)) {
@@ -79,6 +80,7 @@
             constrainingRect = m_constraints.constrainingRectAtLastLayout();
             constrainingRect.move(overflowScrollingNode.scrollDeltaSinceLastCommit());
         }
+        constrainingRect.move(-offsetFromStickyAncestors);
         return m_constraints.layerPositionForConstrainingRect(constrainingRect);
     };
 
@@ -95,7 +97,10 @@
         if (is<ScrollingTreeScrollingNode>(*ancestor))
             return computeLayerPositionForScrollingNode(*ancestor);
 
-        if (is<ScrollingTreeFixedNode>(*ancestor) || is<ScrollingTreeStickyNode>(*ancestor)) {
+        if (is<ScrollingTreeStickyNode>(*ancestor))
+            offsetFromStickyAncestors += downcast<ScrollingTreeStickyNode>(*ancestor).scrollDeltaSinceLastCommit();
+
+        if (is<ScrollingTreeFixedNode>(*ancestor)) {
             // FIXME: Do we need scrolling tree nodes at all for nested cases?
             return m_constraints.layerPositionAtLastLayout();
         }

Modified: trunk/Source/WebCore/page/scrolling/nicosia/ScrollingTreeStickyNode.cpp (284083 => 284084)


--- trunk/Source/WebCore/page/scrolling/nicosia/ScrollingTreeStickyNode.cpp	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/Source/WebCore/page/scrolling/nicosia/ScrollingTreeStickyNode.cpp	2021-10-13 07:59:14 UTC (rev 284084)
@@ -111,6 +111,7 @@
 
 FloatPoint ScrollingTreeStickyNode::computeLayerPosition() const
 {
+    FloatSize offsetFromStickyAncestors;
     auto computeLayerPositionForScrollingNode = [&](ScrollingTreeNode& scrollingNode) {
         FloatRect constrainingRect;
         if (is<ScrollingTreeFrameScrollingNode>(scrollingNode)) {
@@ -121,6 +122,7 @@
             constrainingRect = m_constraints.constrainingRectAtLastLayout();
             constrainingRect.move(overflowScrollingNode.scrollDeltaSinceLastCommit());
         }
+        constrainingRect.move(-offsetFromStickyAncestors);
         return m_constraints.layerPositionForConstrainingRect(constrainingRect);
     };
 
@@ -137,7 +139,10 @@
         if (is<ScrollingTreeScrollingNode>(*ancestor))
             return computeLayerPositionForScrollingNode(*ancestor);
 
-        if (is<ScrollingTreeFixedNode>(*ancestor) || is<ScrollingTreeStickyNode>(*ancestor)) {
+        if (is<ScrollingTreeStickyNode>(*ancestor))
+            offsetFromStickyAncestors += downcast<ScrollingTreeStickyNode>(*ancestor).scrollDeltaSinceLastCommit();
+
+        if (is<ScrollingTreeFixedNode>(*ancestor)) {
             // FIXME: Do we need scrolling tree nodes at all for nested cases?
             return m_constraints.layerPositionAtLastLayout();
         }
@@ -146,6 +151,12 @@
     return m_constraints.layerPositionAtLastLayout();
 }
 
+FloatSize ScrollingTreeStickyNode::scrollDeltaSinceLastCommit() const
+{
+    auto layerPosition = computeLayerPosition();
+    return layerPosition - m_constraints.layerPositionAtLastLayout();
+}
+
 } // namespace WebCore
 
 #endif // ENABLE(ASYNC_SCROLLING) && USE(NICOSIA)

Modified: trunk/Source/WebCore/page/scrolling/nicosia/ScrollingTreeStickyNode.h (284083 => 284084)


--- trunk/Source/WebCore/page/scrolling/nicosia/ScrollingTreeStickyNode.h	2021-10-13 07:53:47 UTC (rev 284083)
+++ trunk/Source/WebCore/page/scrolling/nicosia/ScrollingTreeStickyNode.h	2021-10-13 07:59:14 UTC (rev 284084)
@@ -54,6 +54,7 @@
     void dumpProperties(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const override;
 
     FloatPoint computeLayerPosition() const;
+    FloatSize scrollDeltaSinceLastCommit() const;
 
     StickyPositionViewportConstraints m_constraints;
     RefPtr<Nicosia::CompositionLayer> m_layer;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to