Changeset 243316 in webkit


Ignore:
Timestamp:
Mar 21, 2019 12:54:25 PM (5 years ago)
Author:
Antti Koivisto
Message:

UI-process hit-testing needs to know about containing block relationships
https://bugs.webkit.org/show_bug.cgi?id=195845
<rdar://problem/48949633>

Reviewed by Simon Fraser.

Source/WebCore:

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

  • page/scrolling/ScrollingTree.h:
  • page/scrolling/ScrollingTreeScrollingNode.h:
  • page/scrolling/cocoa/ScrollingTreePositionedNode.h:

(WebCore::ScrollingTreePositionedNode::layer const):

Source/WebKit:

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

When an overflow scroller contains a positioned element the element may not be on a descendant layer of the scroller,
yet should move along with it. This needs to be taken into account in UI-side hit testing.

  • UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h:

(WebKit::RemoteLayerTreeNode::nonAncestorScrollContainerIDs const):
(WebKit::RemoteLayerTreeNode::addNonAncestorScrollContainerID):
(WebKit::RemoteLayerTreeNode::clearNonAncestorScrollContainerIDs):

Maintain non-ancestor scrolling relationships for layers.

  • UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:

(WebKit::RemoteScrollingCoordinatorProxy::commitScrollingTreeState):
(WebKit::RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations):

  • UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
  • UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm:

(WebKit::isScrolledBy):

Helper to figure out who scrolls who.

(-[UIView _web_findDescendantViewAtPoint:withEvent:]):

  • UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:

(WebKit::RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations):

After commit, pull the non-ancestor scrolling relationships from the scrolling tree and update the layer tree.

LayoutTests:

  • fast/scrolling/ios/overflow-scroll-overlap-5-expected.txt: Added.
  • fast/scrolling/ios/overflow-scroll-overlap-5.html: Added.
