Handle UI side hit testing for ScrollPositioningBehavior::Stationary positioned nodes
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Mar 2019 16:28:55 +0000 (16:28 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 22 Mar 2019 16:28:55 +0000 (16:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=196100
<rdar://problem/49117933>

Reviewed by Simon Fraser.

Source/WebCore:

Test: fast/scrolling/ios/overflow-scroll-overlap-6.html

* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::commitTreeState):
* page/scrolling/ScrollingTree.h:
(WebCore::ScrollingTree::positionedNodesWithRelatedOverflow):

Add a separate map of positioned node ids for easy access.

* page/scrolling/cocoa/ScrollingTreePositionedNode.h:
(WebCore::ScrollingTreePositionedNode::scrollPositioningBehavior const):
(WebCore::ScrollingTreePositionedNode::relatedOverflowScrollingNodes const):
* page/scrolling/cocoa/ScrollingTreePositionedNode.mm:
(WebCore::ScrollingTreePositionedNode::commitStateBeforeChildren):

Source/WebKit:

Test: fast/scrolling/ios/overflow-scroll-overlap-6.html

* UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h:
(WebKit::RemoteLayerTreeNode::relatedScrollContainerIDs const):
(WebKit::RemoteLayerTreeNode::relatedScrollContainerPositioningBehavior const):

Make more generic and save the associated positioning behavior.

(WebKit::RemoteLayerTreeNode::nonAncestorScrollContainerIDs const): Deleted.
(WebKit::RemoteLayerTreeNode::addNonAncestorScrollContainerID): Deleted.
(WebKit::RemoteLayerTreeNode::clearNonAncestorScrollContainerIDs): Deleted.
* UIProcess/RemoteLayerTree/RemoteLayerTreeNode.mm:
(WebKit::RemoteLayerTreeNode::setRelatedScrollContainerBehaviorAndIDs):
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
* UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm:
(WebKit::isScrolledBy):

Stationary relationship means the layer won't scroll the scroller.

* UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
(WebKit::RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations):

LayoutTests:

* fast/scrolling/ios/overflow-scroll-overlap-6-expected.txt: Added.
* fast/scrolling/ios/overflow-scroll-overlap-6.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243380 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-6-expected.txt [new file with mode: 0644]
LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-6.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/page/scrolling/ScrollingTree.cpp
Source/WebCore/page/scrolling/ScrollingTree.h
Source/WebCore/page/scrolling/cocoa/ScrollingTreePositionedNode.h
Source/WebCore/page/scrolling/cocoa/ScrollingTreePositionedNode.mm
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h
Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeNode.mm
Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h
Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm
Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm

index f807e62..db1c35c 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-22  Antti Koivisto  <antti@apple.com>
+
+        Handle UI side hit testing for ScrollPositioningBehavior::Stationary positioned nodes
+        https://bugs.webkit.org/show_bug.cgi?id=196100
+        <rdar://problem/49117933>
+
+        Reviewed by Simon Fraser.
+
+        * fast/scrolling/ios/overflow-scroll-overlap-6-expected.txt: Added.
+        * fast/scrolling/ios/overflow-scroll-overlap-6.html: Added.
+
 2019-03-22  Simon Fraser  <simon.fraser@apple.com>
 
         Unreviewed test gardening of plugin tests
diff --git a/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-6-expected.txt b/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-6-expected.txt
new file mode 100644 (file)
index 0000000..fb23ac2
--- /dev/null
@@ -0,0 +1,6 @@
+Test that absolute positioned layer inside stacking-context overflow:scroll is correctly hit tested.
+
+case 1: 
+case 2: Scrollable 2 
+case 3: Scrollable 3 
+
diff --git a/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-6.html b/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-6.html
new file mode 100644 (file)
index 0000000..f96f36e
--- /dev/null
@@ -0,0 +1,84 @@
+<!DOCTYPE html> <!-- webkit-test-runner [ internal:AsyncOverflowScrollingEnabled=true ] -->
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src="../../../resources/ui-helper.js"></script>
+<script src="../resources/overflow-scroll-overlap.js"></script>
+<style>
+.case {
+    width: 200px;
+    height: 200px;
+    display: inline-block;
+    position: relative;
+}
+.scrollcontent {
+    width: 500px;
+    height: 500px;
+    background: green;
+}
+
+.overflowscroll {
+    overflow: scroll;
+    height: 100px;
+    width: 100px;
+    border: 2px solid black;
+}
+.overlapping {
+    position:absolute;
+    left: 25px;
+    top: 25px;
+    width: 100px;
+    height: 100px;
+    background: red;
+}
+.clip {
+    position:absolute;
+    width: 100px;
+    height: 100px;
+    overflow:hidden;
+}
+.large {
+    width: 3000px;
+    height: 150px;
+}
+#log {
+    position:relative;
+    white-space: pre;
+}
+</style>
+</head>
+<body onload="runTest()">
+<p>
+Test that absolute positioned layer inside stacking-context overflow:scroll is correctly hit tested.
+</p>
+
+<div class="case">
+    <div class="overflowscroll target" style="opacity: 0.8;">
+        <div class="overlapping"></div>
+        <div class="scrollcontent"></div>
+    </div>
+</div>
+
+<div class="case">
+    <div class="overflowscroll target" style="opacity: 0.8;">
+        <div class="overlapping">
+            <div class="overlapping" style="left:10px;top:10px"></div>
+        </div>
+        <div class="scrollcontent"></div>
+    </div>
+</div>
+
+<div class="case">
+    <div class="overflowscroll target" style="position:relative;">
+        <div class="overflowscroll target" style="opacity: 0.8; margin:10px">
+            <div class="overlapping"></div>
+            <div class="scrollcontent"></div>
+        </div>
+        <div class="scrollcontent"></div>
+    </div>
+</div>
+
+<div id=log></div>
+
+</body>
+</html>
index 4183090..a972427 100644 (file)
@@ -1,3 +1,26 @@
+2019-03-22  Antti Koivisto  <antti@apple.com>
+
+        Handle UI side hit testing for ScrollPositioningBehavior::Stationary positioned nodes
+        https://bugs.webkit.org/show_bug.cgi?id=196100
+        <rdar://problem/49117933>
+
+        Reviewed by Simon Fraser.
+
+        Test: fast/scrolling/ios/overflow-scroll-overlap-6.html
+
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::commitTreeState):
+        * page/scrolling/ScrollingTree.h:
+        (WebCore::ScrollingTree::positionedNodesWithRelatedOverflow):
+
+        Add a separate map of positioned node ids for easy access.
+
+        * page/scrolling/cocoa/ScrollingTreePositionedNode.h:
+        (WebCore::ScrollingTreePositionedNode::scrollPositioningBehavior const):
+        (WebCore::ScrollingTreePositionedNode::relatedOverflowScrollingNodes const):
+        * page/scrolling/cocoa/ScrollingTreePositionedNode.mm:
+        (WebCore::ScrollingTreePositionedNode::commitStateBeforeChildren):
+
 2019-03-22  Antoine Quint  <graouts@apple.com>
 
         [Web Animations] com.apple.WebKit.WebContent.Development at com.apple.WebCore: WebCore::WebAnimation::timeToNextTick const + 757
