Title: [284448] trunk
Revision
284448
Author
commit-qu...@webkit.org
Date
2021-10-19 06:46:40 -0700 (Tue, 19 Oct 2021)

Log Message

[css-scroll-snap] Triggering a layout during scroll causes jittery scrolling on iOS
https://bugs.webkit.org/show_bug.cgi?id=173887
<rdar://problem/67153673>

Patch by Martin Robinson <mrobin...@igalia.com> on 2021-10-19
Reviewed by Simon Fraser.

Source/WebKit:

Tests: fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html
       fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html

Ensure that when the root node is scrolling, it is added to the list of nodes
with an active user scroll. This prevents the web process from resnapping during
layout when the user is actively scrolling.

* UIProcess/API/ios/WKWebViewIOS.mm:
(-[WKWebView scrollViewWillBeginDragging:]): Call RemoteScrollingCoordinatorProxy::setRootNodeIsInUserScroll
when a scdroll starts and ends.
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h: Added method declaration.
* UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
(WebKit::RemoteScrollingCoordinatorProxy::setRootNodeIsInUserScroll): Added setRootNodeIsInUserScroll method.

LayoutTests:

* fast/scrolling/ios/scroll-snap-with-relayouts-horizontal-expected.txt: Added.
* fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html: Added.
* fast/scrolling/ios/scroll-snap-with-relayouts-vertical-expected.txt: Added.
* fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (284447 => 284448)


--- trunk/LayoutTests/ChangeLog	2021-10-19 13:40:40 UTC (rev 284447)
+++ trunk/LayoutTests/ChangeLog	2021-10-19 13:46:40 UTC (rev 284448)
@@ -1,3 +1,16 @@
+2021-10-19  Martin Robinson  <mrobin...@igalia.com>
+
+        [css-scroll-snap] Triggering a layout during scroll causes jittery scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=173887
+        <rdar://problem/67153673>
+
+        Reviewed by Simon Fraser.
+
+        * fast/scrolling/ios/scroll-snap-with-relayouts-horizontal-expected.txt: Added.
+        * fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html: Added.
+        * fast/scrolling/ios/scroll-snap-with-relayouts-vertical-expected.txt: Added.
+        * fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html: Added.
+
 2021-10-19  Rob Buis  <rb...@igalia.com>
 
         Remove support for some SVG properties

Added: trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-horizontal-expected.txt (0 => 284448)


--- trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-horizontal-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-horizontal-expected.txt	2021-10-19 13:46:40 UTC (rev 284448)
@@ -0,0 +1,6 @@
+PASS horizontal drag snapped to next snap point
+PASS relayouts should not caused the scroll area to snap back
+PASS successfullyParsed is true
+
+TEST COMPLETE
+980

Added: trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html (0 => 284448)


--- trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html	2021-10-19 13:46:40 UTC (rev 284448)
@@ -0,0 +1,74 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true AsyncOverflowScrollingEnabled=true AsyncFrameScrollingEnabled=true ] -->
+<html>
+    <head>
+        <title>Dragging a view should not snap back when the scroll event triggers a relayout</title>
+        <style type="text/css">
+            html {
+                scroll-snap-type: both mandatory
+            }
+
+            html, body {
+                margin: 0;
+                height: 100%;
+                width: 100%;
+            }
+
+            .horizontal-drawer {
+                width: 500%;
+                height: 100%;
+            }
+
+            .block {
+                float: left;
+                height: 100%;
+                width: 20%;
+                scroll-snap-align: start;
+            }
+
+            #console, #output {
+                position: fixed;
+                top: 0px;
+                left: 0px;
+            }
+        </style>
+        <script src=""
+        <script src=""
+        <script>
+        window.jsTestIsAsync = true;
+
+        async function onLoad()
+        {
+            let sawZero = false;
+            window.addEventListener('scroll', () => {
+                document.getElementById('output').innerText = document.scrollingElement.scrollLeft;
+                sawZero ||= document.scrollingElement.scrollLeft == 0;
+            })
+
+            if (window.eventSender == undefined) {
+                document.getElementById('console').innerText = "A scroll drag should not snap until user interaction is finished.";
+                return;
+            }
+
+            try {
+                await UIHelper.dragFromPointToPoint(150, 150, 50, 150, 0.1);
+                await UIHelper.waitForTargetScrollAnimationToSettle(document.scrollingElement);
+                expectTrue(document.scrollingElement.scrollLeft == window.innerWidth, "horizontal drag snapped to next snap point");
+                expectTrue(sawZero === false, "relayouts should not caused the scroll area to snap back");
+            } catch (e) {
+                console.log(e);
+            } finally {
+                finishJSTest();
+            }
+        }
+        </script>
+    </head>
+    <body _onload_="onLoad();">
+        <div class="horizontal-drawer">
+            <div class="block" style="background: #80475E"></div>
+            <div class="block" style="background: #CC5A71"></div>
+            <div class="block" style="background: #80475E"></div>
+        </div>
+        <p id="console"></p>
+        <p id="output"></p>
+    </body>
+</html>

