Add to InteractionInformationAtPosition information about whether the element is...
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Aug 2019 23:01:25 +0000 (23:01 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 8 Aug 2019 23:01:25 +0000 (23:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=200374
rdar://problem/54095519

Reviewed by Tim Horton.
Source/WebCore:

Add to InteractionInformationAtPosition a ScrollingNodeID which represents the enclosing scrolling
node that affects the targeted element's position. We use this to find a UIScrollView in the UI process.

The entrypoint to finding the enclosing scrolling node is ScrollingCoordinator::scrollableContainerNodeID(),
which calls RenderLayerCompositor::asyncScrollableContainerNodeID() to look for a scrolling ancestor in
the current frame, and then looks for an enclosing scrollable frame, or a scrolling ancestor in
the enclosing frame.

There's a bit of subtlety in RenderLayerCompositor::asyncScrollableContainerNodeID() because if you're asking
for the node that scrolls the renderer, if the renderer itself has a layer and is scrollable, you want
its enclosing scroller.

* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::AsyncScrollingCoordinator::scrollableContainerNodeID const):
* page/scrolling/AsyncScrollingCoordinator.h:
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::scrollableContainerNodeID const):
* page/scrolling/ScrollingCoordinator.h:
* rendering/RenderLayer.h:
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::asyncScrollableContainerNodeID):
* rendering/RenderLayerCompositor.h:

Source/WebKit:

Add InteractionInformationAtPosition.containerScrollingNodeID and initialize it in elementPositionInformation()
by asking the scrolling coordinator.

Also add a way to get from a ScrollingNodeID to a UIScrollView to RemoteScrollingCoordinatorProxy,
which gets the scrolling node and asks the delegate for the UIView.

* Shared/ios/InteractionInformationAtPosition.h:
* Shared/ios/InteractionInformationAtPosition.mm:
(WebKit::InteractionInformationAtPosition::encode const):
(WebKit::InteractionInformationAtPosition::decode):
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
* UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
(WebKit::RemoteScrollingCoordinatorProxy::scrollViewForScrollingNodeID const):
* UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h:
* UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
(WebKit::ScrollingTreeOverflowScrollingNodeIOS::scrollView const):
* UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::elementPositionInformation):

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

16 files changed:
Source/WebCore/ChangeLog
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
Source/WebCore/page/scrolling/AsyncScrollingCoordinator.h
Source/WebCore/page/scrolling/ScrollingCoordinator.cpp
Source/WebCore/page/scrolling/ScrollingCoordinator.h
Source/WebCore/rendering/RenderLayerCompositor.cpp
Source/WebCore/rendering/RenderLayerCompositor.h
Source/WebKit/ChangeLog
Source/WebKit/Shared/ios/InteractionInformationAtPosition.h
Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm
Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h
Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm
Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h
Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm
Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h
Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm

index eb1fdbd..995400c 100644 (file)
         (WebCore::WHLSL::EscapedVariableCollector::takeEscapedVariables): Deleted.
         * Modules/webgpu/WHLSL/WHLSLRecursionChecker.cpp:
 
+2019-08-08  Simon Fraser  <simon.fraser@apple.com>
+
+        Add to InteractionInformationAtPosition information about whether the element is in a subscrollable region
+        https://bugs.webkit.org/show_bug.cgi?id=200374
+        rdar://problem/54095519
+
+        Reviewed by Tim Horton.
+
+        Add to InteractionInformationAtPosition a ScrollingNodeID which represents the enclosing scrolling
+        node that affects the targeted element's position. We use this to find a UIScrollView in the UI process.
+        
+        The entrypoint to finding the enclosing scrolling node is ScrollingCoordinator::scrollableContainerNodeID(),
+        which calls RenderLayerCompositor::asyncScrollableContainerNodeID() to look for a scrolling ancestor in
+        the current frame, and then looks for an enclosing scrollable frame, or a scrolling ancestor in
+        the enclosing frame.
+        
+        There's a bit of subtlety in RenderLayerCompositor::asyncScrollableContainerNodeID() because if you're asking
+        for the node that scrolls the renderer, if the renderer itself has a layer and is scrollable, you want
+        its enclosing scroller.
+
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::AsyncScrollingCoordinator::scrollableContainerNodeID const):
+        * page/scrolling/AsyncScrollingCoordinator.h:
+        * page/scrolling/ScrollingCoordinator.cpp:
+        (WebCore::scrollableContainerNodeID const):
+        * page/scrolling/ScrollingCoordinator.h:
+        * rendering/RenderLayer.h:
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::asyncScrollableContainerNodeID):
+        * rendering/RenderLayerCompositor.h:
+
 2019-08-07  Saam Barati  <sbarati@apple.com>
 
         [WHLSL] cache results of argumentTypeForAndOverload inside Checker
