Title: [243926] trunk
Revision
243926
Author
[email protected]
Date
2019-04-04 22:18:17 -0700 (Thu, 04 Apr 2019)

Log Message

[iOS WK2] REGRESSION (r242687): Programmatic scroll of overflow scroll results in bad rendering
https://bugs.webkit.org/show_bug.cgi?id=195584

Reviewed by Zalan Bujtas.

Source/WebCore:

Push data to the scrolling tree about whether an overflow:scroll scroll was programmatic, by having
RenderLayer::scrollToOffset() call into AsyncScrollingCoordinator::requestScrollPositionUpdate(),
just as we do for frames.

AsyncScrollingCoordinator::requestScrollPositionUpdate() is generalized to take any ScrollableArea.

Fix an assumption in the ScrollingTree that we only care about programmatic scrolls on the root node.
ScrollingTree::commitTreeState() no longer sets isHandlingProgrammaticScroll; instead,
callers of ScrollingTreeScrollingNode::scrollTo() pass a ScrollType. Commit functions pass
ScrollType::Programmatic when handling RequestedScrollPosition changes as necessary.

Programmatic scrolls need to get to the scrolling tree in the UI process so that we update
the tree's notion of scroll position, and trigger actual UIScrollView scrolls (layers may have
already been put in the right locations, but the UI process needs to know that a scroll happened).
However, we need to prevent notifications from programmatic scrolls getting back to the
web process, because this causes jumpiness. This is done via an early return in
RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll().

Tests: scrollingcoordinator/ios/programmatic-overflow-scroll.html
       scrollingcoordinator/ios/programmatic-page-scroll.html

* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::requestScrollPositionUpdate):
* page/scrolling/AsyncScrollingCoordinator.h:
* page/scrolling/ScrollingCoordinator.h:
(WebCore::ScrollingCoordinator::requestScrollPositionUpdate):
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::commitTreeState):
(WebCore::ScrollingTree::isHandlingProgrammaticScroll): Deleted.
* page/scrolling/ScrollingTree.h:
(WebCore::ScrollingTree::isHandlingProgrammaticScroll const):
(WebCore::ScrollingTree::setIsHandlingProgrammaticScroll):
* page/scrolling/ScrollingTreeScrollingNode.cpp:
(WebCore::ScrollingTreeScrollingNode::scrollBy):
(WebCore::ScrollingTreeScrollingNode::scrollTo):
* page/scrolling/ScrollingTreeScrollingNode.h:
* page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm:
(WebCore::ScrollingTreeFrameScrollingNodeMac::commitStateAfterChildren):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::scrollToOffset):
(WebCore::RenderLayer::scrollingNodeID const):
* rendering/RenderLayer.h:
* rendering/RenderMarquee.cpp:
(WebCore::RenderMarquee::timerFired):

Source/WebKit:

Push data to the scrolling tree about whether an overflow:scroll scroll was programmatic, by having
RenderLayer::scrollToOffset() call into AsyncScrollingCoordinator::requestScrollPositionUpdate(),
just as we do for frames.

AsyncScrollingCoordinator::requestScrollPositionUpdate() is generalized to take any ScrollableArea.

Fix an assumption in the ScrollingTree that we only care about programmatic scrolls on the root node.
ScrollingTree::commitTreeState() no longer sets isHandlingProgrammaticScroll; instead,
callers of ScrollingTreeScrollingNode::scrollTo() pass a ScrollType. Commit functions pass
ScrollType::Programmatic when handling RequestedScrollPosition changes as necessary.

Programmatic scrolls need to get to the scrolling tree in the UI process so that we update
the tree's notion of scroll position, and trigger actual UIScrollView scrolls (layers may have
already been put in the right locations, but the UI process needs to know that a scroll happened).
However, we need to prevent notifications from programmatic scrolls getting back to the
web process, because this causes jumpiness. This is done via an early return in
RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll().

* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
(WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll):
* UIProcess/RemoteLayerTree/ios/ScrollingTreeFrameScrollingNodeRemoteIOS.mm:
(WebKit::ScrollingTreeFrameScrollingNodeRemoteIOS::commitStateAfterChildren): Subframe nodes have
a delegate, and that will take care of the requestedScrollPosition update.
* UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h:
* UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
(WebKit::ScrollingTreeOverflowScrollingNodeIOS::commitStateAfterChildren):
* UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
(WebKit::ScrollingTreeScrollingNodeDelegateIOS::commitStateAfterChildren):

LayoutTests:

Testing of programmatic scrolls in frames is prevented by webkit.org/b/196635.

* scrollingcoordinator/ios/programmatic-overflow-scroll-expected.html: Added.
* scrollingcoordinator/ios/programmatic-overflow-scroll.html: Added.
* scrollingcoordinator/ios/programmatic-page-scroll-expected.html: Added.
* scrollingcoordinator/ios/programmatic-page-scroll.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (243925 => 243926)


--- trunk/LayoutTests/ChangeLog	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/LayoutTests/ChangeLog	2019-04-05 05:18:17 UTC (rev 243926)
@@ -1,3 +1,17 @@
+2019-04-04  Simon Fraser  <[email protected]>
+
+        [iOS WK2] REGRESSION (r242687): Programmatic scroll of overflow scroll results in bad rendering
+        https://bugs.webkit.org/show_bug.cgi?id=195584
+
+        Reviewed by Zalan Bujtas.
+
+        Testing of programmatic scrolls in frames is prevented by webkit.org/b/196635.
+
+        * scrollingcoordinator/ios/programmatic-overflow-scroll-expected.html: Added.
+        * scrollingcoordinator/ios/programmatic-overflow-scroll.html: Added.
+        * scrollingcoordinator/ios/programmatic-page-scroll-expected.html: Added.
+        * scrollingcoordinator/ios/programmatic-page-scroll.html: Added.
+
 2019-04-04  Shawn Roberts  <[email protected]>
 
         Unreviewed, rolling out r243868.

Added: trunk/LayoutTests/scrollingcoordinator/ios/programmatic-overflow-scroll-expected.html (0 => 243926)


--- trunk/LayoutTests/scrollingcoordinator/ios/programmatic-overflow-scroll-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/programmatic-overflow-scroll-expected.html	2019-04-05 05:18:17 UTC (rev 243926)
@@ -0,0 +1,33 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width">
+    <style>
+        #scroller {
+            height: 300px;
+            width: 300px;
+            overflow: scroll;
+            -webkit-overflow-scrolling: touch;
+        }
+        
+        .box {
+            width: 100%;
+            height: 100%;
+        }
+        
+        .top {
+            background-color: green;
+        }
+
+        .bottom {
+            background-color: green;
+        }
+    </style>
+</head>
+<body>
+    <div id="scroller">
+        <div class="top box"></div>
+        <div class="bottom box"></div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/programmatic-overflow-scroll.html (0 => 243926)