Added: trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-vertical-expected.txt (0 => 284448)


--- trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-vertical-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-vertical-expected.txt	2021-10-19 13:46:40 UTC (rev 284448)
@@ -0,0 +1,6 @@
+PASS vertical drag snapped to next snap point
+PASS relayouts should not have snapped back
+PASS successfullyParsed is true
+
+TEST COMPLETE
+1678

Added: trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html (0 => 284448)


--- trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html	                        (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html	2021-10-19 13:46:40 UTC (rev 284448)
@@ -0,0 +1,71 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true AsyncOverflowScrollingEnabled=true AsyncFrameScrollingEnabled=true ] -->
+<html>
+    <head>
+        <title>Dragging a view should not snap back when the scroll event triggers a relayout</title>
+        <style type="text/css">
+            html {
+                scroll-snap-type: both mandatory
+            }
+
+            html, body {
+                margin: 0;
+                height: 100%;
+                width: 100%;
+            }
+
+            .horizontal-drawer {
+                width: 500%;
+                height: 100%;
+            }
+
+            .block {
+                height: 100%;
+                width: 100%;
+                scroll-snap-align: start;
+            }
+
+            #console, #output {
+                position: fixed;
+                top: 0px;
+                left: 0px;
+            }
+        </style>
+        <script src=""
+        <script src=""
+        <script>
+        window.jsTestIsAsync = true;
+
+        async function onLoad()
+        {
+            let sawZero = false;
+            window.addEventListener('scroll', () => {
+                document.getElementById('output').innerText = document.scrollingElement.scrollTop;
+                sawZero ||= document.scrollingElement.scrollTop == 0;
+            })
+
+            if (window.eventSender == undefined) {
+                document.getElementById('console').innerText = "A scroll drag should not snap until user interaction is finished.";
+                return;
+            }
+
+            try {
+                await UIHelper.dragFromPointToPoint(150, 150, 150, 50, 0.1);
+                await UIHelper.waitForTargetScrollAnimationToSettle(document.scrollingElement);
+                expectTrue(document.scrollingElement.scrollTop == window.innerHeight, "vertical drag snapped to next snap point");
+                expectTrue(sawZero === false, "relayouts should not have snapped back");
+            } catch (e) {
+                console.log(e);
+            } finally {
+                finishJSTest();
+            }
+        }
+        </script>
+    </head>
+    <body _onload_="onLoad();">
+        <div class="block" style="background: #CC5A71"></div>
+        <div class="block" style="background: #80475E"></div>
+        <div class="block" style="background: #CC5A71"></div>
+        <p id="console"></p>
+        <p id="output"></p>
+    </body>
+</html>

Modified: trunk/Source/WebKit/ChangeLog (284447 => 284448)


