Title: [243607] trunk
Revision
243607
Author
[email protected]
Date
2019-03-28 09:44:27 -0700 (Thu, 28 Mar 2019)

Log Message

[macOS WK2] Overlays on instagram.com are shifted if you click on a photo after scrolling
https://bugs.webkit.org/show_bug.cgi?id=196330
rdar://problem/49100304

Source/WebCore:

Reviewed by Antti Koivisto.

When we call ScrollingTree::applyLayerPositions() on the main thread after a flush,
we need to ensure that the most recent version of the scrolling tree has been committed,
because it has to have state (like requested scroll position and layout viewport rect)
that match the layer flush.

To fix this we have to have the main thread wait for the commit to complete, so
ThreadedScrollingTree keeps track of a pending commit count, and uses a condition
variable to allow the main thread to safely wait for it to reach zero.

Tracing shows that this works as expected, and the main thread is never blocked for
more than a few tens of microseconds.

Also lock the tree mutex in ScrollingTree::handleWheelEvent(), since we enter the
scrolling tree here and we don't want that racing with applyLayerPositions() on the
main thread.

Test: scrollingcoordinator/mac/fixed-scrolled-body.html

* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::handleWheelEvent):
(WebCore::ScrollingTree::applyLayerPositions):
* page/scrolling/ScrollingTree.h:
* page/scrolling/ThreadedScrollingTree.cpp:
(WebCore::ThreadedScrollingTree::commitTreeState):
(WebCore::ThreadedScrollingTree::incrementPendingCommitCount):
(WebCore::ThreadedScrollingTree::decrementPendingCommitCount):
(WebCore::ThreadedScrollingTree::waitForPendingCommits):
(WebCore::ThreadedScrollingTree::applyLayerPositions):
* page/scrolling/ThreadedScrollingTree.h:
* page/scrolling/mac/ScrollingCoordinatorMac.mm:
(WebCore::ScrollingCoordinatorMac::commitTreeState):

LayoutTests:

Reviewed by NOBODY (OOPS!).

* scrollingcoordinator/mac/fixed-scrolled-body-expected.html: Added.
* scrollingcoordinator/mac/fixed-scrolled-body.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (243606 => 243607)


--- trunk/LayoutTests/ChangeLog	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/LayoutTests/ChangeLog	2019-03-28 16:44:27 UTC (rev 243607)
@@ -1,3 +1,14 @@
+2019-03-28  Simon Fraser  <[email protected]>
+
+        [macOS WK2] Overlays on instagram.com are shifted if you click on a photo after scrolling
+        https://bugs.webkit.org/show_bug.cgi?id=196330
+        rdar://problem/49100304
+
+        Reviewed by Antti Koivisto.
+
+        * scrollingcoordinator/mac/fixed-scrolled-body-expected.html: Added.
+        * scrollingcoordinator/mac/fixed-scrolled-body.html: Added.
+
 2019-03-28  Zalan Bujtas  <[email protected]>
 
         [SimpleLineLayout] Disable SLL when text-underline-position is not auto.

Added: trunk/LayoutTests/scrollingcoordinator/mac/fixed-scrolled-body-expected.html (0 => 243607)


--- trunk/LayoutTests/scrollingcoordinator/mac/fixed-scrolled-body-expected.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/mac/fixed-scrolled-body-expected.html	2019-03-28 16:44:27 UTC (rev 243607)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        body, html {
+            height: 100%;
+            margin: 0;
+            position: fixed;
+            top: -200px;
+        }
+        .section {
+            height: 2000px;
+        }
+        .overlay {
+            position: fixed;
+            left: 0;
+            top: 0;
+            width: 400px;
+            height: 100px;
+            background-color: blue;
+        }
+    </style>
+</head>
+<body>
+    <div class="section"></div>
+    <div class="overlay"></div>
+</body>
+</html>
+

Added: trunk/LayoutTests/scrollingcoordinator/mac/fixed-scrolled-body.html (0 => 243607)