--- trunk/LayoutTests/scrollingcoordinator/ios/programmatic-overflow-scroll.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/programmatic-overflow-scroll.html	2019-04-05 05:18:17 UTC (rev 243926)
@@ -0,0 +1,42 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width">
+    <style>
+        #scroller {
+            height: 300px;
+            width: 300px;
+            overflow: scroll;
+            -webkit-overflow-scrolling: touch;
+        }
+        
+        .box {
+            width: 100%;
+            height: 100%;
+        }
+        
+        .top {
+            background-color: red;
+        }
+
+        .bottom {
+            background-color: green;
+        }
+
+    </style>
+    <script>
+        function doTest()
+        {
+            scroller.scrollTop = 500;
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div id="scroller">
+        <div class="top box"></div>
+        <div class="bottom box"></div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/programmatic-page-scroll-expected.html (0 => 243926)


--- trunk/LayoutTests/scrollingcoordinator/ios/programmatic-page-scroll-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/programmatic-page-scroll-expected.html	2019-04-05 05:18:17 UTC (rev 243926)
@@ -0,0 +1,52 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width">
+    <style>
+        body {
+            height: 2000px;
+        }
+        #scroller {
+            height: 300px;
+            width: 300px;
+            overflow: scroll;
+            -webkit-overflow-scrolling: touch;
+        }
+        
+        .box {
+            width: 100%;
+            height: 100%;
+        }
+        
+        .top {
+            background-color: red;
+        }
+
+        .bottom {
+            background-color: green;
+        }
+
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        function doTest()
+        {
+            setTimeout(() => {
+                document.scrollingElement.scrollTop = 200;
+            }, 2000);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div id="scroller">
+        <div class="top box"></div>
+        <div class="bottom box"></div>
+    </div>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/programmatic-page-scroll.html (0 => 243926)


--- trunk/LayoutTests/scrollingcoordinator/ios/programmatic-page-scroll.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/programmatic-page-scroll.html	2019-04-05 05:18:17 UTC (rev 243926)
@@ -0,0 +1,52 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name="viewport" content="width=device-width">
+    <style>
+        body {
+            height: 2000px;
+        }
+        #scroller {
+            height: 300px;
+            width: 300px;
+            overflow: scroll;
+            -webkit-overflow-scrolling: touch;
+        }
+        
+        .box {
+            width: 100%;
+            height: 100%;
+        }
+        
+        .top {
+            background-color: red;
+        }
+
+        .bottom {
+            background-color: green;
+        }
+
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        function doTest()
+        {
+            setTimeout(() => {
+                document.scrollingElement.scrollTop = 200;
+            }, 2000);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div id="scroller">
+        <div class="top box"></div>
+        <div class="bottom box"></div>
+    </div>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (243925 => 243926)


--- trunk/Source/WebCore/ChangeLog	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/ChangeLog	2019-04-05 05:18:17 UTC (rev 243926)
@@ -1,3 +1,55 @@
+2019-04-04  Simon Fraser  <[email protected]>
+
+        [iOS WK2] REGRESSION (r242687): Programmatic scroll of overflow scroll results in bad rendering
+        https://bugs.webkit.org/show_bug.cgi?id=195584
+
+        Reviewed by Zalan Bujtas.
+
+        Push data to the scrolling tree about whether an overflow:scroll scroll was programmatic, by having
+        RenderLayer::scrollToOffset() call into AsyncScrollingCoordinator::requestScrollPositionUpdate(),
+        just as we do for frames.
+
+        AsyncScrollingCoordinator::requestScrollPositionUpdate() is generalized to take any ScrollableArea.
+
+        Fix an assumption in the ScrollingTree that we only care about programmatic scrolls on the root node.
+        ScrollingTree::commitTreeState() no longer sets isHandlingProgrammaticScroll; instead,
+        callers of ScrollingTreeScrollingNode::scrollTo() pass a ScrollType. Commit functions pass
+        ScrollType::Programmatic when handling RequestedScrollPosition changes as necessary.
+
+        Programmatic scrolls need to get to the scrolling tree in the UI process so that we update
+        the tree's notion of scroll position, and trigger actual UIScrollView scrolls (layers may have
+        already been put in the right locations, but the UI process needs to know that a scroll happened).
+        However, we need to prevent notifications from programmatic scrolls getting back to the
+        web process, because this causes jumpiness. This is done via an early return in
+        RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll().
+
+        Tests: scrollingcoordinator/ios/programmatic-overflow-scroll.html
+               scrollingcoordinator/ios/programmatic-page-scroll.html
+
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::AsyncScrollingCoordinator::requestScrollPositionUpdate):
+        * page/scrolling/AsyncScrollingCoordinator.h:
+        * page/scrolling/ScrollingCoordinator.h:
+        (WebCore::ScrollingCoordinator::requestScrollPositionUpdate):
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::commitTreeState):
+        (WebCore::ScrollingTree::isHandlingProgrammaticScroll): Deleted.
+        * page/scrolling/ScrollingTree.h:
+        (WebCore::ScrollingTree::isHandlingProgrammaticScroll const):
+        (WebCore::ScrollingTree::setIsHandlingProgrammaticScroll):
+        * page/scrolling/ScrollingTreeScrollingNode.cpp:
+        (WebCore::ScrollingTreeScrollingNode::scrollBy):
+        (WebCore::ScrollingTreeScrollingNode::scrollTo):
+        * page/scrolling/ScrollingTreeScrollingNode.h:
+        * page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm:
+        (WebCore::ScrollingTreeFrameScrollingNodeMac::commitStateAfterChildren):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::scrollToOffset):
+        (WebCore::RenderLayer::scrollingNodeID const):
+        * rendering/RenderLayer.h:
+        * rendering/RenderMarquee.cpp:
+        (WebCore::RenderMarquee::timerFired):
+
 2019-04-04  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, speculative fix for build failure

Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp	2019-04-05 05:18:17 UTC (rev 243926)
@@ -204,18 +204,26 @@
     node->setHorizontalScrollbarLayer(frameView.layerForHorizontalScrollbar());
 }
 