--- trunk/Source/WebKit/ChangeLog	2021-10-19 13:40:40 UTC (rev 284447)
+++ trunk/Source/WebKit/ChangeLog	2021-10-19 13:46:40 UTC (rev 284448)
@@ -1,3 +1,25 @@
+2021-10-19  Martin Robinson  <mrobin...@igalia.com>
+
+        [css-scroll-snap] Triggering a layout during scroll causes jittery scrolling on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=173887
+        <rdar://problem/67153673>
+
+        Reviewed by Simon Fraser.
+
+        Tests: fast/scrolling/ios/scroll-snap-with-relayouts-horizontal.html
+               fast/scrolling/ios/scroll-snap-with-relayouts-vertical.html
+
+        Ensure that when the root node is scrolling, it is added to the list of nodes
+        with an active user scroll. This prevents the web process from resnapping during
+        layout when the user is actively scrolling.
+
+        * UIProcess/API/ios/WKWebViewIOS.mm:
+        (-[WKWebView scrollViewWillBeginDragging:]): Call RemoteScrollingCoordinatorProxy::setRootNodeIsInUserScroll
+        when a scdroll starts and ends.
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h: Added method declaration.
+        * UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
+        (WebKit::RemoteScrollingCoordinatorProxy::setRootNodeIsInUserScroll): Added setRootNodeIsInUserScroll method.
+
 2021-10-19  Youenn Fablet  <you...@apple.com>
 
         getDisplayMedia MediaStreamTrack.applyConstraints behavior regressed in Safari 15

Modified: trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm (284447 => 284448)


--- trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm	2021-10-19 13:40:40 UTC (rev 284447)
+++ trunk/Source/WebKit/UIProcess/API/ios/WKWebViewIOS.mm	2021-10-19 13:46:40 UTC (rev 284448)
@@ -1631,6 +1631,8 @@
     CGFloat scrollDecelerationFactor = (coordinator && coordinator->shouldSetScrollViewDecelerationRateFast()) ? UIScrollViewDecelerationRateFast : UIScrollViewDecelerationRateNormal;
     scrollView.horizontalScrollDecelerationFactor = scrollDecelerationFactor;
     scrollView.verticalScrollDecelerationFactor = scrollDecelerationFactor;
+
+    coordinator->setRootNodeIsInUserScroll(true);
 #endif
 }
 
@@ -1641,6 +1643,10 @@
 
     [self _scheduleVisibleContentRectUpdate];
     [_contentView didFinishScrolling];
+
+#if ENABLE(ASYNC_SCROLLING)
+    _page->scrollingCoordinatorProxy()->setRootNodeIsInUserScroll(false);
+#endif
 }
 
 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h (284447 => 284448)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h	2021-10-19 13:40:40 UTC (rev 284447)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h	2021-10-19 13:46:40 UTC (rev 284448)
@@ -99,6 +99,7 @@
     bool hasActiveSnapPoint() const;
     CGPoint nearestActiveContentInsetAdjustedSnapOffset(CGFloat topInset, const CGPoint&) const;
     bool shouldSetScrollViewDecelerationRateFast() const;
+    void setRootNodeIsInUserScroll(bool);
 #endif
 
     String scrollingTreeAsText() const;

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm (284447 => 284448)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm	2021-10-19 13:40:40 UTC (rev 284447)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm	2021-10-19 13:46:40 UTC (rev 284448)
@@ -218,6 +218,20 @@
     return shouldSnapForMainFrameScrolling(ScrollEventAxis::Horizontal) || shouldSnapForMainFrameScrolling(ScrollEventAxis::Vertical);
 }
 
+void RemoteScrollingCoordinatorProxy::setRootNodeIsInUserScroll(bool value)
+{
+    ScrollingTreeNode* root = m_scrollingTree->rootNode();
+    if (!root || !root->isFrameScrollingNode())
+        return;
+
+    if (value)
+        m_uiState.addNodeWithActiveUserScroll(root->scrollingNodeID());
+    else
+        m_uiState.removeNodeWithActiveUserScroll(root->scrollingNodeID());
+
+    sendUIStateChangedIfNecessary();
+}
+
 bool RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling(ScrollEventAxis axis) const
 {
     ScrollingTreeNode* root = m_scrollingTree->rootNode();
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to