index ae8a9fb..306cfed 100644 (file)
@@ -37,6 +37,8 @@
 #include "Logging.h"
 #include "Page.h"
 #include "PerformanceLoggingClient.h"
+#include "RenderLayerCompositor.h"
+#include "RenderView.h"
 #include "ScrollAnimator.h"
 #include "ScrollingConstraints.h"
 #include "ScrollingStateFixedNode.h"
@@ -789,6 +791,28 @@ bool AsyncScrollingCoordinator::asyncFrameOrOverflowScrollingEnabled() const
     return settings.asyncFrameScrollingEnabled() || settings.asyncOverflowScrollingEnabled();
 }
 
+ScrollingNodeID AsyncScrollingCoordinator::scrollableContainerNodeID(const RenderObject& renderer) const
+{
+    if (auto overflowScrollingNodeID = renderer.view().compositor().asyncScrollableContainerNodeID(renderer))
+        return overflowScrollingNodeID;
+
+    // If we're in a scrollable frame, return that.
+    auto* frameView = renderer.frame().view();
+    if (!frameView)
+        return 0;
+
+    if (auto scrollingNodeID = frameView->scrollingNodeID())
+        return scrollingNodeID;
+
+    // Otherwise, look for a scrollable element in the containing frame.
+    if (auto* ownerElement = renderer.document().ownerElement()) {
+        if (auto* frameRenderer = ownerElement->renderer())
+            return scrollableContainerNodeID(*frameRenderer);
+    }
+
+    return 0;
+}
+
 String AsyncScrollingCoordinator::scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior behavior) const
 {
     if (m_scrollingStateTree->rootStateNode()) {
index 05eec86..2877123 100644 (file)
@@ -91,6 +91,8 @@ private:
     
     bool asyncFrameOrOverflowScrollingEnabled() const;
 
+    WEBCORE_EXPORT ScrollingNodeID scrollableContainerNodeID(const RenderObject&) const override;
+
     WEBCORE_EXPORT void frameViewLayoutUpdated(FrameView&) override;
     WEBCORE_EXPORT void frameViewRootLayerDidChange(FrameView&) override;
     WEBCORE_EXPORT void frameViewVisualViewportChanged(FrameView&) override;
index 7898466..5b6e025 100644 (file)
@@ -96,6 +96,11 @@ bool ScrollingCoordinator::coordinatesScrollingForOverflowLayer(const RenderLaye
     return layer.hasCompositedScrollableOverflow();
 }
 
+ScrollingNodeID ScrollingCoordinator::scrollableContainerNodeID(const RenderObject&) const
+{
+    return 0;
+}
+
 EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegionsForFrame(const Frame& frame) const
 {
     auto* renderView = frame.contentRenderer();
index 84a7f4c..4a8cf8c 100644 (file)
@@ -59,6 +59,7 @@ class FrameView;
 class GraphicsLayer;
 class Page;
 class Region;
+class RenderObject;
 class RenderLayer;
 class ScrollableArea;
 class ViewportConstraints;
@@ -83,6 +84,9 @@ public:
     // Return whether this scrolling coordinator handles scrolling for the given overflow scroll layer.
     WEBCORE_EXPORT virtual bool coordinatesScrollingForOverflowLayer(const RenderLayer&) const;
 
+    // Returns the ScrollingNodeID of the innermost scrolling node that scrolls the renderer.
+    WEBCORE_EXPORT virtual ScrollingNodeID scrollableContainerNodeID(const RenderObject&) const;
+
     // Should be called whenever the given frame view has been laid out.
     virtual void frameViewLayoutUpdated(FrameView&) { }
 
index 8ff9f0f..4d2246d 100644 (file)
@@ -2707,6 +2707,37 @@ Vector<CompositedClipData> RenderLayerCompositor::computeAncestorClippingStack(c
     return newStack;
 }
 
+// Note that this returns the ScrollingNodeID of the scroller this layer is embedded in, not the layer's own ScrollingNodeID if it has one.
+ScrollingNodeID RenderLayerCompositor::asyncScrollableContainerNodeID(const RenderObject& renderer)
+{
+    auto* enclosingLayer = renderer.enclosingLayer();
+    if (!enclosingLayer)
+        return 0;
+    
+    auto layerScrollingNodeID = [](const RenderLayer& layer) -> ScrollingNodeID {
+        if (layer.isComposited())
+            return layer.backing()->scrollingNodeIDForRole(ScrollCoordinationRole::Scrolling);
+        return 0;
+    };
+
+    // If the renderer is inside the layer, we care about the layer's scrollability. Otherwise, we let traverseAncestorLayers look at ancestors.
+    if (!renderer.hasLayer()) {
+        if (auto scrollingNodeID = layerScrollingNodeID(*enclosingLayer))
+            return scrollingNodeID;
+    }
+
+    ScrollingNodeID containerScrollingNodeID = 0;
+    traverseAncestorLayers(*enclosingLayer, [&](const RenderLayer& ancestorLayer, bool isContainingBlockChain, bool /*isPaintOrderAncestor*/) {
+        if (isContainingBlockChain && ancestorLayer.hasCompositedScrollableOverflow()) {
+            containerScrollingNodeID = layerScrollingNodeID(ancestorLayer);
+            return AncestorTraversal::Stop;
+        }
+        return AncestorTraversal::Continue;
+    });
+
+    return containerScrollingNodeID;
+}
+
 // Return true if the given layer is a stacking context and has compositing child
 // layers that it needs to clip. In this case we insert a clipping GraphicsLayer
 // into the hierarchy between this layer and its children in the z-order hierarchy.
index 069ee97..bf645cd 100644 (file)
@@ -214,6 +214,10 @@ public:
 
     bool updateAncestorClippingStack(const RenderLayer&, const RenderLayer* compositingAncestor) const;
 
+    // Returns the ScrollingNodeID for the containing async-scrollable layer that scrolls this renderer's border box.
+    // May return 0 for position-fixed content.
+    static ScrollingNodeID asyncScrollableContainerNodeID(const RenderObject&);
+
     // Whether layer's backing needs a graphics layer to clip z-order children of the given layer.
     static bool clipsCompositingDescendants(const RenderLayer&);
 
index f3f66af..915513e 100644 (file)
         (-[WKContentView continueContextMenuInteractionWithDataDetectors:]): New method to
         use DataDetectors if possible.
 
+2019-08-08  Simon Fraser  <simon.fraser@apple.com>
+
+        Add to InteractionInformationAtPosition information about whether the element is in a subscrollable region
+        https://bugs.webkit.org/show_bug.cgi?id=200374
+        rdar://problem/54095519
+
+        Reviewed by Tim Horton.
+        
+        Add InteractionInformationAtPosition.containerScrollingNodeID and initialize it in elementPositionInformation()
+        by asking the scrolling coordinator.
+        
+        Also add a way to get from a ScrollingNodeID to a UIScrollView to RemoteScrollingCoordinatorProxy,
+        which gets the scrolling node and asks the delegate for the UIView.
+
+        * Shared/ios/InteractionInformationAtPosition.h:
+        * Shared/ios/InteractionInformationAtPosition.mm:
+        (WebKit::InteractionInformationAtPosition::encode const):
+        (WebKit::InteractionInformationAtPosition::decode):
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
+        * UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
+        (WebKit::RemoteScrollingCoordinatorProxy::scrollViewForScrollingNodeID const):
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.h:
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
+        (WebKit::ScrollingTreeOverflowScrollingNodeIOS::scrollView const):
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::elementPositionInformation):
+
 2019-08-07  Priyanka Agarwal  <pagarwal999@apple.com>
 
         Allow clients to toggle a text input field between being viewable and having characters hidden while maintaining 
index dccc0e9..6a47bd7 100644 (file)
@@ -31,6 +31,7 @@
 #include "InteractionInformationRequest.h"
 #include "ShareableBitmap.h"
 #include <WebCore/IntPoint.h>
+#include <WebCore/ScrollTypes.h>
 #include <WebCore/SelectionRect.h>
 #include <WebCore/TextIndicator.h>
 #include <wtf/URL.h>
@@ -61,6 +62,7 @@ struct InteractionInformationAtPosition {
     bool isAttachment { false };
     bool isAnimatedImage { false };
     bool isElement { false };
+    WebCore::ScrollingNodeID containerScrollingNodeID { 0 };
 #if ENABLE(DATA_DETECTION)
     bool isDataDetectorLink { false };
 #endif
index daf39ff..2ff3fd8 100644 (file)
@@ -56,6 +56,7 @@ void InteractionInformationAtPosition::encode(IPC::Encoder& encoder) const
     encoder << isAttachment;
     encoder << isAnimatedImage;
     encoder << isElement;
+    encoder << containerScrollingNodeID;
     encoder << adjustedPointForNodeRespondingToClickEvents;
     encoder << url;
     encoder << imageURL;
@@ -125,6 +126,9 @@ bool InteractionInformationAtPosition::decode(IPC::Decoder& decoder, Interaction
     if (!decoder.decode(result.isElement))
         return false;
 
+    if (!decoder.decode(result.containerScrollingNodeID))
+        return false;
+
     if (!decoder.decode(result.adjustedPointForNodeRespondingToClickEvents))
         return false;
 
index 72a8eac..86d0def 100644 (file)
@@ -34,6 +34,8 @@
 #include <wtf/Noncopyable.h>
 #include <wtf/RefPtr.h>
 
+OBJC_CLASS UIScrollView;
+
 namespace WebCore {
 class FloatPoint;
 class PlatformWheelEvent;
@@ -87,6 +89,8 @@ public:
     bool hasScrollableMainFrame() const;
 
 #if PLATFORM(IOS_FAMILY)
+    UIScrollView *scrollViewForScrollingNodeID(WebCore::ScrollingNodeID) const;
+
     WebCore::FloatRect currentLayoutViewport() const;
     void scrollingTreeNodeWillStartPanGesture();
     void scrollingTreeNodeWillStartScroll();
index 177390f..5452eba 100644 (file)
@@ -31,6 +31,7 @@
 
 #import "RemoteLayerTreeHost.h"
 #import "RemoteLayerTreeNode.h"
+#import "ScrollingTreeOverflowScrollingNodeIOS.h"
 #import "WebPageProxy.h"
 #import <UIKit/UIView.h>
 #import <WebCore/ScrollingStateFrameScrollingNode.h>
 namespace WebKit {
 using namespace WebCore;
 
+UIScrollView *RemoteScrollingCoordinatorProxy::scrollViewForScrollingNodeID(WebCore::ScrollingNodeID nodeID) const
+{
+    auto* treeNode = m_scrollingTree->nodeForID(nodeID);
+    if (!is<ScrollingTreeOverflowScrollingNode>(treeNode))
+        return nil;
+
+    auto* scrollingNode = downcast<ScrollingTreeOverflowScrollingNode>(treeNode);
+    // All ScrollingTreeOverflowScrollingNodes are ScrollingTreeOverflowScrollingNodeIOS on iOS.
+    return static_cast<ScrollingTreeOverflowScrollingNodeIOS*>(scrollingNode)->scrollView();
+}
+
 void RemoteScrollingCoordinatorProxy::connectStateNodeLayers(ScrollingStateTree& stateTree, const RemoteLayerTreeHost& layerTreeHost)
 {
     for (auto& currNode : stateTree.nodeMap().values()) {
index 5b986d2..8b6e91e 100644 (file)
@@ -29,6 +29,8 @@
 
 #include <WebCore/ScrollingTreeOverflowScrollingNode.h>
 
+OBJC_CLASS UIScrollView;
+
 namespace WebKit {
 
 class ScrollingTreeScrollingNodeDelegateIOS;
@@ -38,6 +40,8 @@ public:
     static Ref<ScrollingTreeOverflowScrollingNodeIOS> create(WebCore::ScrollingTree&, WebCore::ScrollingNodeID);
     virtual ~ScrollingTreeOverflowScrollingNodeIOS();
 
+    UIScrollView* scrollView() const;
+
 private:
     ScrollingTreeOverflowScrollingNodeIOS(WebCore::ScrollingTree&, WebCore::ScrollingNodeID);
 
index 18fe088..b56e2ea 100644 (file)
@@ -51,6 +51,11 @@ ScrollingTreeOverflowScrollingNodeIOS::~ScrollingTreeOverflowScrollingNodeIOS()
 {
 }
 
+UIScrollView* ScrollingTreeOverflowScrollingNodeIOS::scrollView() const
+{
+    return m_scrollingNodeDelegate->scrollView();
+}
+
 void ScrollingTreeOverflowScrollingNodeIOS::commitStateBeforeChildren(const WebCore::ScrollingStateNode& stateNode)
 {
     if (stateNode.hasChangedProperty(ScrollingStateScrollingNode::ScrollContainerLayer))
index 788d1c9..6489a8e 100644 (file)
@@ -74,10 +74,9 @@ public:
 #endif
 
     UIScrollView *findActingScrollParent(UIScrollView *);
-
-private:
     UIScrollView *scrollView() const;
 
+private:
     RetainPtr<CALayer> m_scrollLayer;
     RetainPtr<CALayer> m_scrolledContentsLayer;
     RetainPtr<WKScrollingNodeScrollViewDelegate> m_scrollViewDelegate;
index 30c0cbe..72d4283 100644 (file)
@@ -2683,6 +2683,14 @@ static void elementPositionInformation(WebPage& page, Element& element, const In
 #endif
     }
 
+    auto* elementForScrollTesting = linkElement ? linkElement : &element;
+    if (auto* renderer = elementForScrollTesting->renderer()) {
+#if ENABLE(ASYNC_SCROLLING)
+        if (auto* scrollingCoordinator = page.scrollingCoordinator())
+            info.containerScrollingNodeID = scrollingCoordinator->scrollableContainerNodeID(*renderer);
+#endif
+    }
+
     if (auto* renderer = element.renderer()) {
         if (renderer->isRenderImage())
             imagePositionInformation(page, element, request, info);