-bool AsyncScrollingCoordinator::requestScrollPositionUpdate(FrameView& frameView, const IntPoint& scrollPosition)
+bool AsyncScrollingCoordinator::requestScrollPositionUpdate(ScrollableArea& scrollableArea, const IntPoint& scrollPosition)
 {
     ASSERT(isMainThread());
     ASSERT(m_page);
 
-    if (!coordinatesScrollingForFrameView(frameView))
+    auto scrollingNodeID = scrollableArea.scrollingNodeID();
+    if (!scrollingNodeID)
         return false;
 
-    bool inPageCache = frameView.frame().document()->pageCacheState() != Document::NotInPageCache;
-    bool inProgrammaticScroll = frameView.currentScrollType() == ScrollType::Programmatic;
+    auto* frameView = frameViewForScrollingNode(scrollingNodeID);
+    if (!frameView)
+        return false;
+
+    if (!coordinatesScrollingForFrameView(*frameView))
+        return false;
+
+    bool inPageCache = frameView->frame().document()->pageCacheState() != Document::NotInPageCache;
+    bool inProgrammaticScroll = scrollableArea.currentScrollType() == ScrollType::Programmatic;
     if (inProgrammaticScroll || inPageCache)
-        updateScrollPositionAfterAsyncScroll(frameView.scrollingNodeID(), scrollPosition, { }, ScrollType::Programmatic, ScrollingLayerPositionAction::Set);
+        updateScrollPositionAfterAsyncScroll(scrollingNodeID, scrollPosition, { }, ScrollType::Programmatic, ScrollingLayerPositionAction::Set);
 
     // If this frame view's document is being put into the page cache, we don't want to update our
     // main frame scroll position. Just let the FrameView think that we did.
@@ -222,7 +230,7 @@
     if (inPageCache)
         return true;
 
-    auto* stateNode = downcast<ScrollingStateScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollingNodeID()));
+    auto* stateNode = downcast<ScrollingStateScrollingNode>(m_scrollingStateTree->stateNodeForID(scrollingNodeID));
     if (!stateNode)
         return false;
 

Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h	2019-04-05 05:18:17 UTC (rev 243926)
@@ -95,7 +95,7 @@
     WEBCORE_EXPORT void frameViewRootLayerDidChange(FrameView&) override;
     WEBCORE_EXPORT void frameViewEventTrackingRegionsChanged(FrameView&) override;
 
-    WEBCORE_EXPORT bool requestScrollPositionUpdate(FrameView&, const IntPoint&) override;
+    WEBCORE_EXPORT bool requestScrollPositionUpdate(ScrollableArea&, const IntPoint&) override;
 
     WEBCORE_EXPORT void applyScrollingTreeLayerPositions() override;
 

Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2019-04-05 05:18:17 UTC (rev 243926)
@@ -114,7 +114,7 @@
 
     // These virtual functions are currently unique to the threaded scrolling architecture. 
     virtual void commitTreeStateIfNeeded() { }
-    virtual bool requestScrollPositionUpdate(FrameView&, const IntPoint&) { return false; }
+    virtual bool requestScrollPositionUpdate(ScrollableArea&, const IntPoint&) { return false; }
     virtual ScrollingEventResult handleWheelEvent(FrameView&, const PlatformWheelEvent&) { return ScrollingEventResult::DidNotHandleEvent; }
 
     // Create an unparented node.

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-04-05 05:18:17 UTC (rev 243926)
@@ -166,9 +166,6 @@
             m_asyncFrameOrOverflowScrollingEnabled = scrollingStateTree->rootStateNode()->asyncFrameOrOverflowScrollingEnabled();
     }
     