--- trunk/LayoutTests/scrollingcoordinator/mac/fixed-scrolled-body.html	                        (rev 0)
+++ trunk/LayoutTests/scrollingcoordinator/mac/fixed-scrolled-body.html	2019-03-28 16:44:27 UTC (rev 243607)
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <style>
+        body, html {
+            height: 100%;
+            width: 100%;
+            margin: 0;
+        }
+        .section {
+            height: 2000px;
+        }
+        .overlay {
+            position: fixed;
+            left: 0;
+            top: 0;
+            width: 400px;
+            height: 100px;
+            background-color: blue;
+        }
+    </style>
+    <script>
+        if (window.testRunner)
+            testRunner.waitUntilDone();
+
+        function doTest()
+        {
+            window.scrollTo(0, 200);
+            requestAnimationFrame(() => {
+                document.body.style.top = -window.scrollY + 'px';
+                document.body.style.position = 'fixed';
+
+                if (window.testRunner)
+                    testRunner.notifyDone();
+            });
+        }
+        
+        window.addEventListener('load', doTest, false);
+    </script>
+</head>
+<body>
+    <div class="section"></div>
+    <div class="overlay"></div>
+</body>
+</html>
+

Modified: trunk/Source/WebCore/ChangeLog (243606 => 243607)


--- trunk/Source/WebCore/ChangeLog	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/Source/WebCore/ChangeLog	2019-03-28 16:44:27 UTC (rev 243607)
@@ -1,3 +1,43 @@
+2019-03-28  Simon Fraser  <[email protected]>
+
+        [macOS WK2] Overlays on instagram.com are shifted if you click on a photo after scrolling
+        https://bugs.webkit.org/show_bug.cgi?id=196330
+        rdar://problem/49100304
+
+        Reviewed by Antti Koivisto.
+
+        When we call ScrollingTree::applyLayerPositions() on the main thread after a flush,
+        we need to ensure that the most recent version of the scrolling tree has been committed,
+        because it has to have state (like requested scroll position and layout viewport rect)
+        that match the layer flush.
+
+        To fix this we have to have the main thread wait for the commit to complete, so
+        ThreadedScrollingTree keeps track of a pending commit count, and uses a condition
+        variable to allow the main thread to safely wait for it to reach zero.
+
+        Tracing shows that this works as expected, and the main thread is never blocked for
+        more than a few tens of microseconds.
+
+        Also lock the tree mutex in ScrollingTree::handleWheelEvent(), since we enter the
+        scrolling tree here and we don't want that racing with applyLayerPositions() on the
+        main thread.
+
+        Test: scrollingcoordinator/mac/fixed-scrolled-body.html
+
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::handleWheelEvent):
+        (WebCore::ScrollingTree::applyLayerPositions):
+        * page/scrolling/ScrollingTree.h:
+        * page/scrolling/ThreadedScrollingTree.cpp:
+        (WebCore::ThreadedScrollingTree::commitTreeState):
+        (WebCore::ThreadedScrollingTree::incrementPendingCommitCount):
+        (WebCore::ThreadedScrollingTree::decrementPendingCommitCount):
+        (WebCore::ThreadedScrollingTree::waitForPendingCommits):
+        (WebCore::ThreadedScrollingTree::applyLayerPositions):
+        * page/scrolling/ThreadedScrollingTree.h:
+        * page/scrolling/mac/ScrollingCoordinatorMac.mm:
+        (WebCore::ScrollingCoordinatorMac::commitTreeState):
+
 2019-03-28  Zalan Bujtas  <[email protected]>
 
         [SimpleLineLayout] Disable SLL when text-underline-position is not auto.

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (243606 => 243607)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-03-28 16:44:27 UTC (rev 243607)
@@ -93,6 +93,8 @@
 {
     LOG_WITH_STREAM(Scrolling, stream << "ScrollingTree " << this << " handleWheelEvent (async scrolling enabled: " << asyncFrameOrOverflowScrollingEnabled() << ")");
 
+    LockHolder locker(m_treeMutex);
+
     if (!asyncFrameOrOverflowScrollingEnabled()) {
         if (m_rootNode)
             downcast<ScrollingTreeScrollingNode>(*m_rootNode).handleWheelEvent(wheelEvent);
@@ -106,7 +108,6 @@
             return downcast<ScrollingTreeScrollingNode>(*node).handleWheelEvent(wheelEvent);
     }
 
-    LockHolder locker(m_treeMutex);
     if (m_rootNode) {
         auto& frameScrollingNode = downcast<ScrollingTreeFrameScrollingNode>(*m_rootNode);
 
@@ -260,9 +261,9 @@
     node->commitStateAfterChildren(*stateNode);
 }
 
-// Called from the main thread.
 void ScrollingTree::applyLayerPositions()
 {
+    ASSERT(isMainThread());
     LockHolder locker(m_treeMutex);
 
     if (!m_rootNode)

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (243606 => 243607)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-03-28 16:44:27 UTC (rev 243607)
@@ -69,7 +69,7 @@
     virtual void invalidate() { }
     WEBCORE_EXPORT virtual void commitTreeState(std::unique_ptr<ScrollingStateTree>);
     
-    WEBCORE_EXPORT void applyLayerPositions();
+    WEBCORE_EXPORT virtual void applyLayerPositions();
 
     virtual Ref<ScrollingTreeNode> createScrollingTreeNode(ScrollingNodeType, ScrollingNodeID) = 0;
     
@@ -153,7 +153,7 @@
     HashSet<ScrollingNodeID>& positionedNodesWithRelatedOverflow() { return m_positionedNodesWithRelatedOverflow; }
 
     WEBCORE_EXPORT String scrollingTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal);
-    
+
 protected:
     void setMainFrameScrollPosition(FloatPoint);
 

Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp (243606 => 243607)


--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.cpp	2019-03-28 16:44:27 UTC (rev 243607)
@@ -89,6 +89,8 @@
 {
     ASSERT(ScrollingThread::isCurrentThread());
     ScrollingTree::commitTreeState(WTFMove(scrollingStateTree));
+    
+    decrementPendingCommitCount();
 }
 
 void ThreadedScrollingTree::scrollingTreeNodeDidScroll(ScrollingTreeScrollingNode& node, ScrollingLayerPositionAction scrollingLayerPositionAction)
@@ -124,6 +126,35 @@
     });
 }
 
