Diff
Modified: trunk/LayoutTests/ChangeLog (243315 => 243316)
--- trunk/LayoutTests/ChangeLog 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/LayoutTests/ChangeLog 2019-03-21 19:54:25 UTC (rev 243316)
@@ -1,3 +1,14 @@
+2019-03-21 Antti Koivisto <[email protected]>
+
+ 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.
+
+ * fast/scrolling/ios/overflow-scroll-overlap-5-expected.txt: Added.
+ * fast/scrolling/ios/overflow-scroll-overlap-5.html: Added.
+
2019-03-21 Shawn Roberts <[email protected]>
Unreviewed, rebaseline test after failure in 243211.
Added: trunk/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-5-expected.txt (0 => 243316)
--- trunk/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-5-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-5-expected.txt 2019-03-21 19:54:25 UTC (rev 243316)
@@ -0,0 +1,11 @@
+Test that scrollable areas with content that has complex containing block relationship are correctly targeted.
+
+case 1: Scrollable 1
+case 2: Scrollable 2
+case 3: Scrollable 3
+case 4: Scrollable 4
+case 5: Scrollable 5
+case 6: Scrollable 7
+case 7: Scrollable 10
+case 8: Scrollable 11
+
Added: trunk/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-5.html (0 => 243316)
--- trunk/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-5.html (rev 0)
+++ trunk/LayoutTests/fast/scrolling/ios/overflow-scroll-overlap-5.html 2019-03-21 19:54:25 UTC (rev 243316)
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<script src=""
+<script src=""
+<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;
+ position: absolute;
+ 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 scrollable areas with content that has complex containing block relationship are correctly targeted.
+</p>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent"></div>
+ <div class="overlapping" style="position:absolute;"></div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent"></div>
+ <div class="overlapping" style="top:-475px; position:relative;"></div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent"></div>
+ <div class="overlapping" style="position:absolute;">
+ <div class="overlapping" style="position:static; transform:translate3d(-50px, -5px, 0px)"></div>
+ </div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent"></div>
+ <div class="overlapping" style="top:-475px; position:relative;">
+ <div class="overlapping" style="position:static; transform:translate3d(-50px, -5px, 0px)"></div>
+ </div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="overflowscroll" style="left:25px; top:25px; position:absolute;">
+ <div class="scrollcontent"></div>
+ </div>
+ <div class="scrollcontent"></div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent"></div>
+ <div class="overflowscroll" style="left:60px; top:60px; position:absolute;">
+ <div class="scrollcontent"></div>
+ </div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent" style="position:absolute;"></div>
+ <div class="overflowscroll" style="position:absolute; left:25px;">
+ <div class="scrollcontent"></div>
+ <div class="overlapping" style="position:absolute;">
+ <div class="overlapping" style="position:static; transform:translate3d(-50px, -5px, 0px)"></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div class="case">
+ <div class="overflowscroll target">
+ <div class="scrollcontent" style="position:absolute;"></div>
+ <div class="overflowscroll" style="position:absolute; left:60px;">
+ <div class="scrollcontent"></div>
+ <div class="overlapping" style="position:absolute;">
+ <div class="overlapping" style="position:static; transform:translate3d(-50px, -5px, 0px)"></div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<div id=log></div>
+
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (243315 => 243316)
--- trunk/Source/WebCore/ChangeLog 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebCore/ChangeLog 2019-03-21 19:54:25 UTC (rev 243316)
@@ -1,3 +1,18 @@
+2019-03-21 Antti Koivisto <[email protected]>
+
+ 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.
+
+ 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):
+
2019-03-21 Zalan Bujtas <[email protected]>
[ContentChangeObserver] Cleanup reset state.
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (243315 => 243316)
--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h 2019-03-21 19:54:25 UTC (rev 243316)
@@ -73,7 +73,7 @@
virtual Ref<ScrollingTreeNode> createScrollingTreeNode(ScrollingNodeType, ScrollingNodeID) = 0;
- ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
+ WEBCORE_EXPORT ScrollingTreeNode* nodeForID(ScrollingNodeID) const;
// Called after a scrolling tree node has handled a scroll and updated its layers.
// Updates FrameView/RenderLayer scrolling state and GraphicsLayers.
Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h (243315 => 243316)
--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h 2019-03-21 19:54:25 UTC (rev 243316)
@@ -81,6 +81,11 @@
bool scrollLimitReached(const PlatformWheelEvent&) const;
ScrollingTreeScrollingNode* scrollingNodeForPoint(LayoutPoint) const override;
+#if PLATFORM(COCOA)
+ CALayer *scrollContainerLayer() const { return m_scrollContainerLayer.get(); }
+ CALayer *scrolledContentsLayer() const { return m_scrolledContentsLayer.get(); }
+#endif
+
protected:
ScrollingTreeScrollingNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID);
@@ -120,11 +125,6 @@
bool expectsWheelEventTestTrigger() const { return m_expectsWheelEventTestTrigger; }
-#if PLATFORM(COCOA)
- CALayer *scrollContainerLayer() const { return m_scrollContainerLayer.get(); }
- CALayer *scrolledContentsLayer() const { return m_scrolledContentsLayer.get(); }
-#endif
-
LayoutPoint parentToLocalPoint(LayoutPoint) const override;
LayoutPoint localToContentsPoint(LayoutPoint) const override;
Modified: trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreePositionedNode.h (243315 => 243316)
--- trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreePositionedNode.h 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebCore/page/scrolling/cocoa/ScrollingTreePositionedNode.h 2019-03-21 19:54:25 UTC (rev 243316)
@@ -41,6 +41,8 @@
virtual ~ScrollingTreePositionedNode();
+ CALayer *layer() const { return m_layer.get(); }
+
private:
ScrollingTreePositionedNode(ScrollingTree&, ScrollingNodeID);
Modified: trunk/Source/WebKit/ChangeLog (243315 => 243316)
--- trunk/Source/WebKit/ChangeLog 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebKit/ChangeLog 2019-03-21 19:54:25 UTC (rev 243316)
@@ -1,3 +1,38 @@
+2019-03-21 Antti Koivisto <[email protected]>
+
+ 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.
+
+ 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.
+
2019-03-21 Daniel Bates <[email protected]>
[iOS] Inline -_ensureFormAccessoryView into -formAccessoryView and have -_updateAccessory ensure we have a form accessory
Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h (243315 => 243316)
--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteLayerTreeNode.h 2019-03-21 19:54:25 UTC (rev 243316)
@@ -27,6 +27,7 @@
#include <WebCore/GraphicsLayer.h>
#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
OBJC_CLASS CALayer;
#if PLATFORM(IOS_FAMILY)
@@ -58,6 +59,11 @@
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(); }
+
void detachFromParent();
static WebCore::GraphicsLayer::PlatformLayerID layerID(CALayer *);
@@ -76,6 +82,7 @@
#endif
WebCore::Region m_eventRegion;
+ Vector<WebCore::GraphicsLayer::PlatformLayerID> m_nonAncestorScrollLayerIDs;
};
}
Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp (243315 => 243316)
--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp 2019-03-21 19:54:25 UTC (rev 243316)
@@ -80,10 +80,9 @@
{
m_requestedScrollInfo = &requestedScrollInfo;
- // FIXME: There must be a better idiom for this.
- std::unique_ptr<ScrollingStateTree> stateTree(const_cast<RemoteScrollingCoordinatorTransaction&>(transaction).scrollingStateTree().release());
+ auto stateTree = WTFMove(const_cast<RemoteScrollingCoordinatorTransaction&>(transaction).scrollingStateTree());
- const RemoteLayerTreeHost* layerTreeHost = this->layerTreeHost();
+ auto* layerTreeHost = this->layerTreeHost();
if (!layerTreeHost) {
ASSERT_NOT_REACHED();
return;
@@ -92,6 +91,8 @@
connectStateNodeLayers(*stateTree, *layerTreeHost);
m_scrollingTree->commitTreeState(WTFMove(stateTree));
+ establishLayerTreeScrollingRelations(*layerTreeHost);
+
m_requestedScrollInfo = nullptr;
}
@@ -163,6 +164,11 @@
}
}
}
+
+void RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations(const RemoteLayerTreeHost&)
+{
+}
+
#endif
bool RemoteScrollingCoordinatorProxy::handleWheelEvent(const PlatformWheelEvent& event)
Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h (243315 => 243316)
--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h 2019-03-21 19:54:25 UTC (rev 243316)
@@ -30,6 +30,7 @@
#include "MessageReceiver.h"
#include "RemoteScrollingCoordinator.h"
#include "RemoteScrollingTree.h"
+#include <WebCore/GraphicsLayer.h>
#include <wtf/Noncopyable.h>
#include <wtf/RefPtr.h>
@@ -108,6 +109,8 @@
private:
void connectStateNodeLayers(WebCore::ScrollingStateTree&, const RemoteLayerTreeHost&);
+ void establishLayerTreeScrollingRelations(const RemoteLayerTreeHost&);
+
#if ENABLE(CSS_SCROLL_SNAP)
bool shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis) const;
float closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis, float scrollDestination, float velocity, unsigned& closestIndex) const;
@@ -124,6 +127,7 @@
unsigned m_currentVerticalSnapPointIndex { 0 };
#endif
bool m_propagatesMainFrameScrolls;
+ HashSet<WebCore::GraphicsLayer::PlatformLayerID> m_layersWithNonAncestorScrollingRelations;
};
} // namespace WebKit
Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm (243315 => 243316)
--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteLayerTreeViews.mm 2019-03-21 19:54:25 UTC (rev 243316)
@@ -65,8 +65,24 @@
};
}
+static bool isScrolledBy(WKChildScrollView* scrollView, UIView *hitView)
+{
+ auto scrollLayerID = RemoteLayerTreeNode::layerID(scrollView.layer);
+
+ for (UIView *view = hitView; view; view = [view superview]) {
+ if (view == scrollView)
+ return true;
+
+ auto* node = RemoteLayerTreeNode::forCALayer(view.layer);
+ if (node && scrollLayerID && node->nonAncestorScrollContainerIDs().contains(scrollLayerID))
+ return true;
+ }
+
+ return false;
}
+}
+
@interface UIView (WKHitTesting)
- (UIView *)_web_findDescendantViewAtPoint:(CGPoint)point withEvent:(UIEvent *)event;
@end
@@ -89,8 +105,7 @@
}
if ([view isKindOfClass:[WKChildScrollView class]]) {
- // See if the deepest view hit is actually a child of the scrollview.
- if ([viewsAtPoint.last() isDescendantOfView:view])
+ if (WebKit::isScrolledBy((WKChildScrollView *)view, viewsAtPoint.last()))
return view;
}
}
Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm (243315 => 243316)
--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm 2019-03-21 19:52:18 UTC (rev 243315)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/RemoteScrollingCoordinatorProxyIOS.mm 2019-03-21 19:54:25 UTC (rev 243316)
@@ -43,6 +43,8 @@
#import <WebCore/ScrollSnapOffsetsInfo.h>
#import <WebCore/ScrollTypes.h>
#import <WebCore/ScrollingTreeFrameScrollingNode.h>
+#import <WebCore/ScrollingTreeOverflowScrollingNode.h>
+#import <WebCore/ScrollingTreePositionedNode.h>
#endif
namespace WebKit {
@@ -117,6 +119,32 @@
m_webPageProxy.scrollingNodeScrollDidEndScroll();
}
+void RemoteScrollingCoordinatorProxy::establishLayerTreeScrollingRelations(const RemoteLayerTreeHost& remoteLayerTreeHost)
+{
+ for (auto layerID : m_layersWithNonAncestorScrollingRelations) {
+ if (auto* layerNode = remoteLayerTreeHost.nodeForID(layerID))
+ layerNode->clearNonAncestorScrollContainerIDs();
+ }
+ m_layersWithNonAncestorScrollingRelations.clear();
+
+ // Usually a scroll view scrolls its descendant layers. In some positioning cases it also controls non-descendants.
+ // To do overlap hit testing correctly we tell layers about such relations.
+
+ // 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());
+
+ positionedLayerNode->addNonAncestorScrollContainerID(RemoteLayerTreeNode::layerID(overflowNode->scrollContainerLayer()));
+
+ m_layersWithNonAncestorScrollingRelations.add(positionedLayerNode->layerID());
+ }
+ }
+}
+
#if ENABLE(CSS_SCROLL_SNAP)
void RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping(CGSize maxScrollOffsets, CGPoint velocity, CGFloat topInset, CGPoint* targetContentOffset)
{