Title: [246156] trunk
Revision
246156
Author
[email protected]
Date
2019-06-06 09:39:34 -0700 (Thu, 06 Jun 2019)

Log Message

Position fixed is buggy with overflow:auto scrolling inside iframes
https://bugs.webkit.org/show_bug.cgi?id=154399
<rdar://problem/24742251>

Reviewed by Frederic Wang and Simon Fraser.

Source/WebCore:

Test: scrollingcoordinator/ios/fixed-frame-overflow-swipe.html

After layer tree commit we were calling mainFrameViewportChangedViaDelegatedScrolling (even if viewport did not change)
and expecting it to apply UI side scrolling deltas. However optimization prevents it from descending into subframes
and we fail to update those properly.

In reality we only need to to apply scrolling tree positiong after commit if there has been delegated scrolling after the last
one. Track this and do full update when needed.

* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::applyLayerPositionsAfterCommit):

Add specific function for this. Don't do anything unless needed.

* page/scrolling/ScrollingTree.h:
(WebCore::ScrollingTree::didScrollByDelegatedScrolling):

Track if there has been any delegated scrolling.

* page/scrolling/ScrollingTreeScrollingNode.cpp:
(WebCore::ScrollingTreeScrollingNode::wasScrolledByDelegatedScrolling):

We can now bail out if nothing changes since we no longer rely on this for post-commit updates.

Source/WebKit:

* UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:
(WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):

Remove viewportChangedViaDelegatedScrolling call as we were just relying on its side effect of (partially) applying
the scrolling tree. Instead call the new applyScrollingTreeLayerPositionsAfterCommit() unconditionally.
It only does work if there are local deltas to apply.

Local deltas will potentially need to be applied in non-fixed cases too and it is hard to reason about the conditions.

* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
(WebKit::RemoteScrollingCoordinatorProxy::applyScrollingTreeLayerPositionsAfterCommit):
(WebKit::RemoteScrollingCoordinatorProxy::applyScrollingTreeLayerPositions): Deleted.
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:

LayoutTests:

* scrollingcoordinator/ios/fixed-frame-overflow-swipe-expected.html: Added.
* scrollingcoordinator/ios/fixed-frame-overflow-swipe.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (246155 => 246156)


--- trunk/LayoutTests/ChangeLog	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/LayoutTests/ChangeLog	2019-06-06 16:39:34 UTC (rev 246156)
@@ -1,3 +1,14 @@
+2019-06-06  Antti Koivisto  <[email protected]>
+
+        Position fixed is buggy with overflow:auto scrolling inside iframes
+        https://bugs.webkit.org/show_bug.cgi?id=154399
+        <rdar://problem/24742251>
+
+        Reviewed by Frederic Wang and Simon Fraser.
+
+        * scrollingcoordinator/ios/fixed-frame-overflow-swipe-expected.html: Added.
+        * scrollingcoordinator/ios/fixed-frame-overflow-swipe.html: Added.
+
 2019-06-06  Antoine Quint  <[email protected]>
 
         [Pointer Events] Add support for chorded button interactions

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-frame-overflow-swipe-expected.html (0 => 246156)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-frame-overflow-swipe-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-frame-overflow-swipe-expected.html	2019-06-06 16:39:34 UTC (rev 246156)
@@ -0,0 +1,86 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name='viewport' content='initial-scale=1.0'>
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+    </style>
+    <script src=''></script>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await UIHelper.ensurePresentationUpdate();
+            frame.contentDocument.querySelector('.scroller').scrollTo(0, 200);
+            await UIHelper.ensurePresentationUpdate();
+
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <iframe id='frame' width=300 height=400 srcdoc="<!DOCTYPE html>
+        <html>
+        <head>
+            <style>
+                .scroller {
+                    margin: 10px;
+                    height: 300px;
+                    width: 300px;
+                    border: 1px solid black;
+                    overflow: scroll;
+                    z-index: 0;
+                    position: relative;
+                }
+
+                .fixed {
+                    position: fixed;
+                    bottom: 0px;
+                    right: 0px;
+                    width: 200px;
+                    height: 200px;
+                    background-color: green;
+                }
+                .spacer {
+                    height: 1000px;
+                    border: 2px solid blue;
+                }
+            </style>
+        </head>
+        <body>
+            <div class='scroller'>
+                <div class='fixed'></div>
+                <div class='spacer'></div>
+            </div>
+        </body>
+        </html>"
+    ></iframe>
+</body>
+</html>