-    bool scrollRequestIsProgammatic = rootNode ? rootNode->requestedScrollPositionRepresentsProgrammaticScroll() : false;
-    SetForScope<bool> changeHandlingProgrammaticScroll(m_isHandlingProgrammaticScroll, scrollRequestIsProgammatic);
-
     // unvisitedNodes starts with all nodes in the map; we remove nodes as we visit them. At the end, it's the unvisited nodes.
     // We can't use orphanNodes for this, because orphanNodes won't contain descendants of removed nodes.
     HashSet<ScrollingNodeID> unvisitedNodes;
@@ -404,11 +401,6 @@
     m_swipeState.rubberBandsAtBottom = canRubberBandAtBottom;
 }
 
-bool ScrollingTree::isHandlingProgrammaticScroll()
-{
-    return m_isHandlingProgrammaticScroll;
-}
-
 // Can be called from the main thread.
 void ScrollingTree::setScrollPinningBehavior(ScrollPinningBehavior pinning)
 {

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-04-05 05:18:17 UTC (rev 243926)
@@ -118,7 +118,8 @@
     // Can be called from any thread. Will update what edges allow rubber-banding.
     WEBCORE_EXPORT void setCanRubberBandState(bool canRubberBandAtLeft, bool canRubberBandAtRight, bool canRubberBandAtTop, bool canRubberBandAtBottom);
 
-    bool isHandlingProgrammaticScroll();
+    bool isHandlingProgrammaticScroll() const { return m_isHandlingProgrammaticScroll; }
+    void setIsHandlingProgrammaticScroll(bool isHandlingProgrammaticScroll) { m_isHandlingProgrammaticScroll = isHandlingProgrammaticScroll; }
     
     void setScrollPinningBehavior(ScrollPinningBehavior);
     WEBCORE_EXPORT ScrollPinningBehavior scrollPinningBehavior();
@@ -204,8 +205,8 @@
     SwipeState m_swipeState;
 
     unsigned m_fixedOrStickyNodeCount { 0 };
+    bool m_isHandlingProgrammaticScroll { false };
     bool m_scrollingPerformanceLoggingEnabled { false };
-    bool m_isHandlingProgrammaticScroll { false };
     bool m_asyncFrameOrOverflowScrollingEnabled { false };
 };
     

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp	2019-04-05 05:18:17 UTC (rev 243926)
@@ -152,14 +152,16 @@
 
 void ScrollingTreeScrollingNode::scrollBy(const FloatSize& delta, ScrollPositionClamp clamp)
 {
-    scrollTo(currentScrollPosition() + delta, clamp);
+    scrollTo(currentScrollPosition() + delta, ScrollType::User, clamp);
 }
 
-void ScrollingTreeScrollingNode::scrollTo(const FloatPoint& position, ScrollPositionClamp clamp)
+void ScrollingTreeScrollingNode::scrollTo(const FloatPoint& position, ScrollType scrollType, ScrollPositionClamp clamp)
 {
     if (position == m_currentScrollPosition)
         return;
 
+    scrollingTree().setIsHandlingProgrammaticScroll(scrollType == ScrollType::Programmatic);
+    
     m_currentScrollPosition = adjustedScrollPosition(position, clamp);
     
     LOG_WITH_STREAM(Scrolling, stream << "ScrollingTreeScrollingNode " << scrollingNodeID() << " scrollTo " << position << " (delta from last committed position " << (m_lastCommittedScrollPosition - m_currentScrollPosition) << ")");
@@ -166,6 +168,8 @@
 
     updateViewportForCurrentScrollPosition();
     currentScrollPositionChanged();
+
+    scrollingTree().setIsHandlingProgrammaticScroll(false);
 }
 
 void ScrollingTreeScrollingNode::currentScrollPositionChanged()

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h	2019-04-05 05:18:17 UTC (rev 243926)
@@ -57,7 +57,7 @@
     FloatPoint lastCommittedScrollPosition() const { return m_lastCommittedScrollPosition; }
 
     // These are imperative; they adjust the scrolling layers.