index 45e4640..294c8f2 100644 (file)
@@ -175,6 +175,7 @@ void ScrollingTree::commitTreeState(std::unique_ptr<ScrollingStateTree> scrollin
         unvisitedNodes.add(nodeID);
 
     m_overflowRelatedNodesMap.clear();
+    m_positionedNodesWithRelatedOverflow.clear();
 
     // orphanNodes keeps child nodes alive while we rebuild child lists.
     OrphanScrollingNodeMap orphanNodes;
index b7be6f2..c4e2037 100644 (file)
@@ -150,6 +150,8 @@ public:
     using RelatedNodesMap = HashMap<ScrollingNodeID, Vector<ScrollingNodeID>>;
     RelatedNodesMap& overflowRelatedNodes() { return m_overflowRelatedNodesMap; }
 
+    HashSet<ScrollingNodeID>& positionedNodesWithRelatedOverflow() { return m_positionedNodesWithRelatedOverflow; }
+
     WEBCORE_EXPORT String scrollingTreeAsText(ScrollingStateTreeAsTextBehavior = ScrollingStateTreeAsTextBehaviorNormal);
     
 protected:
@@ -173,6 +175,7 @@ private:
     ScrollingTreeNodeMap m_nodeMap;
 
     RelatedNodesMap m_overflowRelatedNodesMap;
+    HashSet<ScrollingNodeID> m_positionedNodesWithRelatedOverflow;
 
     struct TreeState {
         ScrollingNodeID latchedNodeID { 0 };
index 1a50660..a1053ac 100644 (file)
@@ -43,6 +43,9 @@ public:
 
     CALayer *layer() const { return m_layer.get(); }
 
+    ScrollPositioningBehavior scrollPositioningBehavior() const { return m_constraints.scrollPositioningBehavior(); }
+    const Vector<ScrollingNodeID>& relatedOverflowScrollingNodes() const { return m_relatedOverflowScrollingNodes; }
+
 private:
     ScrollingTreePositionedNode(ScrollingTree&, ScrollingNodeID);
 
index c6b5863..14abd50 100644 (file)
@@ -72,6 +72,8 @@ void ScrollingTreePositionedNode::commitStateBeforeChildren(const ScrollingState
             }).iterator->value.append(scrollingNodeID());
         }
     }