Added: trunk/LayoutTests/scrollingcoordinator/ios/fixed-frame-overflow-swipe.html (0 => 246156)


--- trunk/LayoutTests/scrollingcoordinator/ios/fixed-frame-overflow-swipe.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/ios/fixed-frame-overflow-swipe.html	2019-06-06 16:39:34 UTC (rev 246156)
@@ -0,0 +1,84 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ useFlexibleViewport=true internal:AsyncOverflowScrollingEnabled=true internal:AsyncFrameScrollingEnabled=true ] -->
+<html>
+<head>
+    <meta name='viewport' content='initial-scale=1.0'>
+    <style>
+        .scroller {
+            margin: 10px;
+            height: 300px;
+            width: 300px;
+            border: 1px solid black;
+            overflow: scroll;
+            z-index: 0;
+            position: relative;
+        }
+        
+        .fixed {
+            position: fixed;
+            top: 0px;
+            width: 200px;
+            height: 200px;
+            background-color: green;
+        }
+    </style>
+    <script src=''></script>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        async function doTest()
+        {
+            if (!window.testRunner)
+                return;
+
+            if (!testRunner.runUIScript)
+                return;
+
+            await touchAndDragFromPointToPoint(50, 200, 50, 50);
+            await liftUpAtPoint(50, 200);
+
+            testRunner.notifyDone();
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <iframe width=300 height=400 srcdoc="<!DOCTYPE html>
+        <html>
+        <head>
+            <style>
+                .scroller {
+                    margin: 10px;
+                    height: 300px;
+                    width: 300px;
+                    border: 1px solid black;
+                    overflow: scroll;
+                    z-index: 0;
+                    position: relative;
+                }
+
+                .fixed {
+                    position: fixed;
+                    bottom: 0px;
+                    right: 0px;
+                    width: 200px;
+                    height: 200px;
+                    background-color: green;
+                }
+                .spacer {
+                    height: 1000px;
+                    border: 2px solid blue;
+                }
+            </style>
+        </head>
+        <body>
+            <div class='scroller'>
+                <div class='fixed'></div>
+                <div class='spacer'></div>
+            </div>
+        </body>
+        </html>"
+    ></iframe>
+</body>
+</html>

Modified: trunk/Source/WebCore/ChangeLog (246155 => 246156)


--- trunk/Source/WebCore/ChangeLog	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebCore/ChangeLog	2019-06-06 16:39:34 UTC (rev 246156)
@@ -1,3 +1,35 @@
+2019-06-06  Antti Koivisto  <[email protected]>
+
+        Position fixed is buggy with overflow:auto scrolling inside iframes
+        https://bugs.webkit.org/show_bug.cgi?id=154399
+        <rdar://problem/24742251>
+
+        Reviewed by Frederic Wang and Simon Fraser.
+
+        Test: scrollingcoordinator/ios/fixed-frame-overflow-swipe.html
+
+        After layer tree commit we were calling mainFrameViewportChangedViaDelegatedScrolling (even if viewport did not change)
+        and expecting it to apply UI side scrolling deltas. However optimization prevents it from descending into subframes
+        and we fail to update those properly.
+
+        In reality we only need to to apply scrolling tree positiong after commit if there has been delegated scrolling after the last
+        one. Track this and do full update when needed.
+
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::applyLayerPositionsAfterCommit):
+
+        Add specific function for this. Don't do anything unless needed.
+
+        * page/scrolling/ScrollingTree.h:
+        (WebCore::ScrollingTree::didScrollByDelegatedScrolling):
+
+        Track if there has been any delegated scrolling.
+
+        * page/scrolling/ScrollingTreeScrollingNode.cpp:
+        (WebCore::ScrollingTreeScrollingNode::wasScrolledByDelegatedScrolling):
+
+        We can now bail out if nothing changes since we no longer rely on this for post-commit updates.
+
 2019-06-06  Zalan Bujtas  <[email protected]>
 
         [LFC][IFC] Layout and preferred width computation should both call placeInlineItems().

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (246155 => 246156)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-06-06 16:39:34 UTC (rev 246156)
@@ -254,6 +254,16 @@
     node->commitStateAfterChildren(*stateNode);
 }
 