-    void scrollTo(const FloatPoint&, ScrollPositionClamp = ScrollPositionClamp::ToContentEdges);
+    void scrollTo(const FloatPoint&, ScrollType = ScrollType::User, ScrollPositionClamp = ScrollPositionClamp::ToContentEdges);
     void scrollBy(const FloatSize&, ScrollPositionClamp = ScrollPositionClamp::ToContentEdges);
 
     void wasScrolledByDelegatedScrolling(const FloatPoint& position, Optional<FloatRect> overrideLayoutViewport = { });

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm (243925 => 243926)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm	2019-04-05 05:18:17 UTC (rev 243926)
@@ -137,8 +137,10 @@
     const auto& scrollingStateNode = downcast<ScrollingStateScrollingNode>(stateNode);
 
     // Update the scroll position after child nodes have been updated, because they need to have updated their constraints before any scrolling happens.
-    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition))
-        scrollTo(scrollingStateNode.requestedScrollPosition());
+    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
+        auto scrollType = scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll() ? ScrollType::Programmatic : ScrollType::User;
+        scrollTo(scrollingStateNode.requestedScrollPosition(), scrollType);
+    }
 
     if (isRootNode()
         && (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrolledContentsLayer)

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (243925 => 243926)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2019-04-05 05:18:17 UTC (rev 243926)
@@ -2346,8 +2346,15 @@
     auto previousScrollType = currentScrollType();
     setCurrentScrollType(scrollType);
 
-    scrollToOffsetWithoutAnimation(newScrollOffset, clamping);
+    bool handled = false;
+#if ENABLE(ASYNC_SCROLLING)
+    if (ScrollingCoordinator* scrollingCoordinator = page().scrollingCoordinator())
+        handled = scrollingCoordinator->requestScrollPositionUpdate(*this, scrollPositionFromOffset(scrollOffset));
+#endif
 
+    if (!handled)
+        scrollToOffsetWithoutAnimation(newScrollOffset, clamping);
+
     setCurrentScrollType(previousScrollType);
 }
 
@@ -2804,6 +2811,14 @@
     return 0;
 }
 
+ScrollingNodeID RenderLayer::scrollingNodeID() const
+{
+    if (!isComposited())
+        return 0;
+
+    return backing()->scrollingNodeIDForRole(ScrollCoordinationRole::Scrolling);
+}
+
 IntRect RenderLayer::visibleContentRectInternal(VisibleContentRectIncludesScrollbars scrollbarInclusion, VisibleContentRectBehavior) const
 {
     IntSize scrollbarSpace;

Modified: trunk/Source/WebCore/rendering/RenderLayer.h (243925 => 243926)


--- trunk/Source/WebCore/rendering/RenderLayer.h	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/rendering/RenderLayer.h	2019-04-05 05:18:17 UTC (rev 243926)
@@ -420,8 +420,8 @@
     void scrollToYPosition(int y, ScrollType, ScrollClamping = ScrollClamping::Clamped);
 
     // These are only used by marquee.
-    void scrollToXOffset(int x, ScrollClamping clamping = ScrollClamping::Clamped) { scrollToOffset(ScrollOffset(x, scrollOffset().y()), ScrollType::Programmatic, clamping); }
-    void scrollToYOffset(int y, ScrollClamping clamping = ScrollClamping::Clamped) { scrollToOffset(ScrollOffset(scrollOffset().x(), y), ScrollType::Programmatic, clamping); }
+    void scrollToXOffset(int x) { scrollToOffset(ScrollOffset(x, scrollOffset().y()), ScrollType::Programmatic, ScrollClamping::Unclamped); }
+    void scrollToYOffset(int y) { scrollToOffset(ScrollOffset(scrollOffset().x(), y), ScrollType::Programmatic, ScrollClamping::Unclamped); }
 
     void setPostLayoutScrollPosition(Optional<ScrollPosition>);
     void applyPostLayoutScrollPositionIfNeeded();
@@ -1050,6 +1050,7 @@
     IntPoint convertFromContainingViewToScrollbar(const Scrollbar&, const IntPoint&) const override;
     int scrollSize(ScrollbarOrientation) const override;
     void setScrollOffset(const ScrollOffset&) override;
+    ScrollingNodeID scrollingNodeID() const override;
 
     IntRect visibleContentRectInternal(VisibleContentRectIncludesScrollbars, VisibleContentRectBehavior) const override;
     IntSize overhangAmount() const override;

Modified: trunk/Source/WebCore/rendering/RenderMarquee.cpp (243925 => 243926)


--- trunk/Source/WebCore/rendering/RenderMarquee.cpp	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebCore/rendering/RenderMarquee.cpp	2019-04-05 05:18:17 UTC (rev 243926)
@@ -247,9 +247,9 @@
     if (m_reset) {
         m_reset = false;
         if (isHorizontal())
-            m_layer->scrollToXOffset(m_start, ScrollClamping::Unclamped);
+            m_layer->scrollToXOffset(m_start);
         else
-            m_layer->scrollToYOffset(m_start, ScrollClamping::Unclamped);
+            m_layer->scrollToYOffset(m_start);
         return;
     }
     
@@ -289,9 +289,9 @@
     }
     
     if (isHorizontal())