+    if (!m_relatedOverflowScrollingNodes.isEmpty() && m_constraints.scrollPositioningBehavior() != ScrollPositioningBehavior::None)
+        scrollingTree().positionedNodesWithRelatedOverflow().add(scrollingNodeID());
 }
 
 void ScrollingTreePositionedNode::applyLayerPositions(const FloatRect&, FloatSize& cumulativeDelta)
index ef69908..4844455 100644 (file)
@@ -1,3 +1,33 @@
+2019-03-22  Antti Koivisto  <antti@apple.com>
+
+        Handle UI side hit testing for ScrollPositioningBehavior::Stationary positioned nodes
+        https://bugs.webkit.org/show_bug.cgi?id=196100
+        <rdar://problem/49117933>
+
+        Reviewed by Simon Fraser.
+
+        Test: fast/scrolling/ios/overflow-scroll-overlap-6.html
+
+        * UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h:
+        (WebKit::RemoteLayerTreeNode::relatedScrollContainerIDs const):
+        (WebKit::RemoteLayerTreeNode::relatedScrollContainerPositioningBehavior const):
+
+        Make more generic and save the associated positioning behavior.
+
+        (WebKit::RemoteLayerTreeNode::nonAncestorScrollContainerIDs const): Deleted.
+        (WebKit::RemoteLayerTreeNode::addNonAncestorScrollContainerID): Deleted.
+        (WebKit::RemoteLayerTreeNode::clearNonAncestorScrollContainerIDs): Deleted.
+        * UIProcess/RemoteLayerTree/RemoteLayerTreeNode.mm:
+        (WebKit::RemoteLayerTreeNode::setRelatedScrollContainerBehaviorAndIDs):
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
+        * UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm:
+        (WebKit::isScrolledBy):
+
+        Stationary relationship means the layer won't scroll the scroller.
+
+        * UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
+        (WebKit::RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations):
+
 2019-03-22  Chris Dumez  <cdumez@apple.com>
 
         REGRESSION (r243094): ePub files do not render or open in Books
index 350098b..700aa13 100644 (file)
@@ -59,10 +59,10 @@ public:
     const WebCore::Region& eventRegion() const { return m_eventRegion; }
     void setEventRegion(const WebCore::Region&);
 
-    // If empty the layer is scrolled by an ancestor scroller.
-    const auto& nonAncestorScrollContainerIDs() const { return m_nonAncestorScrollLayerIDs; }
-    void addNonAncestorScrollContainerID(WebCore::GraphicsLayer::PlatformLayerID layerID) { m_nonAncestorScrollLayerIDs.append(layerID); }
-    void clearNonAncestorScrollContainerIDs() { m_nonAncestorScrollLayerIDs.clear(); }
+    // If empty the layer is scrolled normally by an ancestor scroller.
+    const auto& relatedScrollContainerIDs() const { return m_relatedScrollContainerIDs; }
+    WebCore::ScrollPositioningBehavior relatedScrollContainerPositioningBehavior() const { return m_relatedScrollContainerPositioningBehavior; }
+    void setRelatedScrollContainerBehaviorAndIDs(WebCore::ScrollPositioningBehavior, Vector<WebCore::GraphicsLayer::PlatformLayerID>&&);
 
     void detachFromParent();
 
@@ -82,7 +82,9 @@ private:
 #endif
 
     WebCore::Region m_eventRegion;
-    Vector<WebCore::GraphicsLayer::PlatformLayerID> m_nonAncestorScrollLayerIDs;
+
+    Vector<WebCore::GraphicsLayer::PlatformLayerID> m_relatedScrollContainerIDs;
+    WebCore::ScrollPositioningBehavior m_relatedScrollContainerPositioningBehavior { WebCore::ScrollPositioningBehavior::None };
 };
 
 }
index 9200a68..d898fdf 100644 (file)
@@ -92,6 +92,12 @@ void RemoteLayerTreeNode::setEventRegion(const WebCore::Region& eventRegion)
     m_eventRegion = eventRegion;
 }
 
+void RemoteLayerTreeNode::setRelatedScrollContainerBehaviorAndIDs(WebCore::ScrollPositioningBehavior behavior, Vector<WebCore::GraphicsLayer::PlatformLayerID>&& scrollContainerIDs)
+{
+    m_relatedScrollContainerPositioningBehavior = behavior;
+    m_relatedScrollContainerIDs = WTFMove(scrollContainerIDs);
+}
+
 void RemoteLayerTreeNode::initializeLayer()
 {
     [layer() setValue:[NSValue valueWithPointer:this] forKey:WKRemoteLayerTreeNodePropertyKey];
index c07a559..a08070f 100644 (file)
@@ -127,7 +127,7 @@ private:
     unsigned m_currentVerticalSnapPointIndex { 0 };
 #endif
     bool m_propagatesMainFrameScrolls;
-    HashSet<WebCore::GraphicsLayer::PlatformLayerID> m_layersWithNonAncestorScrollingRelations;
+    HashSet<WebCore::GraphicsLayer::PlatformLayerID> m_layersWithScrollingRelations;
 };
 
 } // namespace WebKit