+void ScrollingTree::applyLayerPositionsAfterCommit()
+{
+    // Scrolling tree needs to make adjustments only if the UI side positions have changed.
+    if (!m_wasScrolledByDelegatedScrollingSincePreviousCommit)
+        return;
+    m_wasScrolledByDelegatedScrollingSincePreviousCommit = false;
+
+    applyLayerPositions();
+}
+
 void ScrollingTree::applyLayerPositions()
 {
     ASSERT(isMainThread());

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (246155 => 246156)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-06-06 16:39:34 UTC (rev 246156)
@@ -71,6 +71,7 @@
     WEBCORE_EXPORT virtual void commitTreeState(std::unique_ptr<ScrollingStateTree>);
     
     WEBCORE_EXPORT virtual void applyLayerPositions();
+    WEBCORE_EXPORT void applyLayerPositionsAfterCommit();
 
     virtual Ref<ScrollingTreeNode> createScrollingTreeNode(ScrollingNodeType, ScrollingNodeID) = 0;
     
@@ -84,9 +85,10 @@
     virtual void scrollingTreeNodeRequestsScroll(ScrollingNodeID, const FloatPoint& /*scrollPosition*/, bool /*representsProgrammaticScroll*/) { }
 
     // Delegated scrolling/zooming has caused the viewport to change, so update viewport-constrained layers
-    // (but don't cause scroll events to be fired).
-    WEBCORE_EXPORT virtual void mainFrameViewportChangedViaDelegatedScrolling(const FloatPoint& scrollPosition, const WebCore::FloatRect& layoutViewport, double scale);
+    WEBCORE_EXPORT void mainFrameViewportChangedViaDelegatedScrolling(const FloatPoint& scrollPosition, const WebCore::FloatRect& layoutViewport, double scale);
 
+    void didScrollByDelegatedScrolling() { m_wasScrolledByDelegatedScrollingSincePreviousCommit = true; }
+
     void notifyRelatedNodesAfterScrollPositionChange(ScrollingTreeScrollingNode& changedNode);
 
     virtual void reportSynchronousScrollingReasonsChanged(MonotonicTime, SynchronousScrollingReasons) { }
@@ -209,6 +211,7 @@
     bool m_isHandlingProgrammaticScroll { false };
     bool m_scrollingPerformanceLoggingEnabled { false };
     bool m_asyncFrameOrOverflowScrollingEnabled { false };
+    bool m_wasScrolledByDelegatedScrollingSincePreviousCommit { false };
 };
     
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp (246155 => 246156)


--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp	2019-06-06 16:39:34 UTC (rev 246156)
@@ -196,10 +196,9 @@
 
 void ScrollingTreeScrollingNode::wasScrolledByDelegatedScrolling(const FloatPoint& position, Optional<FloatRect> overrideLayoutViewport)
 {
-    // Even if position and overrideLayoutViewport haven't changed for this node, other nodes may have received new constraint data
-    // via a commit, so the call to notifyRelatedNodesAfterScrollPositionChange() is necessary. We could avoid this if we knew that
-    // no commits had happened.
     bool scrollPositionChanged = !scrollPositionAndLayoutViewportMatch(position, overrideLayoutViewport);
+    if (!scrollPositionChanged)
+        return;
 
     m_currentScrollPosition = adjustedScrollPosition(position, ScrollPositionClamp::None);
     updateViewportForCurrentScrollPosition(overrideLayoutViewport);
@@ -207,9 +206,8 @@
     repositionRelatedLayers();
 
     scrollingTree().notifyRelatedNodesAfterScrollPositionChange(*this);
-    
-    if (scrollPositionChanged)
-        scrollingTree().scrollingTreeNodeDidScroll(*this);
+    scrollingTree().scrollingTreeNodeDidScroll(*this);
+    scrollingTree().didScrollByDelegatedScrolling();
 }
 
 LayoutPoint ScrollingTreeScrollingNode::parentToLocalPoint(LayoutPoint point) const

Modified: trunk/Source/WebKit/ChangeLog (246155 => 246156)