-        m_layer->scrollToXOffset(newPos, ScrollClamping::Unclamped);
+        m_layer->scrollToXOffset(newPos);
     else
-        m_layer->scrollToYOffset(newPos, ScrollClamping::Unclamped);
+        m_layer->scrollToYOffset(newPos);
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebKit/ChangeLog (243925 => 243926)


--- trunk/Source/WebKit/ChangeLog	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebKit/ChangeLog	2019-04-05 05:18:17 UTC (rev 243926)
@@ -1,3 +1,39 @@
+2019-04-04  Simon Fraser  <[email protected]>
+
+        [iOS WK2] REGRESSION (r242687): Programmatic scroll of overflow scroll results in bad rendering
+        https://bugs.webkit.org/show_bug.cgi?id=195584
+
+        Reviewed by Zalan Bujtas.
+
+        Push data to the scrolling tree about whether an overflow:scroll scroll was programmatic, by having
+        RenderLayer::scrollToOffset() call into AsyncScrollingCoordinator::requestScrollPositionUpdate(),
+        just as we do for frames.
+
+        AsyncScrollingCoordinator::requestScrollPositionUpdate() is generalized to take any ScrollableArea.
+
+        Fix an assumption in the ScrollingTree that we only care about programmatic scrolls on the root node.
+        ScrollingTree::commitTreeState() no longer sets isHandlingProgrammaticScroll; instead,
+        callers of ScrollingTreeScrollingNode::scrollTo() pass a ScrollType. Commit functions pass
+        ScrollType::Programmatic when handling RequestedScrollPosition changes as necessary.
+
+        Programmatic scrolls need to get to the scrolling tree in the UI process so that we update
+        the tree's notion of scroll position, and trigger actual UIScrollView scrolls (layers may have
+        already been put in the right locations, but the UI process needs to know that a scroll happened).
+        However, we need to prevent notifications from programmatic scrolls getting back to the
+        web process, because this causes jumpiness. This is done via an early return in
+        RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll().
+
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
+        (WebKit::RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidScroll):
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeFrameScrollingNodeRemoteIOS.mm:
+        (WebKit::ScrollingTreeFrameScrollingNodeRemoteIOS::commitStateAfterChildren): Subframe nodes have
+        a delegate, and that will take care of the requestedScrollPosition update.
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h:
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
+        (WebKit::ScrollingTreeOverflowScrollingNodeIOS::commitStateAfterChildren):
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
+        (WebKit::ScrollingTreeScrollingNodeDelegateIOS::commitStateAfterChildren):
+
 2019-04-04  Ryan Haddad  <[email protected]>
 
         Unreviewed, rolling out r243888.

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp (243925 => 243926)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp	2019-04-05 05:18:17 UTC (rev 243926)
@@ -216,6 +216,10 @@
 #if PLATFORM(IOS_FAMILY)
     m_webPageProxy.scrollingNodeScrollViewDidScroll();
 #endif