index 5aae321..27ad209 100644 (file)
@@ -74,8 +74,16 @@ static bool isScrolledBy(WKChildScrollView* scrollView, UIView *hitView)
             return true;
 
         auto* node = RemoteLayerTreeNode::forCALayer(view.layer);
-        if (node && scrollLayerID && node->nonAncestorScrollContainerIDs().contains(scrollLayerID))
-            return true;
+        if (node && scrollLayerID && node->relatedScrollContainerIDs().contains(scrollLayerID)) {
+            switch (node->relatedScrollContainerPositioningBehavior()) {
+            case WebCore::ScrollPositioningBehavior::Moves:
+                return true;
+            case WebCore::ScrollPositioningBehavior::Stationary:
+                return false;
+            case WebCore::ScrollPositioningBehavior::None:
+                ASSERT_NOT_REACHED();
+            }
+        }
     }
 
     return false;
index 62f12ba..70a01ef 100644 (file)
@@ -121,27 +121,28 @@ void RemoteScrollingCoordinatorProxy::scrollingTreeNodeDidEndScroll()
 
 void RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations(const RemoteLayerTreeHost& remoteLayerTreeHost)
 {
-    for (auto layerID : m_layersWithNonAncestorScrollingRelations) {
+    for (auto layerID : m_layersWithScrollingRelations) {
         if (auto* layerNode = remoteLayerTreeHost.nodeForID(layerID))
-            layerNode->clearNonAncestorScrollContainerIDs();
+            layerNode->setRelatedScrollContainerBehaviorAndIDs({ }, { });
     }
-    m_layersWithNonAncestorScrollingRelations.clear();
+    m_layersWithScrollingRelations.clear();
 
-    // Usually a scroll view scrolls its descendant layers. In some positioning cases it also controls non-descendants.
+    // Usually a scroll view scrolls its descendant layers. In some positioning cases it also controls non-descendants, or doesn't control a descendant.
     // To do overlap hit testing correctly we tell layers about such relations.
+    for (auto positionedNodeID : m_scrollingTree->positionedNodesWithRelatedOverflow()) {
+        auto* positionedNode = downcast<ScrollingTreePositionedNode>(m_scrollingTree->nodeForID(positionedNodeID));
+        auto* positionedLayerNode = RemoteLayerTreeNode::forCALayer(positionedNode->layer());
 
-    // FIXME: This doesn't contain ScrollPositioningBehavior::Stationary nodes. They will need to be handled too.
-    //        See https://bugs.webkit.org/show_bug.cgi?id=196100
-    for (auto& overflowAndPositionedNodeIDs : m_scrollingTree->overflowRelatedNodes()) {
-        auto* overflowNode = downcast<ScrollingTreeOverflowScrollingNode>(m_scrollingTree->nodeForID(overflowAndPositionedNodeIDs.key));
-        for (auto positionedNodeID : overflowAndPositionedNodeIDs.value) {
-            auto* positionedNode = downcast<ScrollingTreePositionedNode>(m_scrollingTree->nodeForID(positionedNodeID));
-            auto* positionedLayerNode = RemoteLayerTreeNode::forCALayer(positionedNode->layer());
+        Vector<GraphicsLayer::PlatformLayerID> scrollContainerLayerIDs;
 
-            positionedLayerNode->addNonAncestorScrollContainerID(RemoteLayerTreeNode::layerID(overflowNode->scrollContainerLayer()));
-
-            m_layersWithNonAncestorScrollingRelations.add(positionedLayerNode->layerID());
+        for (auto overflowNodeID : positionedNode->relatedOverflowScrollingNodes()) {
+            auto* overflowNode = downcast<ScrollingTreeOverflowScrollingNode>(m_scrollingTree->nodeForID(overflowNodeID));
+            scrollContainerLayerIDs.append(RemoteLayerTreeNode::layerID(overflowNode->scrollContainerLayer()));
         }
+
+        positionedLayerNode->setRelatedScrollContainerBehaviorAndIDs(positionedNode->scrollPositioningBehavior(), WTFMove(scrollContainerLayerIDs));
+
+        m_layersWithScrollingRelations.add(positionedLayerNode->layerID());
     }
 }