--- trunk/Source/WebKit/ChangeLog	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebKit/ChangeLog	2019-06-06 16:39:34 UTC (rev 246156)
@@ -1,3 +1,25 @@
+2019-06-06  Antti Koivisto  <[email protected]>
+
+        Position fixed is buggy with overflow:auto scrolling inside iframes
+        https://bugs.webkit.org/show_bug.cgi?id=154399
+        <rdar://problem/24742251>
+
+        Reviewed by Frederic Wang and Simon Fraser.
+
+        * UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm:
+        (WebKit::RemoteLayerTreeDrawingAreaProxy::commitLayerTree):
+
+        Remove viewportChangedViaDelegatedScrolling call as we were just relying on its side effect of (partially) applying
+        the scrolling tree. Instead call the new applyScrollingTreeLayerPositionsAfterCommit() unconditionally.
+        It only does work if there are local deltas to apply.
+
+        Local deltas will potentially need to be applied in non-fixed cases too and it is hard to reason about the conditions.
+
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
+        (WebKit::RemoteScrollingCoordinatorProxy::applyScrollingTreeLayerPositionsAfterCommit):
+        (WebKit::RemoteScrollingCoordinatorProxy::applyScrollingTreeLayerPositions): Deleted.
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
+
 2019-06-06  Michael Catanzaro  <[email protected]>
 
         [WPE][GTK] Clean up use of initiatingPageID in implementation of webkit_uri_scheme_request_get_web_view()

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm (246155 => 246156)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeDrawingAreaProxy.mm	2019-06-06 16:39:34 UTC (rev 246156)
@@ -217,15 +217,7 @@
     m_webPageProxy.didCommitLayerTree(layerTreeTransaction);
 
 #if ENABLE(ASYNC_SCROLLING)
-    if (m_webPageProxy.scrollingCoordinatorProxy()->hasFixedOrSticky()) {
-#if PLATFORM(IOS_FAMILY)
-        // If we got a new layer for a fixed or sticky node, its position from the WebProcess is probably stale. We need to re-run the "viewport" changed logic to udpate it with our UI-side state.
-        FloatRect layoutViewport = m_webPageProxy.computeCustomFixedPositionRect(m_webPageProxy.unobscuredContentRect(), m_webPageProxy.unobscuredContentRectRespectingInputViewBounds(), m_webPageProxy.customFixedPositionRect(), m_webPageProxy.displayedContentScale(), FrameView::LayoutViewportConstraint::Unconstrained);
-        m_webPageProxy.scrollingCoordinatorProxy()->viewportChangedViaDelegatedScrolling(m_webPageProxy.unobscuredContentRect().location(), layoutViewport, m_webPageProxy.displayedContentScale());
-#else
-        m_webPageProxy.scrollingCoordinatorProxy()->applyScrollingTreeLayerPositions();
-#endif
-    }
+    m_webPageProxy.scrollingCoordinatorProxy()->applyScrollingTreeLayerPositionsAfterCommit();
 
     // Handle requested scroll position updates from the scrolling tree transaction after didCommitLayerTree()
     // has updated the view size based on the content size.

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp (246155 => 246156)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp	2019-06-06 16:39:34 UTC (rev 246156)
@@ -192,9 +192,9 @@
     m_scrollingTree->mainFrameViewportChangedViaDelegatedScrolling(scrollPosition, layoutViewport, scale);
 }
 
-void RemoteScrollingCoordinatorProxy::applyScrollingTreeLayerPositions()
+void RemoteScrollingCoordinatorProxy::applyScrollingTreeLayerPositionsAfterCommit()
 {
-    m_scrollingTree->applyLayerPositions();
+    m_scrollingTree->applyLayerPositionsAfterCommit();
 }
 
 void RemoteScrollingCoordinatorProxy::currentSnapPointIndicesDidChange(WebCore::ScrollingNodeID nodeID, unsigned horizontal, unsigned vertical)

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h (246155 => 246156)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h	2019-06-06 16:34:45 UTC (rev 246155)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h	2019-06-06 16:39:34 UTC (rev 246156)
@@ -61,7 +61,7 @@
     // Called externally when native views move around.
     void viewportChangedViaDelegatedScrolling(const WebCore::FloatPoint& scrollPosition, const WebCore::FloatRect& layoutViewport, double scale);
 
-    void applyScrollingTreeLayerPositions();
+    void applyScrollingTreeLayerPositionsAfterCommit();
 
     void currentSnapPointIndicesDidChange(WebCore::ScrollingNodeID, unsigned horizontal, unsigned vertical);
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to