+
+    if (m_scrollingTree->isHandlingProgrammaticScroll())
+        return;
+
     m_webPageProxy.send(Messages::RemoteScrollingCoordinator::ScrollPositionChangedForNode(scrolledNodeID, newScrollPosition, scrollingLayerPositionAction == ScrollingLayerPositionAction::Sync));
 }
 

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeFrameScrollingNodeRemoteIOS.mm (243925 => 243926)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeFrameScrollingNodeRemoteIOS.mm	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeFrameScrollingNodeRemoteIOS.mm	2019-04-05 05:18:17 UTC (rev 243926)
@@ -82,12 +82,16 @@
 
     const auto& scrollingStateNode = downcast<ScrollingStateFrameScrollingNode>(stateNode);
 
+    if (m_scrollingNodeDelegate) {
+        m_scrollingNodeDelegate->commitStateAfterChildren(scrollingStateNode);
+        return;
+    }
+
     // Update the scroll position after child nodes have been updated, because they need to have updated their constraints before any scrolling happens.
-    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition))
-        scrollTo(scrollingStateNode.requestedScrollPosition());
-
-    if (m_scrollingNodeDelegate)
-        m_scrollingNodeDelegate->commitStateAfterChildren(downcast<ScrollingStateScrollingNode>(stateNode));
+    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
+        auto scrollType = scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll() ? ScrollType::Programmatic : ScrollType::User;
+        scrollTo(scrollingStateNode.requestedScrollPosition(), scrollType);
+    }
 }
 
 FloatPoint ScrollingTreeFrameScrollingNodeRemoteIOS::minimumScrollPosition() const

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h (243925 => 243926)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h	2019-04-05 05:18:17 UTC (rev 243926)
@@ -46,6 +46,7 @@
     
     void repositionScrollingLayers() override;
 
+    // The delegate is non-null for subframes.
     std::unique_ptr<ScrollingTreeScrollingNodeDelegateIOS> m_scrollingNodeDelegate;
 };
 

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm (243925 => 243926)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm	2019-04-05 05:18:17 UTC (rev 243926)
@@ -63,7 +63,9 @@
 void ScrollingTreeOverflowScrollingNodeIOS::commitStateAfterChildren(const ScrollingStateNode& stateNode)
 {
     ScrollingTreeOverflowScrollingNode::commitStateAfterChildren(stateNode);
-    m_scrollingNodeDelegate->commitStateAfterChildren(downcast<ScrollingStateScrollingNode>(stateNode));
+
+    const auto& scrollingStateNode = downcast<ScrollingStateScrollingNode>(stateNode);
+    m_scrollingNodeDelegate->commitStateAfterChildren(scrollingStateNode);
 }
 
 void ScrollingTreeOverflowScrollingNodeIOS::repositionScrollingLayers()

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm (243925 => 243926)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm	2019-04-05 04:17:44 UTC (rev 243925)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm	2019-04-05 05:18:17 UTC (rev 243926)
@@ -225,6 +225,7 @@
 void ScrollingTreeScrollingNodeDelegateIOS::commitStateAfterChildren(const ScrollingStateScrollingNode& scrollingStateNode)
 {
     SetForScope<bool> updatingChange(m_updatingFromStateNode, true);
+
     if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollContainerLayer)
         || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::TotalContentsSize)
         || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::ReachableContentsSize)
@@ -287,6 +288,11 @@
 
         END_BLOCK_OBJC_EXCEPTIONS
     }
+
+    if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {
+        auto scrollType = scrollingStateNode.requestedScrollPositionRepresentsProgrammaticScroll() ? ScrollType::Programmatic : ScrollType::User;
+        scrollingNode().scrollTo(scrollingStateNode.requestedScrollPosition(), scrollType);
+    }
 }
 
 void ScrollingTreeScrollingNodeDelegateIOS::repositionScrollingLayers()
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to