+void ThreadedScrollingTree::incrementPendingCommitCount()
+{
+    LockHolder commitLocker(m_pendingCommitCountMutex);
+    ++m_pendingCommitCount;
+}
+
+void ThreadedScrollingTree::decrementPendingCommitCount()
+{
+    LockHolder commitLocker(m_pendingCommitCountMutex);
+    ASSERT(m_pendingCommitCount > 0);
+    if (!--m_pendingCommitCount)
+        m_commitCondition.notifyOne();
+}
+
+void ThreadedScrollingTree::waitForPendingCommits()
+{
+    ASSERT(isMainThread());
+
+    LockHolder commitLocker(m_pendingCommitCountMutex);
+    while (m_pendingCommitCount)
+        m_commitCondition.wait(m_pendingCommitCountMutex);
+}
+
+void ThreadedScrollingTree::applyLayerPositions()
+{
+    waitForPendingCommits();
+    ScrollingTree::applyLayerPositions();
+}
+
 #if PLATFORM(COCOA)
 void ThreadedScrollingTree::currentSnapPointIndicesDidChange(ScrollingNodeID nodeID, unsigned horizontal, unsigned vertical)
 {

Modified: trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h (243606 => 243607)


--- trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/Source/WebCore/page/scrolling/ThreadedScrollingTree.h	2019-03-28 16:44:27 UTC (rev 243607)
@@ -29,6 +29,7 @@
 
 #include "ScrollingStateTree.h"
 #include "ScrollingTree.h"
+#include <wtf/Condition.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
@@ -54,6 +55,9 @@
 
     void invalidate() override;
 
+    void incrementPendingCommitCount();
+    void decrementPendingCommitCount();
+
 protected:
     explicit ThreadedScrollingTree(AsyncScrollingCoordinator&);
 
@@ -74,8 +78,15 @@
 
 private:
     bool isThreadedScrollingTree() const override { return true; }
+    void applyLayerPositions() override;
 
     RefPtr<AsyncScrollingCoordinator> m_scrollingCoordinator;
+
+    void waitForPendingCommits();
+
+    Lock m_pendingCommitCountMutex;
+    unsigned m_pendingCommitCount { 0 };
+    Condition m_commitCondition;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm (243606 => 243607)


--- trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm	2019-03-28 16:36:18 UTC (rev 243606)
+++ trunk/Source/WebCore/page/scrolling/mac/ScrollingCoordinatorMac.mm	2019-03-28 16:44:27 UTC (rev 243607)
@@ -122,6 +122,8 @@
     RefPtr<ThreadedScrollingTree> threadedScrollingTree = downcast<ThreadedScrollingTree>(scrollingTree());
     ScrollingStateTree* unprotectedTreeState = scrollingStateTree()->commit(LayerRepresentation::PlatformLayerRepresentation).release();
 
+    threadedScrollingTree->incrementPendingCommitCount();
+
     ScrollingThread::dispatch([threadedScrollingTree, unprotectedTreeState] {
         std::unique_ptr<ScrollingStateTree> treeState(unprotectedTreeState);
         threadedScrollingTree->commitTreeState(WTFMove(treeState));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to