Location:
trunk
Files:
2 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r243314 r243316  
     12019-03-21  Antti Koivisto  <antti@apple.com>
     2
     3        UI-process hit-testing needs to know about containing block relationships
     4        https://bugs.webkit.org/show_bug.cgi?id=195845
     5        <rdar://problem/48949633>
     6
     7        Reviewed by Simon Fraser.
     8
     9        * fast/scrolling/ios/overflow-scroll-overlap-5-expected.txt: Added.
     10        * fast/scrolling/ios/overflow-scroll-overlap-5.html: Added.
     11
    1122019-03-21  Shawn Roberts  <sroberts@apple.com>
    213
  • trunk/Source/WebCore/ChangeLog

    r243315 r243316  
     12019-03-21  Antti Koivisto  <antti@apple.com>
     2
     3        UI-process hit-testing needs to know about containing block relationships
     4        https://bugs.webkit.org/show_bug.cgi?id=195845
     5        <rdar://problem/48949633>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Test: fast/scrolling/ios/overflow-scroll-overlap-5.html
     10
     11        * page/scrolling/ScrollingTree.h:
     12        * page/scrolling/ScrollingTreeScrollingNode.h:
     13        * page/scrolling/cocoa/ScrollingTreePositionedNode.h:
     14        (WebCore::ScrollingTreePositionedNode::layer const):
     15
    1162019-03-21  Zalan Bujtas  <zalan@apple.com>
    217
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.h

    r242997 r243316  
    7474    virtual Ref<ScrollingTreeNode> createScrollingTreeNode(ScrollingNodeType, ScrollingNodeID) = 0;
    7575   
    76     ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
     76    WEBCORE_EXPORT ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
    7777
    7878    // Called after a scrolling tree node has handled a scroll and updated its layers.
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h

    r242687 r243316  
    8282    ScrollingTreeScrollingNode* scrollingNodeForPoint(LayoutPoint) const override;
    8383
     84#if PLATFORM(COCOA)
     85    CALayer *scrollContainerLayer() const { return m_scrollContainerLayer.get(); }
     86    CALayer *scrolledContentsLayer() const { return m_scrolledContentsLayer.get(); }
     87#endif
     88
    8489protected:
    8590    ScrollingTreeScrollingNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID);
     
    121126    bool expectsWheelEventTestTrigger() const { return m_expectsWheelEventTestTrigger; }
    122127
    123 #if PLATFORM(COCOA)
    124     CALayer *scrollContainerLayer() const { return m_scrollContainerLayer.get(); }
    125     CALayer *scrolledContentsLayer() const { return m_scrolledContentsLayer.get(); }
    126 #endif
    127 
    128128    LayoutPoint parentToLocalPoint(LayoutPoint) const override;
    129129    LayoutPoint localToContentsPoint(LayoutPoint) const override;
  • trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreePositionedNode.h

    r242997 r243316  
    4242    virtual ~ScrollingTreePositionedNode();
    4343
     44    CALayer *layer() const { return m_layer.get(); }
     45
    4446private:
    4547    ScrollingTreePositionedNode(ScrollingTree&, ScrollingNodeID);
  • trunk/Source/WebKit/ChangeLog

    r243302 r243316  
     12019-03-21  Antti Koivisto  <antti@apple.com>
     2
     3        UI-process hit-testing needs to know about containing block relationships
     4        https://bugs.webkit.org/show_bug.cgi?id=195845
     5        <rdar://problem/48949633>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Test: fast/scrolling/ios/overflow-scroll-overlap-5.html
     10
     11        When an overflow scroller contains a positioned element the element may not be on a descendant layer of the scroller,
     12        yet should move along with it. This needs to be taken into account in UI-side hit testing.
     13
     14        * UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h:
     15        (WebKit::RemoteLayerTreeNode::nonAncestorScrollContainerIDs const):
     16        (WebKit::RemoteLayerTreeNode::addNonAncestorScrollContainerID):
     17        (WebKit::RemoteLayerTreeNode::clearNonAncestorScrollContainerIDs):
     18
     19        Maintain non-ancestor scrolling relationships for layers.
     20
     21        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
     22        (WebKit::RemoteScrollingCoordinatorProxy::commitScrollingTreeState):
     23        (WebKit::RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations):
     24        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
     25        * UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm:
     26        (WebKit::isScrolledBy):
     27
     28        Helper to figure out who scrolls who.
     29
     30        (-[UIView _web_findDescendantViewAtPoint:withEvent:]):
     31        * UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm:
     32        (WebKit::RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations):
     33
     34        After commit, pull the non-ancestor scrolling relationships from the scrolling tree and update the layer tree.
     35
    1362019-03-21  Daniel Bates  <dabates@apple.com>
    237
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h

    r243007 r243316  
    2828#include <WebCore/GraphicsLayer.h>
    2929#include <wtf/RetainPtr.h>
     30#include <wtf/Vector.h>
    3031
    3132OBJC_CLASS CALayer;
     
    5960    void setEventRegion(const WebCore::Region&);
    6061
     62    // If empty the layer is scrolled by an ancestor scroller.
     63    const auto& nonAncestorScrollContainerIDs() const { return m_nonAncestorScrollLayerIDs; }
     64    void addNonAncestorScrollContainerID(WebCore::GraphicsLayer::PlatformLayerID layerID) { m_nonAncestorScrollLayerIDs.append(layerID); }
     65    void clearNonAncestorScrollContainerIDs() { m_nonAncestorScrollLayerIDs.clear(); }
     66
    6167    void detachFromParent();
    6268
     
    7783
    7884    WebCore::Region m_eventRegion;
     85    Vector<WebCore::GraphicsLayer::PlatformLayerID> m_nonAncestorScrollLayerIDs;
    7986};
    8087
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp

    r242979 r243316  
    8181    m_requestedScrollInfo = &requestedScrollInfo;
    8282
    83     // FIXME: There must be a better idiom for this.
    84     std::unique_ptr<ScrollingStateTree> stateTree(const_cast<RemoteScrollingCoordinatorTransaction&>(transaction).scrollingStateTree().release());
    85 
    86     const RemoteLayerTreeHost* layerTreeHost = this->layerTreeHost();
     83    auto stateTree = WTFMove(const_cast<RemoteScrollingCoordinatorTransaction&>(transaction).scrollingStateTree());
     84
     85    auto* layerTreeHost = this->layerTreeHost();
    8786    if (!layerTreeHost) {
    8887        ASSERT_NOT_REACHED();
     
    9291    connectStateNodeLayers(*stateTree, *layerTreeHost);
    9392    m_scrollingTree->commitTreeState(WTFMove(stateTree));
     93
     94    establishLayerTreeScrollingRelations(*layerTreeHost);
    9495
    9596    m_requestedScrollInfo = nullptr;
     
    164165    }
    165166}
     167
     168void RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations(const RemoteLayerTreeHost&)
     169{
     170}
     171
    166172#endif
    167173
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h

    r242687 r243316  
    3131#include "RemoteScrollingCoordinator.h"
    3232#include "RemoteScrollingTree.h"
     33#include <WebCore/GraphicsLayer.h>
    3334#include <wtf/Noncopyable.h>
    3435#include <wtf/RefPtr.h>
     
    109110private:
    110111    void connectStateNodeLayers(WebCore::ScrollingStateTree&, const RemoteLayerTreeHost&);
     112    void establishLayerTreeScrollingRelations(const RemoteLayerTreeHost&);
     113
    111114#if ENABLE(CSS_SCROLL_SNAP)
    112115    bool shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis) const;
     
    125128#endif
    126129    bool m_propagatesMainFrameScrolls;
     130    HashSet<WebCore::GraphicsLayer::PlatformLayerID> m_layersWithNonAncestorScrollingRelations;
    127131};
    128132
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm

    r243134 r243316  
    6666}
    6767
     68static bool isScrolledBy(WKChildScrollView* scrollView, UIView *hitView)
     69{
     70    auto scrollLayerID = RemoteLayerTreeNode::layerID(scrollView.layer);
     71
     72    for (UIView *view = hitView; view; view = [view superview]) {
     73        if (view == scrollView)
     74            return true;
     75
     76        auto* node = RemoteLayerTreeNode::forCALayer(view.layer);
     77        if (node && scrollLayerID && node->nonAncestorScrollContainerIDs().contains(scrollLayerID))
     78            return true;
     79    }
     80
     81    return false;
     82}
     83
    6884}
    6985
     
    90106
    91107        if ([view isKindOfClass:[WKChildScrollView class]]) {
    92             // See if the deepest view hit is actually a child of the scrollview.
    93             if ([viewsAtPoint.last() isDescendantOfView:view])
     108            if (WebKit::isScrolledBy((WKChildScrollView *)view, viewsAtPoint.last()))
    94109                return view;
    95110        }
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm

    r242913 r243316  
    4444#import <WebCore/ScrollTypes.h>
    4545#import <WebCore/ScrollingTreeFrameScrollingNode.h>
     46#import <WebCore/ScrollingTreeOverflowScrollingNode.h>
     47#import <WebCore/ScrollingTreePositionedNode.h>
    4648#endif
    4749
     
    118120}
    119121
     122void RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations(const RemoteLayerTreeHost& remoteLayerTreeHost)
     123{
     124    for (auto layerID : m_layersWithNonAncestorScrollingRelations) {
     125        if (auto* layerNode = remoteLayerTreeHost.nodeForID(layerID))
     126            layerNode->clearNonAncestorScrollContainerIDs();
     127    }
     128    m_layersWithNonAncestorScrollingRelations.clear();
     129
     130    // Usually a scroll view scrolls its descendant layers. In some positioning cases it also controls non-descendants.
     131    // To do overlap hit testing correctly we tell layers about such relations.
     132
     133    // FIXME: This doesn't contain ScrollPositioningBehavior::Stationary nodes. They will need to be handled too.
     134    //        See https://bugs.webkit.org/show_bug.cgi?id=196100
     135    for (auto& overflowAndPositionedNodeIDs : m_scrollingTree->overflowRelatedNodes()) {
     136        auto* overflowNode = downcast<ScrollingTreeOverflowScrollingNode>(m_scrollingTree->nodeForID(overflowAndPositionedNodeIDs.key));
     137        for (auto positionedNodeID : overflowAndPositionedNodeIDs.value) {
     138            auto* positionedNode = downcast<ScrollingTreePositionedNode>(m_scrollingTree->nodeForID(positionedNodeID));
     139            auto* positionedLayerNode = RemoteLayerTreeNode::forCALayer(positionedNode->layer());
     140
     141            positionedLayerNode->addNonAncestorScrollContainerID(RemoteLayerTreeNode::layerID(overflowNode->scrollContainerLayer()));
     142
     143            m_layersWithNonAncestorScrollingRelations.add(positionedLayerNode->layerID());
     144        }
     145    }
     146}
     147
    120148#if ENABLE(CSS_SCROLL_SNAP)
    121149void RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping(CGSize maxScrollOffsets, CGPoint velocity, CGFloat topInset, CGPoint* targetContentOffset)
Note: See TracChangeset for help on using the changeset viewer.