Title: [240579] trunk
Revision
240579
Author
[email protected]
Date
2019-01-28 07:08:54 -0800 (Mon, 28 Jan 2019)

Log Message

Limit user-agent interactions based on the touch-action property on iOS
https://bugs.webkit.org/show_bug.cgi?id=193447
<rdar://problem/47283874>

Reviewed by Antti Koivisto and Simon Fraser.

Source/WebCore:

We now compile a list of elements with a non-auto touch-action property that is updated whenever an element has its style changed
or is removed from its document. When the content of that list changes, we inform the scrolling coordinator such that it can compile
a list of TouchActionData structures which hold the touch-action value, the ID of the nearest scroll node and the Region containing
the bounds of each of those elements to send it up to the UI process along with touch regions. Computing the list of allowed touch
actions for a given element accounts for not only the value specified directly on that element's style, but also in its hierarchy,
crossing any frame boundary towards the top-level document's root node.

Tests: pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html
       pointerevents/ios/touch-action-none-on-iframe.html
       pointerevents/ios/touch-action-none-on-parent.html
       pointerevents/ios/touch-action-none.html
       pointerevents/ios/touch-action-pan-x-pan-y.html
       pointerevents/ios/touch-action-pan-x.html
       pointerevents/ios/touch-action-pan-y.html
       pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html
       pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html

* WebCore.xcodeproj/project.pbxproj: Update how certain headers are exposed such that they can be used from WebKit.
* dom/Document.cpp:
(WebCore::Document::invalidateRenderingDependentRegions):
(WebCore::Document::nodeWillBeRemoved): Ensure a node that is being removed from this document is no longer listed in its
list of elements with a non-auto touch-action property.
(WebCore::Document::absoluteEventRegionForNode):
(WebCore::Document::absoluteRegionForEventTargets):
(WebCore::Document::updateTouchActionElements): Create a list of elements with a non-auto touch-action property if one doesn't
exist yet and update it to add the given element if it contains a non-auto touch-action, or remove it if it doesn't. If the contents
of that list changed as a result, the scrolling coordinator is informed.
* dom/Document.h:
(WebCore::Document:: const):
* dom/Element.cpp:
(WebCore::parentCrossingFrameBoundaries):
(WebCore::Element::computedTouchActions const): Provide the list of allowed touch actions accounting for the "touch-action" property
specified on this element and all of its hierarchy, crossing frame boundary.
(WebCore::Element::nearestScrollingNodeIDUsingTouchOverflowScrolling const): Provide the ScrollingNodeID, if any, for the nearest scrolling node
for that element. This will allow the UI process to identify which scroll view's behavior to customize to reflect the element's allowed
touch actions.
* dom/Element.h:
* page/scrolling/ScrollingCoordinator.cpp:
(WebCore::ScrollingCoordinator::absoluteEventTrackingRegionsForFrame const): Compute the region for all elements with a non-auto touch-action property
throughout the provided frame and all of its subframes.
* page/scrolling/ScrollingCoordinator.h:
(WebCore::ScrollableAreaParameters::operator== const): Deleted.
* page/scrolling/ScrollingCoordinatorTypes.h: Added.
(WebCore::ScrollableAreaParameters::operator== const):
* page/scrolling/ScrollingTree.cpp:
(WebCore::ScrollingTree::touchActionDataAtPoint const): Query the list of TouchActionData objects for a match based on the provided point. Right
now the logic is pretty crude, stopping at the first TouchActionData for which the region contains the provided point, but future patches will
account for overlap and nesting.
* page/scrolling/ScrollingTree.h:
* page/scrolling/ScrollingTreeNode.h:
* platform/EventTrackingRegions.cpp:
(WebCore::operator==):
* platform/EventTrackingRegions.h:
(WebCore::operator!=):
* style/StyleTreeResolver.cpp:
(WebCore::Style::TreeResolver::resolveElement): Update the list of elements with a non-auto touch-action property when an element's style changes.

Source/WebKit:

Handle the "none", "pan-x", "pan-y" and "pinch-zoom" values for the touch-action property by querying the scrolling tree whenever a touch begins
to identify whether its point is contained within the region of an element with a non-auto touch-action property. If it is, we use the list of
permitted touch actions such to then customize the behavior of the nearest scroll view to pan or zoom only as instructed.

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<TouchActionData>::encode):
(IPC::ArgumentCoder<TouchActionData>::decode):
(IPC::ArgumentCoder<EventTrackingRegions>::encode):
(IPC::ArgumentCoder<EventTrackingRegions>::decode):
(IPC::ArgumentCoder<Region>::decode):
* Shared/WebCoreArgumentCoders.h:
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Account for panning constraints set on the content view to prevent deceleration
to pan the view if it ought not.
(-[WKWebView _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Implement an additional
UIScrollView delegation method to apply the panning constraints set on the content view while panning.
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
(WebKit::RemoteScrollingCoordinatorProxy::touchActionDataAtPoint const):
(WebKit::RemoteScrollingCoordinatorProxy::touchActionDataForScrollNodeID const):
(WebKit::RemoteScrollingCoordinatorProxy::setTouchDataForTouchIdentifier):
(WebKit::RemoteScrollingCoordinatorProxy::clearTouchDataForTouchIdentifier):
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
* UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
* UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
(-[WKScrollingNodeScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Apply the same logic as in WKWebView.
(-[WKScrollingNodeScrollViewDelegate _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Apply
the same logic as in WKWebView.
(WebKit::ScrollingTreeScrollingNodeDelegateIOS::touchActionData const):
* UIProcess/WebPageProxy.h:
(WebKit::WebPageProxy::isScrollingOrZooming const):
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView preventsPanningInXAxis]):
(-[WKContentView preventsPanningInYAxis]):
(-[WKContentView cleanupInteraction]):
(-[WKContentView _webTouchEventsRecognized:]):
(-[WKContentView _handleTouchActionsForTouchEvent:]): As we process touches, check whether there are touch actions set for this touch's points' locations. Based
on those touch actions, either setDefaultPrevented on the _touchEventGestureRecognizer if the touch action is "none" or selectively disable panning and zooming.
(-[WKContentView _resetPanningPreventionFlags]):
(-[WKContentView _didEndScrollingOrZooming]):

LayoutTests:

Add a new series of tests that check that the "none", "pan-x", "pan-y" and "pinch-zoom" values have the expected
impact on page panning on iOS.

* pointerevents/ios/touch-action-none-expected.txt: Added.
* pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt: Added.
* pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html: Added.
* pointerevents/ios/touch-action-none-on-iframe-expected.txt: Added.
* pointerevents/ios/touch-action-none-on-iframe.html: Added.
* pointerevents/ios/touch-action-none-on-parent-expected.txt: Added.
* pointerevents/ios/touch-action-none-on-parent.html: Added.
* pointerevents/ios/touch-action-none.html: Added.
* pointerevents/ios/touch-action-pan-x-expected.txt: Added.
* pointerevents/ios/touch-action-pan-x-pan-y-expected.txt: Added.
* pointerevents/ios/touch-action-pan-x-pan-y.html: Added.
* pointerevents/ios/touch-action-pan-x.html: Added.
* pointerevents/ios/touch-action-pan-y-expected.txt: Added.
* pointerevents/ios/touch-action-pan-y.html: Added.
* pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt: Added.
* pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html: Added.
* pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt: Added.
* pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (240578 => 240579)


--- trunk/LayoutTests/ChangeLog	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/LayoutTests/ChangeLog	2019-01-28 15:08:54 UTC (rev 240579)
@@ -1,3 +1,33 @@
+2019-01-28  Antoine Quint  <[email protected]>
+
+        Limit user-agent interactions based on the touch-action property on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=193447
+        <rdar://problem/47283874>
+
+        Reviewed by Antti Koivisto and Simon Fraser.
+
+        Add a new series of tests that check that the "none", "pan-x", "pan-y" and "pinch-zoom" values have the expected
+        impact on page panning on iOS.
+
+        * pointerevents/ios/touch-action-none-expected.txt: Added.
+        * pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt: Added.
+        * pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html: Added.
+        * pointerevents/ios/touch-action-none-on-iframe-expected.txt: Added.
+        * pointerevents/ios/touch-action-none-on-iframe.html: Added.
+        * pointerevents/ios/touch-action-none-on-parent-expected.txt: Added.
+        * pointerevents/ios/touch-action-none-on-parent.html: Added.
+        * pointerevents/ios/touch-action-none.html: Added.
+        * pointerevents/ios/touch-action-pan-x-expected.txt: Added.
+        * pointerevents/ios/touch-action-pan-x-pan-y-expected.txt: Added.
+        * pointerevents/ios/touch-action-pan-x-pan-y.html: Added.
+        * pointerevents/ios/touch-action-pan-x.html: Added.
+        * pointerevents/ios/touch-action-pan-y-expected.txt: Added.
+        * pointerevents/ios/touch-action-pan-y.html: Added.
+        * pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt: Added.
+        * pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html: Added.
+        * pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt: Added.
+        * pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html: Added.
+
 2019-01-28  Nikita Vasilyev  <[email protected]>
 
         Web Inspector: Add Changes panel to Elements tab

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: none on an element prevents page scrolling. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: none in content hosted in a scrollable container using '-webkit-overflow-scrolling: touch' prevents scrolling of that container. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+
+#scrolling-container {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 400px;
+    height: 400px;
+    overflow: scroll;
+    -webkit-overflow-scrolling: touch;
+}
+
+#scrolling-container > div {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 200%;
+    height: 200%;
+    touch-action: none;
+}
+
+</style>
+</head>
+<body>
+<div id="scrolling-container"><div></div></div>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+async_test(test => {
+    const scrollingContainer = document.body.firstElementChild;
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_equals(scrollingContainer.scrollLeft, 0, "The scrolling container was not scrolled in the x-axis.");
+        assert_equals(scrollingContainer.scrollTop, 0, "The scrolling container was not scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: none in content hosted in a scrollable container using '-webkit-overflow-scrolling: touch' prevents scrolling of that container.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-on-iframe-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-on-iframe-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-on-iframe-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,4 @@
+
+
+PASS Testing that setting touch-action: none on an iframe and interacting with its content prevents page scrolling. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-on-iframe.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-on-iframe.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-on-iframe.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<style>
+
+iframe {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 400px;
+    height: 400px;
+    touch-action: none;
+}
+
+</style>
+</head>
+<body>
+<iframe></iframe>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+async_test(test => {
+    const iframe = document.body.firstElementChild;
+    const target = iframe.contentDocument.body.appendChild(document.createElement("div"));
+    target.setAttribute("style", `
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 200%;
+        height: 200%;
+    `);
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
+        assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: none on an iframe and interacting with its content prevents page scrolling.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-on-parent-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-on-parent-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-on-parent-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: none on a parent element prevents page scrolling. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none-on-parent.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none-on-parent.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none-on-parent.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "200px", height: "200px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+    document.body.style.touchAction = "none";
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
+        assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: none on a parent element prevents page scrolling.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-none.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-none.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-none.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "200px", height: "200px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+
+    target.style.touchAction = "none";
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
+        assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: none on an element prevents page scrolling.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: pan-x on an element prevents page scrolling in the y-axis. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting 'touch-action: pan-x pan-y' on an element allows page scrolling in both axes. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "200px", height: "200px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+
+    target.style.touchAction = "pan-x pan-y";
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_not_equals(window.pageXOffset, 0, "The page was scrolled in the x-axis.");
+        assert_not_equals(window.pageYOffset, 0, "The page was scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting 'touch-action: pan-x pan-y' on an element allows page scrolling in both axes.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pan-x.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pan-x.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pan-x.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "200px", height: "200px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+
+    target.style.touchAction = "pan-x";
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_not_equals(window.pageXOffset, 0, "The page was scrolled in the x-axis.");
+        assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: pan-x on an element prevents page scrolling in the y-axis.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: pan-x on an element prevents page scrolling in the x-axis. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pan-y.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pan-y.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pan-y.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "200px", height: "200px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+
+    target.style.touchAction = "pan-y";
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
+        assert_not_equals(window.pageYOffset, 0, "The page was scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: pan-x on an element prevents page scrolling in the x-axis.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: pinch-zoom on an element allows page zooming. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,29 @@
+<!DOCTYPE html><!-- webkit-test-runner [ useFlexibleViewport=true ] -->
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "400px", height: "400px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+
+    target.style.touchAction = "pinch-zoom";
+
+    ui.pinchOut({ x: 50, y: 50, width: 100, height: 100, scale: 0.5 }).then(() => {
+        assert_not_equals(window.internals.pageScaleFactor(), 1, "The page was scaled.");
+        test.done();
+    });
+}, "Testing that setting touch-action: pinch-zoom on an element allows page zooming.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,3 @@
+
+PASS Testing that setting touch-action: pinch-zoom on an element prevents page scrolling. 
+

Added: trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html (0 => 240579)


--- trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html	                        (rev 0)
+++ trunk/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width, initial-scale=1">
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script>
+
+'use strict';
+
+target_test({ width: "200px", height: "200px" }, (target, test) => {
+    document.body.style.width = "2000px";
+    document.body.style.height = "2000px";
+
+    target.style.touchAction = "pinch-zoom";
+
+    ui.swipe({ x: 150, y: 150 }, { x: 50, y: 50 }).then(() => {
+        assert_equals(window.pageXOffset, 0, "The page was not scrolled in the x-axis.");
+        assert_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis.");
+        test.done();
+    });
+}, "Testing that setting touch-action: pinch-zoom on an element prevents page scrolling.");
+
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (240578 => 240579)


--- trunk/Source/WebCore/ChangeLog	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/ChangeLog	2019-01-28 15:08:54 UTC (rev 240579)
@@ -1,3 +1,68 @@
+2019-01-28  Antoine Quint  <[email protected]>
+
+        Limit user-agent interactions based on the touch-action property on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=193447
+        <rdar://problem/47283874>
+
+        Reviewed by Antti Koivisto and Simon Fraser.
+
+        We now compile a list of elements with a non-auto touch-action property that is updated whenever an element has its style changed
+        or is removed from its document. When the content of that list changes, we inform the scrolling coordinator such that it can compile
+        a list of TouchActionData structures which hold the touch-action value, the ID of the nearest scroll node and the Region containing
+        the bounds of each of those elements to send it up to the UI process along with touch regions. Computing the list of allowed touch
+        actions for a given element accounts for not only the value specified directly on that element's style, but also in its hierarchy,
+        crossing any frame boundary towards the top-level document's root node.
+
+        Tests: pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html
+               pointerevents/ios/touch-action-none-on-iframe.html
+               pointerevents/ios/touch-action-none-on-parent.html
+               pointerevents/ios/touch-action-none.html
+               pointerevents/ios/touch-action-pan-x-pan-y.html
+               pointerevents/ios/touch-action-pan-x.html
+               pointerevents/ios/touch-action-pan-y.html
+               pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html
+               pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html
+
+        * WebCore.xcodeproj/project.pbxproj: Update how certain headers are exposed such that they can be used from WebKit.
+        * dom/Document.cpp:
+        (WebCore::Document::invalidateRenderingDependentRegions):
+        (WebCore::Document::nodeWillBeRemoved): Ensure a node that is being removed from this document is no longer listed in its
+        list of elements with a non-auto touch-action property.
+        (WebCore::Document::absoluteEventRegionForNode):
+        (WebCore::Document::absoluteRegionForEventTargets):
+        (WebCore::Document::updateTouchActionElements): Create a list of elements with a non-auto touch-action property if one doesn't
+        exist yet and update it to add the given element if it contains a non-auto touch-action, or remove it if it doesn't. If the contents
+        of that list changed as a result, the scrolling coordinator is informed.
+        * dom/Document.h:
+        (WebCore::Document:: const):
+        * dom/Element.cpp:
+        (WebCore::parentCrossingFrameBoundaries):
+        (WebCore::Element::computedTouchActions const): Provide the list of allowed touch actions accounting for the "touch-action" property
+        specified on this element and all of its hierarchy, crossing frame boundary.
+        (WebCore::Element::nearestScrollingNodeIDUsingTouchOverflowScrolling const): Provide the ScrollingNodeID, if any, for the nearest scrolling node
+        for that element. This will allow the UI process to identify which scroll view's behavior to customize to reflect the element's allowed
+        touch actions.
+        * dom/Element.h:
+        * page/scrolling/ScrollingCoordinator.cpp:
+        (WebCore::ScrollingCoordinator::absoluteEventTrackingRegionsForFrame const): Compute the region for all elements with a non-auto touch-action property
+        throughout the provided frame and all of its subframes.
+        * page/scrolling/ScrollingCoordinator.h:
+        (WebCore::ScrollableAreaParameters::operator== const): Deleted.
+        * page/scrolling/ScrollingCoordinatorTypes.h: Added.
+        (WebCore::ScrollableAreaParameters::operator== const):
+        * page/scrolling/ScrollingTree.cpp:
+        (WebCore::ScrollingTree::touchActionDataAtPoint const): Query the list of TouchActionData objects for a match based on the provided point. Right
+        now the logic is pretty crude, stopping at the first TouchActionData for which the region contains the provided point, but future patches will
+        account for overlap and nesting.
+        * page/scrolling/ScrollingTree.h:
+        * page/scrolling/ScrollingTreeNode.h:
+        * platform/EventTrackingRegions.cpp:
+        (WebCore::operator==):
+        * platform/EventTrackingRegions.h:
+        (WebCore::operator!=):
+        * style/StyleTreeResolver.cpp:
+        (WebCore::Style::TreeResolver::resolveElement): Update the list of elements with a non-auto touch-action property when an element's style changes.
+
 2019-01-27  Michael Catanzaro  <[email protected]>
 
         Unreviewed, fix WPE/GTK debug builds after r240557

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (240578 => 240579)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2019-01-28 15:08:54 UTC (rev 240579)
@@ -2096,6 +2096,7 @@
 		712BE4831FE865DD002031CC /* FillMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 712BE4811FE865D4002031CC /* FillMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		712BE4881FE8686A002031CC /* JSFillMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 712BE4851FE86818002031CC /* JSFillMode.h */; };
 		712BE4891FE86875002031CC /* JSPlaybackDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 712BE4861FE86859002031CC /* JSPlaybackDirection.h */; };
+		712DBA4921F8AD83008F36B2 /* ScrollingCoordinatorTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 712DBA4721F8AD79008F36B2 /* ScrollingCoordinatorTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		713171341FBE78DB00F758DE /* CSSPropertyBlendingClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 713171321FBE78C500F758DE /* CSSPropertyBlendingClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7132445120109DA500AE7FB2 /* WebAnimationUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 7132444F20109D9B00AE7FB2 /* WebAnimationUtilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		7134496E146941B300720312 /* SVGLengthContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 7134496C146941B300720312 /* SVGLengthContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2418,7 +2419,7 @@
 		834476EF1DA5BC5E002B6ED2 /* JSScrollToOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 83E9B3011DA5A51E00FFE8F6 /* JSScrollToOptions.h */; };
 		8348BFAC1B85729800912F36 /* ClassCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8348BFAA1B85729500912F36 /* ClassCollection.h */; };
 		834DFAD01F7DAE5D00C2725B /* SharedStringHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 834DFACC1F7DAE5600C2725B /* SharedStringHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		83520C7E1A71BFCC006BD2AA /* CSSFontFamily.h in Headers */ = {isa = PBXBuildFile; fileRef = 83520C7D1A71BFCC006BD2AA /* CSSFontFamily.h */; };
+		83520C7E1A71BFCC006BD2AA /* CSSFontFamily.h in Headers */ = {isa = PBXBuildFile; fileRef = 83520C7D1A71BFCC006BD2AA /* CSSFontFamily.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		8358CB701C53277500E0C2D8 /* JSXMLDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F570AD1C53268E007FD6CB /* JSXMLDocument.h */; };
 		835D2D781F5F1FBD00141DED /* HTMLInputElementEntriesAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 835D2D751F5F1FB800141DED /* HTMLInputElementEntriesAPI.h */; };
 		835D363719FF6193004C93AB /* StyleBuilderCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = 835D363619FF6193004C93AB /* StyleBuilderCustom.h */; };
@@ -2904,7 +2905,7 @@
 		9920398318B95BC600B39AF9 /* UserInputBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = 9920398118B95BC600B39AF9 /* UserInputBridge.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		996E59DF1DF0128D006612B9 /* NavigatorWebDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 996E59DC1DF00D90006612B9 /* NavigatorWebDriver.h */; };
 		9A528E8417D7F52F00AA9518 /* FloatingObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A528E8217D7F52F00AA9518 /* FloatingObjects.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		9AB1F38018E2489A00534743 /* CSSToLengthConversionData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AB1F37E18E2489A00534743 /* CSSToLengthConversionData.h */; };
+		9AB1F38018E2489A00534743 /* CSSToLengthConversionData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AB1F37E18E2489A00534743 /* CSSToLengthConversionData.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B24DE8E15194B9500C59C27 /* HTMLBDIElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B24DE8C15194B9500C59C27 /* HTMLBDIElement.h */; };
 		9B2D8A7914997CCF00ECEF3E /* UndoStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B2D8A7814997CCF00ECEF3E /* UndoStep.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B32CDA913DF7FA900F34D13 /* RenderedPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B32CDA713DF7FA900F34D13 /* RenderedPosition.h */; };
@@ -4782,7 +4783,7 @@
 		E1E1BF00115FF6FB006F52CA /* WindowsKeyboardCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = E1E1BEFF115FF6FB006F52CA /* WindowsKeyboardCodes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E1E6EEA80B628DB3005F2F70 /* JSHTMLSelectElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E1E6EEA70B628DB3005F2F70 /* JSHTMLSelectElement.h */; };
 		E1EC29A00BB04C6B00EA187B /* XPathNodeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = E1EC299E0BB04C6B00EA187B /* XPathNodeSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
-		E1ED8AC30CC49BE000BFC557 /* CSSPrimitiveValueMappings.h in Headers */ = {isa = PBXBuildFile; fileRef = E1ED8AC20CC49BE000BFC557 /* CSSPrimitiveValueMappings.h */; };
+		E1ED8AC30CC49BE000BFC557 /* CSSPrimitiveValueMappings.h in Headers */ = {isa = PBXBuildFile; fileRef = E1ED8AC20CC49BE000BFC557 /* CSSPrimitiveValueMappings.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E1F1E8300C3C2BB9006DB391 /* XSLTExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F1E82E0C3C2BB9006DB391 /* XSLTExtensions.h */; };
 		E1F80B8818317252007885C3 /* CryptoKeyPair.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F80B8618317252007885C3 /* CryptoKeyPair.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E1F80B8E183172B5007885C3 /* JSCryptoKeyPair.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F80B8C183172B5007885C3 /* JSCryptoKeyPair.h */; };
@@ -9306,6 +9307,7 @@
 		712BE4851FE86818002031CC /* JSFillMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFillMode.h; sourceTree = "<group>"; };
 		712BE4861FE86859002031CC /* JSPlaybackDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPlaybackDirection.h; sourceTree = "<group>"; };
 		712BE4871FE8685A002031CC /* JSPlaybackDirection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPlaybackDirection.cpp; sourceTree = "<group>"; };
+		712DBA4721F8AD79008F36B2 /* ScrollingCoordinatorTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingCoordinatorTypes.h; sourceTree = "<group>"; };
 		7130141D1DC9C08600CA3A88 /* pip-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "pip-support.js"; sourceTree = "<group>"; };
 		713171321FBE78C500F758DE /* CSSPropertyBlendingClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSPropertyBlendingClient.h; sourceTree = "<group>"; };
 		7132444F20109D9B00AE7FB2 /* WebAnimationUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAnimationUtilities.h; sourceTree = "<group>"; };
@@ -16906,6 +16908,7 @@
 				0F605AEB15F94848004DF0C0 /* ScrollingConstraints.h */,
 				1AF62EE414DA22A70041556C /* ScrollingCoordinator.cpp */,
 				1AF62EE514DA22A70041556C /* ScrollingCoordinator.h */,
+				712DBA4721F8AD79008F36B2 /* ScrollingCoordinatorTypes.h */,
 				51C61B081DE536E7008A212D /* ScrollingMomentumCalculator.cpp */,
 				51C61B091DE536E7008A212D /* ScrollingMomentumCalculator.h */,
 				93C38BFC164473C700091EB2 /* ScrollingStateFixedNode.cpp */,
@@ -29573,7 +29576,6 @@
 				F55B3DC21251F12D003EF269 /* ImageInputType.h in Headers */,
 				089582560E857A7E00F82C83 /* ImageLoader.h in Headers */,
 				BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */,
-				A59C230A21F29206004EC939 /* InspectorCPUProfilerAgent.h in Headers */,
 				2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */,
 				B51A2F3F17D7D3AE0072517A /* ImageQualityController.h in Headers */,
 				49291E4B134172C800E753DE /* ImageRenderingMode.h in Headers */,
@@ -29636,6 +29638,7 @@
 				A5B81CA81FAA44620037D1E6 /* InspectorCanvasAgent.h in Headers */,
 				1C81B95C0E97330800266E07 /* InspectorClient.h in Headers */,
 				1C81B95A0E97330800266E07 /* InspectorController.h in Headers */,
+				A59C230A21F29206004EC939 /* InspectorCPUProfilerAgent.h in Headers */,
 				A5B81CA91FAA44620037D1E6 /* InspectorCSSAgent.h in Headers */,
 				4A9CC82116BF9BB400EC645A /* InspectorCSSOMWrappers.h in Headers */,
 				A5B81CAA1FAA44620037D1E6 /* InspectorDatabaseAgent.h in Headers */,
@@ -31412,6 +31415,7 @@
 				1AF62EE814DA22A70041556C /* ScrollingCoordinator.h in Headers */,
 				0FC4E40D187F82E10045882C /* ScrollingCoordinatorIOS.h in Headers */,
 				9391A991162746CB00297330 /* ScrollingCoordinatorMac.h in Headers */,
+				712DBA4921F8AD83008F36B2 /* ScrollingCoordinatorTypes.h in Headers */,
 				51C61B0B1DE536E7008A212D /* ScrollingMomentumCalculator.h in Headers */,
 				517DEEE81DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h in Headers */,
 				93C38BFF164473C700091EB2 /* ScrollingStateFixedNode.h in Headers */,

Modified: trunk/Source/WebCore/dom/Document.cpp (240578 => 240579)


--- trunk/Source/WebCore/dom/Document.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/dom/Document.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -208,6 +208,7 @@
 #include "TextAutoSizing.h"
 #include "TextEvent.h"
 #include "TextNodeTraversal.h"
+#include "TouchAction.h"
 #include "TransformSource.h"
 #include "TreeWalker.h"
 #include "UndoManager.h"
@@ -4151,6 +4152,15 @@
 #if PLATFORM(IOS_FAMILY) && ENABLE(TOUCH_EVENTS)
     setTouchEventRegionsNeedUpdate();
 #endif
+
+#if ENABLE(POINTER_EVENTS)
+    if (auto* page = this->page()) {
+        if (auto* frameView = view()) {
+            if (auto* scrollingCoordinator = page->scrollingCoordinator())
+                scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
+        }
+    }
+#endif
 }
 
 void Document::invalidateScrollbarDependentRegions()
@@ -4534,6 +4544,11 @@
 
     if (is<Text>(node))
         m_markers->removeMarkers(node);
+
+#if ENABLE(POINTER_EVENTS)
+    if (m_touchActionElements && is<Element>(node))
+        m_touchActionElements->remove(&downcast<Element>(node));
+#endif
 }
 
 static Node* fallbackFocusNavigationStartingNodeAfterRemoval(Node& node)
@@ -7096,6 +7111,34 @@
     return LayoutRect();
 }
 
+Document::RegionFixedPair Document::absoluteEventRegionForNode(Node& node)
+{
+    Region region;
+    LayoutRect rootRelativeBounds;
+    bool insideFixedPosition = false;
+
+    if (is<Document>(node)) {
+        auto& document = downcast<Document>(node);
+        if (&document == this)
+            rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
+        else if (Element* element = document.ownerElement())
+            rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
+    } else if (is<Element>(node)) {
+        auto& element = downcast<Element>(node);
+        if (is<HTMLBodyElement>(element)) {
+            // For the body, just use the document bounds.
+            // The body may not cover this whole area, but it's OK for this region to be an overestimate.
+            rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
+        } else
+            rootRelativeBounds = element.absoluteEventHandlerBounds(insideFixedPosition);
+    }
+
+    if (!rootRelativeBounds.isEmpty())
+        region.unite(Region(enclosingIntRect(rootRelativeBounds)));
+
+    return RegionFixedPair(region, insideFixedPosition);
+}
+
 Document::RegionFixedPair Document::absoluteRegionForEventTargets(const EventTargetSet* targets)
 {
     LayoutDisallowedScope layoutDisallowedScope(LayoutDisallowedScope::Reason::ReentrancyAvoidance);
@@ -7107,26 +7150,11 @@
     bool insideFixedPosition = false;
 
     for (auto& keyValuePair : *targets) {
-        LayoutRect rootRelativeBounds;
-
-        if (is<Document>(keyValuePair.key)) {
-            Document* document = downcast<Document>(keyValuePair.key);
-            if (document == this)
-                rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
-            else if (Element* element = document->ownerElement())
-                rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
-        } else if (is<Element>(keyValuePair.key)) {
-            Element* element = downcast<Element>(keyValuePair.key);
-            if (is<HTMLBodyElement>(element)) {
-                // For the body, just use the document bounds.
-                // The body may not cover this whole area, but it's OK for this region to be an overestimate.
-                rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
-            } else
-                rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
+        if (auto* node = keyValuePair.key) {
+            auto targetRegionFixedPair = absoluteEventRegionForNode(*node);
+            targetRegion.unite(targetRegionFixedPair.first);
+            insideFixedPosition |= targetRegionFixedPair.second;
         }
-        
-        if (!rootRelativeBounds.isEmpty())
-            targetRegion.unite(Region(enclosingIntRect(rootRelativeBounds)));
     }
 
     return RegionFixedPair(targetRegion, insideFixedPosition);
@@ -8658,4 +8686,32 @@
 }
 #endif
 
+#if ENABLE(POINTER_EVENTS)
+void Document::updateTouchActionElements(Element& element, const RenderStyle& style)
+{
+    bool changed = false;
+
+    if (style.touchActions() != TouchAction::Auto) {
+        if (!m_touchActionElements)
+            m_touchActionElements = std::make_unique<HashSet<Element*>>();
+        changed |= m_touchActionElements->add(&element).isNewEntry;
+    } else if (m_touchActionElements)
+        changed |= m_touchActionElements->remove(&element);
+
+#if PLATFORM(IOS_FAMILY)
+    if (!changed)
+        return;
+
+    Page* page = this->page();
+    if (!page)
+        return;
+
+    if (FrameView* frameView = view()) {
+        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
+            scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
+    }
+#endif
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Document.h (240578 => 240579)


--- trunk/Source/WebCore/dom/Document.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/dom/Document.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -1276,6 +1276,10 @@
     bool hasTouchEventHandlers() const { return false; }
     bool touchEventTargetsContain(Node&) const { return false; }
 #endif
+#if ENABLE(POINTER_EVENTS)
+    void updateTouchActionElements(Element&, const RenderStyle&);
+    const HashSet<Element*>* touchActionElements() const { return m_touchActionElements.get(); }
+#endif
 
     void didAddTouchEventHandler(Node&);
     void didRemoveTouchEventHandler(Node&, EventHandlerRemoval = EventHandlerRemoval::One);
@@ -1294,6 +1298,7 @@
     const EventTargetSet* wheelEventTargets() const { return m_wheelEventTargets.get(); }
 
     typedef std::pair<Region, bool> RegionFixedPair;
+    RegionFixedPair absoluteEventRegionForNode(Node&);
     RegionFixedPair absoluteRegionForEventTargets(const EventTargetSet*);
 
     LayoutRect absoluteEventHandlerBounds(bool&) final;
@@ -1875,6 +1880,9 @@
 #if ENABLE(TOUCH_EVENTS)
     std::unique_ptr<EventTargetSet> m_touchEventTargets;
 #endif
+#if ENABLE(POINTER_EVENTS)
+    std::unique_ptr<HashSet<Element*>> m_touchActionElements;
+#endif
     std::unique_ptr<EventTargetSet> m_wheelEventTargets;
 
     MonotonicTime m_lastHandledUserGestureTimestamp;

Modified: trunk/Source/WebCore/dom/Element.cpp (240578 => 240579)


--- trunk/Source/WebCore/dom/Element.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/dom/Element.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -81,6 +81,8 @@
 #include "PointerLockController.h"
 #include "RenderFragmentContainer.h"
 #include "RenderLayer.h"
+#include "RenderLayerBacking.h"
+#include "RenderLayerCompositor.h"
 #include "RenderListBox.h"
 #include "RenderTheme.h"
 #include "RenderTreeUpdater.h"
@@ -3418,7 +3420,7 @@
     invalidateStyleAndLayerComposition();
 }
 
-static Element* parentCrossingFrameBoundaries(Element* element)
+static Element* parentCrossingFrameBoundaries(const Element* element)
 {
     ASSERT(element);
     return element->parentElement() ? element->parentElement() : element->document().ownerElement();
@@ -4122,4 +4124,66 @@
 }
 #endif
 
+#if ENABLE(POINTER_EVENTS)
+OptionSet<TouchAction> Element::computedTouchActions() const
+{
+    OptionSet<TouchAction> computedTouchActions = TouchAction::Auto;
+    for (auto* element = this; element; element = parentCrossingFrameBoundaries(element)) {
+        auto* renderer = element->renderer();
+        if (!renderer)
+            continue;
+
+        auto touchActions = renderer->style().touchActions();
+
+        // Once we've encountered touch-action: none, we know that this will be the computed value.
+        if (touchActions == TouchAction::None)
+            return touchActions;
+
+        // If the computed touch-action so far was "auto", we can just use the current element's touch-action.
+        if (computedTouchActions == TouchAction::Auto) {
+            computedTouchActions = touchActions;
+            continue;
+        }
+
+        // If the current element has touch-action: auto or the same touch-action as the computed touch-action,
+        // we need to keep going up the ancestry chain.
+        if (touchActions == TouchAction::Auto || touchActions == computedTouchActions)
+            continue;
+
+        // Now, the element's touch-action and the computed touch-action are different and are neither "auto" nor "none".
+        if (computedTouchActions == TouchAction::Manipulation) {
+            // If the computed touch-action is "manipulation", we can take the current element's touch-action as the newly
+            // computed touch-action.
+            computedTouchActions = touchActions;
+        } else if (touchActions == TouchAction::Manipulation) {
+            // Otherwise, we have a restricted computed touch-action so far. If the current element's touch-action is "manipulation"
+            // then we can just keep going and leave the computed touch-action untouched.
+            continue;
+        }
+
+        // In any other case, we have competing restrictive touch-action values that can only yield "none".
+        return TouchAction::None;
+    }
+    return computedTouchActions;
+}
+
+#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
+ScrollingNodeID Element::nearestScrollingNodeIDUsingTouchOverflowScrolling() const
+{
+    if (!renderer())
+        return 0;
+
+    // We are not interested in the root, so check that we also have a valid parent.
+    for (auto* layer = renderer()->enclosingLayer(); layer && layer->parent(); layer = layer->parent()) {
+        if (layer->isComposited()) {
+            if (auto scrollingNodeID = layer->backing()->scrollingNodeIDForRole(ScrollCoordinationRole::Scrolling))
+                return scrollingNodeID;
+        }
+    }
+
+    return 0;
+}
+#endif
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/dom/Element.h (240578 => 240579)


--- trunk/Source/WebCore/dom/Element.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/dom/Element.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -31,6 +31,7 @@
 #include "KeyframeAnimationOptions.h"
 #include "ScrollToOptions.h"
 #include "ScrollTypes.h"
+#include "ScrollingCoordinator.h"
 #include "ShadowRootMode.h"
 #include "SimulatedClickOptions.h"
 #include "StyleChange.h"
@@ -75,6 +76,10 @@
     DoNotReveal
 };
 
+#if ENABLE(POINTER_EVENTS)
+enum class TouchAction : uint8_t;
+#endif
+
 class Element : public ContainerNode {
     WTF_MAKE_ISO_ALLOCATED(Element);
 public:
@@ -588,6 +593,13 @@
     ExceptionOr<Ref<WebAnimation>> animate(JSC::ExecState&, JSC::Strong<JSC::JSObject>&&, Optional<Variant<double, KeyframeAnimationOptions>>&&);
     Vector<RefPtr<WebAnimation>> getAnimations();
 
+#if ENABLE(POINTER_EVENTS)
+    OptionSet<TouchAction> computedTouchActions() const;
+#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
+    ScrollingNodeID nearestScrollingNodeIDUsingTouchOverflowScrolling() const;
+#endif
+#endif
+
 protected:
     Element(const QualifiedName&, Document&, ConstructionType);
 

Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp (240578 => 240579)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -38,6 +38,7 @@
 #include "Region.h"
 #include "RenderLayerCompositor.h"
 #include "RenderView.h"
+#include "RuntimeEnabledFeatures.h"
 #include "ScrollAnimator.h"
 #include "Settings.h"
 #include <wtf/MainThread.h>
@@ -107,7 +108,25 @@
     auto* document = frame.document();
     if (!document)
         return EventTrackingRegions();
-    return document->eventTrackingRegions();
+    auto eventTrackingRegions = document->eventTrackingRegions();
+
+#if ENABLE(POINTER_EVENTS)
+    if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled()) {
+        if (auto* touchActionElements = frame.document()->touchActionElements()) {
+            auto& touchActionData = eventTrackingRegions.touchActionData;
+            for (const auto& element : *touchActionElements) {
+                ASSERT(element);
+                touchActionData.append({
+                    element->computedTouchActions(),
+                    element->nearestScrollingNodeIDUsingTouchOverflowScrolling(),
+                    element->document().absoluteEventRegionForNode(*element).first
+                });
+            }
+        }
+    }
+#endif
+
+    return eventTrackingRegions;
 #else
     auto* frameView = frame.view();
     if (!frameView)

Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h (240578 => 240579)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -30,6 +30,7 @@
 #include "PlatformWheelEvent.h"
 #include "ScrollSnapOffsetsInfo.h"
 #include "ScrollTypes.h"
+#include "ScrollingCoordinatorTypes.h"
 #include <wtf/Forward.h>
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/TypeCasts.h>
@@ -51,27 +52,6 @@
 
 namespace WebCore {
 
-typedef unsigned SynchronousScrollingReasons;
-typedef uint64_t ScrollingNodeID;
-
-enum class ScrollingNodeType : uint8_t {
-    MainFrame,
-    Subframe,
-    FrameHosting,
-    Overflow,
-    Fixed,
-    Sticky
-};
-
-enum ScrollingStateTreeAsTextBehaviorFlags {
-    ScrollingStateTreeAsTextBehaviorNormal                  = 0,
-    ScrollingStateTreeAsTextBehaviorIncludeLayerIDs         = 1 << 0,
-    ScrollingStateTreeAsTextBehaviorIncludeNodeIDs          = 1 << 1,
-    ScrollingStateTreeAsTextBehaviorIncludeLayerPositions   = 1 << 2,
-    ScrollingStateTreeAsTextBehaviorDebug                   = ScrollingStateTreeAsTextBehaviorIncludeLayerIDs | ScrollingStateTreeAsTextBehaviorIncludeNodeIDs | ScrollingStateTreeAsTextBehaviorIncludeLayerPositions
-};
-typedef unsigned ScrollingStateTreeAsTextBehavior;
-
 class Document;
 class Frame;
 class FrameView;
@@ -86,42 +66,6 @@
 class ScrollingTree;
 #endif
 
-enum class ScrollingLayerPositionAction {
-    Set,
-    SetApproximate,
-    Sync
-};
-
-struct ScrollableAreaParameters {
-    ScrollElasticity horizontalScrollElasticity { ScrollElasticityNone };
-    ScrollElasticity verticalScrollElasticity { ScrollElasticityNone };
-
-    ScrollbarMode horizontalScrollbarMode { ScrollbarAuto };
-    ScrollbarMode verticalScrollbarMode { ScrollbarAuto };
-
-    bool hasEnabledHorizontalScrollbar { false };
-    bool hasEnabledVerticalScrollbar { false };
-
-    bool useDarkAppearanceForScrollbars { false };
-
-    bool operator==(const ScrollableAreaParameters& other) const
-    {
-        return horizontalScrollElasticity == other.horizontalScrollElasticity
-            && verticalScrollElasticity == other.verticalScrollElasticity
-            && horizontalScrollbarMode == other.horizontalScrollbarMode
-            && verticalScrollbarMode == other.verticalScrollbarMode
-            && hasEnabledHorizontalScrollbar == other.hasEnabledHorizontalScrollbar
-            && hasEnabledVerticalScrollbar == other.hasEnabledVerticalScrollbar
-            && useDarkAppearanceForScrollbars == other.useDarkAppearanceForScrollbars;
-    }
-};
-
-enum class ViewportRectStability {
-    Stable,
-    Unstable,
-    ChangingObscuredInsetsInteractively // This implies Unstable.
-};
-
 class ScrollingCoordinator : public ThreadSafeRefCounted<ScrollingCoordinator> {
 public:
     static Ref<ScrollingCoordinator> create(Page*);

Added: trunk/Source/WebCore/page/scrolling/ScrollingCoordinatorTypes.h (0 => 240579)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinatorTypes.h	                        (rev 0)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinatorTypes.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "ScrollTypes.h"
+
+namespace WebCore {
+
+typedef unsigned SynchronousScrollingReasons;
+typedef uint64_t ScrollingNodeID;
+
+enum class ScrollingNodeType : uint8_t {
+    MainFrame,
+    Subframe,
+    FrameHosting,
+    Overflow,
+    Fixed,
+    Sticky
+};
+
+enum ScrollingStateTreeAsTextBehaviorFlags {
+    ScrollingStateTreeAsTextBehaviorNormal                  = 0,
+    ScrollingStateTreeAsTextBehaviorIncludeLayerIDs         = 1 << 0,
+    ScrollingStateTreeAsTextBehaviorIncludeNodeIDs          = 1 << 1,
+    ScrollingStateTreeAsTextBehaviorIncludeLayerPositions   = 1 << 2,
+    ScrollingStateTreeAsTextBehaviorDebug                   = ScrollingStateTreeAsTextBehaviorIncludeLayerIDs | ScrollingStateTreeAsTextBehaviorIncludeNodeIDs | ScrollingStateTreeAsTextBehaviorIncludeLayerPositions
+};
+typedef unsigned ScrollingStateTreeAsTextBehavior;
+
+enum class ScrollingLayerPositionAction {
+    Set,
+    SetApproximate,
+    Sync
+};
+
+struct ScrollableAreaParameters {
+    ScrollElasticity horizontalScrollElasticity { ScrollElasticityNone };
+    ScrollElasticity verticalScrollElasticity { ScrollElasticityNone };
+
+    ScrollbarMode horizontalScrollbarMode { ScrollbarAuto };
+    ScrollbarMode verticalScrollbarMode { ScrollbarAuto };
+
+    bool hasEnabledHorizontalScrollbar { false };
+    bool hasEnabledVerticalScrollbar { false };
+
+    bool useDarkAppearanceForScrollbars { false };
+
+    bool operator==(const ScrollableAreaParameters& other) const
+    {
+        return horizontalScrollElasticity == other.horizontalScrollElasticity
+            && verticalScrollElasticity == other.verticalScrollElasticity
+            && horizontalScrollbarMode == other.horizontalScrollbarMode
+            && verticalScrollbarMode == other.verticalScrollbarMode
+            && hasEnabledHorizontalScrollbar == other.hasEnabledHorizontalScrollbar
+            && hasEnabledVerticalScrollbar == other.hasEnabledVerticalScrollbar
+            && useDarkAppearanceForScrollbars == other.useDarkAppearanceForScrollbars;
+    }
+};
+
+enum class ViewportRectStability {
+    Stable,
+    Unstable,
+    ChangingObscuredInsetsInteractively // This implies Unstable.
+};
+
+}

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp (240578 => 240579)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -403,6 +403,19 @@
     return ts.release();
 }
 
+#if ENABLE(POINTER_EVENTS)
+Optional<TouchActionData> ScrollingTree::touchActionDataAtPoint(IntPoint p) const
+{
+    // FIXME: This does not handle the case where there are multiple regions matching this point.
+    for (auto& touchActionData : m_eventTrackingRegions.touchActionData) {
+        if (touchActionData.region.contains(p))
+            return touchActionData;
+    }
+
+    return WTF::nullopt;
+}
+#endif
+
 } // namespace WebCore
 
 #endif // ENABLE(ASYNC_SCROLLING)

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTree.h (240578 => 240579)


--- trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTree.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -30,6 +30,7 @@
 #include "PlatformWheelEvent.h"
 #include "Region.h"
 #include "ScrollingCoordinator.h"
+#include "TouchAction.h"
 #include "WheelEventTestTrigger.h"
 #include <wtf/HashMap.h>
 #include <wtf/Lock.h>
@@ -104,7 +105,10 @@
 #endif
 
     WEBCORE_EXPORT TrackingType eventTrackingTypeForPoint(const AtomicString& eventName, IntPoint);
-    
+#if ENABLE(POINTER_EVENTS)
+    WEBCORE_EXPORT Optional<TouchActionData> touchActionDataAtPoint(IntPoint) const;
+#endif
+
 #if PLATFORM(MAC)
     virtual void handleWheelEventPhase(PlatformWheelEventPhase) = 0;
     virtual void setActiveScrollSnapIndices(ScrollingNodeID, unsigned /*horizontalIndex*/, unsigned /*verticalIndex*/) { }

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h (240578 => 240579)


--- trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -31,6 +31,7 @@
 #include "ScrollTypes.h"
 #include "ScrollingCoordinator.h"
 #include "ScrollingStateNode.h"
+#include "TouchAction.h"
 #include <wtf/RefCounted.h>
 #include <wtf/TypeCasts.h>
 

Modified: trunk/Source/WebCore/platform/EventTrackingRegions.cpp (240578 => 240579)


--- trunk/Source/WebCore/platform/EventTrackingRegions.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/platform/EventTrackingRegions.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -73,7 +73,19 @@
 bool operator==(const EventTrackingRegions& a, const EventTrackingRegions& b)
 {
     return a.asynchronousDispatchRegion == b.asynchronousDispatchRegion
+#if ENABLE(POINTER_EVENTS)
+        && a.touchActionData == b.touchActionData
+#endif
         && a.eventSpecificSynchronousDispatchRegions == b.eventSpecificSynchronousDispatchRegions;
 }
 
+#if ENABLE(POINTER_EVENTS)
+bool operator==(const TouchActionData& a, const TouchActionData& b)
+{
+    return a.touchActions == b.touchActions
+        && a.scrollingNodeID == b.scrollingNodeID
+        && a.region == b.region;
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WebCore/platform/EventTrackingRegions.h (240578 => 240579)


--- trunk/Source/WebCore/platform/EventTrackingRegions.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/platform/EventTrackingRegions.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -30,6 +30,12 @@
 #include <wtf/text/StringHash.h>
 #include <wtf/text/WTFString.h>
 
+#if ENABLE(POINTER_EVENTS)
+#include "CSSPrimitiveValueMappings.h"
+#include "ScrollingCoordinatorTypes.h"
+#include "TouchAction.h"
+#endif
+
 namespace WebCore {
 
 enum class TrackingType : uint8_t {
@@ -38,6 +44,18 @@
     Synchronous = 2
 };
 
+#if ENABLE(POINTER_EVENTS)
+typedef uint64_t ScrollingNodeID;
+struct TouchActionData {
+    OptionSet<TouchAction> touchActions { TouchAction::Auto };
+    ScrollingNodeID scrollingNodeID { 0 };
+    Region region;
+};
+
+bool operator==(const TouchActionData&, const TouchActionData&);
+inline bool operator!=(const TouchActionData& a, const TouchActionData& b) { return !(a == b); }
+#endif
+
 struct EventTrackingRegions {
     // Region for which events can be dispatched without blocking scrolling.
     Region asynchronousDispatchRegion;
@@ -46,6 +64,10 @@
     // The key is the Event Name with an active handler.
     HashMap<String, Region> eventSpecificSynchronousDispatchRegions;
 
+#if ENABLE(POINTER_EVENTS)
+    Vector<TouchActionData> touchActionData;
+#endif
+
     bool isEmpty() const;
 
     void translate(IntSize);

Modified: trunk/Source/WebCore/style/StyleTreeResolver.cpp (240578 => 240579)


--- trunk/Source/WebCore/style/StyleTreeResolver.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebCore/style/StyleTreeResolver.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -236,6 +236,11 @@
     auto beforeUpdate = resolvePseudoStyle(element, update, PseudoId::Before);
     auto afterUpdate = resolvePseudoStyle(element, update, PseudoId::After);
 
+#if ENABLE(POINTER_EVENTS)
+    if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled())
+        m_document.updateTouchActionElements(element, *update.style.get());
+#endif
+
     return { WTFMove(update), descendantsToResolve, WTFMove(beforeUpdate), WTFMove(afterUpdate) };
 }
 

Modified: trunk/Source/WebKit/ChangeLog (240578 => 240579)


--- trunk/Source/WebKit/ChangeLog	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/ChangeLog	2019-01-28 15:08:54 UTC (rev 240579)
@@ -1,3 +1,52 @@
+2019-01-28  Antoine Quint  <[email protected]>
+
+        Limit user-agent interactions based on the touch-action property on iOS
+        https://bugs.webkit.org/show_bug.cgi?id=193447
+        <rdar://problem/47283874>
+
+        Reviewed by Antti Koivisto and Simon Fraser.
+
+        Handle the "none", "pan-x", "pan-y" and "pinch-zoom" values for the touch-action property by querying the scrolling tree whenever a touch begins
+        to identify whether its point is contained within the region of an element with a non-auto touch-action property. If it is, we use the list of
+        permitted touch actions such to then customize the behavior of the nearest scroll view to pan or zoom only as instructed.
+
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<TouchActionData>::encode):
+        (IPC::ArgumentCoder<TouchActionData>::decode):
+        (IPC::ArgumentCoder<EventTrackingRegions>::encode):
+        (IPC::ArgumentCoder<EventTrackingRegions>::decode):
+        (IPC::ArgumentCoder<Region>::decode):
+        * Shared/WebCoreArgumentCoders.h:
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Account for panning constraints set on the content view to prevent deceleration
+        to pan the view if it ought not.
+        (-[WKWebView _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Implement an additional
+        UIScrollView delegation method to apply the panning constraints set on the content view while panning.
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
+        (WebKit::RemoteScrollingCoordinatorProxy::touchActionDataAtPoint const):
+        (WebKit::RemoteScrollingCoordinatorProxy::touchActionDataForScrollNodeID const):
+        (WebKit::RemoteScrollingCoordinatorProxy::setTouchDataForTouchIdentifier):
+        (WebKit::RemoteScrollingCoordinatorProxy::clearTouchDataForTouchIdentifier):
+        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
+        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
+        (-[WKScrollingNodeScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Apply the same logic as in WKWebView.
+        (-[WKScrollingNodeScrollViewDelegate _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Apply
+        the same logic as in WKWebView.
+        (WebKit::ScrollingTreeScrollingNodeDelegateIOS::touchActionData const):
+        * UIProcess/WebPageProxy.h:
+        (WebKit::WebPageProxy::isScrollingOrZooming const):
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView preventsPanningInXAxis]):
+        (-[WKContentView preventsPanningInYAxis]):
+        (-[WKContentView cleanupInteraction]):
+        (-[WKContentView _webTouchEventsRecognized:]):
+        (-[WKContentView _handleTouchActionsForTouchEvent:]): As we process touches, check whether there are touch actions set for this touch's points' locations. Based
+        on those touch actions, either setDefaultPrevented on the _touchEventGestureRecognizer if the touch action is "none" or selectively disable panning and zooming.
+        (-[WKContentView _resetPanningPreventionFlags]):
+        (-[WKContentView _didEndScrollingOrZooming]):
+
 2019-01-28  Antti Koivisto  <[email protected]>
 
         WebUserContentController::removeUserScriptMessageHandlerInternal may deref and delete itself

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (240578 => 240579)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -329,10 +329,40 @@
     return {{ WTFMove(identifier), WTFMove(updateResponseCounter), WTFMove(requestHeadersGuard), WTFMove(request), WTFMove(options.value()), WTFMove(referrer), WTFMove(responseHeadersGuard), WTFMove(response), WTFMove(responseBody), responseBodySize }};
 }
 
+#if ENABLE(POINTER_EVENTS)
+void ArgumentCoder<TouchActionData>::encode(Encoder& encoder, const TouchActionData& touchActionData)
+{
+    encoder << touchActionData.touchActions << touchActionData.scrollingNodeID << touchActionData.region;
+}
+
+Optional<TouchActionData> ArgumentCoder<TouchActionData>::decode(Decoder& decoder)
+{
+    Optional<OptionSet<TouchAction>> touchActions;
+    decoder >> touchActions;
+    if (!touchActions)
+        return WTF::nullopt;
+
+    Optional<ScrollingNodeID> scrollingNodeID;
+    decoder >> scrollingNodeID;
+    if (!scrollingNodeID)
+        return WTF::nullopt;
+
+    Optional<Region> region;
+    decoder >> region;
+    if (!region)
+        return WTF::nullopt;
+
+    return {{ WTFMove(*touchActions), WTFMove(*scrollingNodeID), WTFMove(*region) }};
+}
+#endif
+
 void ArgumentCoder<EventTrackingRegions>::encode(Encoder& encoder, const EventTrackingRegions& eventTrackingRegions)
 {
     encoder << eventTrackingRegions.asynchronousDispatchRegion;
     encoder << eventTrackingRegions.eventSpecificSynchronousDispatchRegions;
+#if ENABLE(POINTER_EVENTS)
+    encoder << eventTrackingRegions.touchActionData;
+#endif
 }
 
 bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTrackingRegions& eventTrackingRegions)
@@ -343,8 +373,16 @@
     HashMap<String, Region> eventSpecificSynchronousDispatchRegions;
     if (!decoder.decode(eventSpecificSynchronousDispatchRegions))
         return false;
+#if ENABLE(POINTER_EVENTS)
+    Vector<TouchActionData> touchActionData;
+    if (!decoder.decode(touchActionData))
+        return false;
+#endif
     eventTrackingRegions.asynchronousDispatchRegion = WTFMove(asynchronousDispatchRegion);
     eventTrackingRegions.eventSpecificSynchronousDispatchRegions = WTFMove(eventSpecificSynchronousDispatchRegions);
+#if ENABLE(POINTER_EVENTS)
+    eventTrackingRegions.touchActionData = WTFMove(touchActionData);
+#endif
     return true;
 }
 
@@ -915,6 +953,15 @@
     return true;
 }
 
+Optional<Region> ArgumentCoder<Region>::decode(Decoder& decoder)
+{
+    Region region;
+    if (!decode(decoder, region))
+        return WTF::nullopt;
+
+    return region;
+}
+
 void ArgumentCoder<Length>::encode(Encoder& encoder, const Length& length)
 {
     SimpleArgumentCoder<Length>::encode(encoder, length);

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h (240578 => 240579)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -121,6 +121,9 @@
 struct ScrollableAreaParameters;
 struct TextCheckingResult;
 struct TextIndicatorData;
+#if ENABLE(POINTER_EVENTS)
+struct TouchActionData;
+#endif
 struct ViewportAttributes;
 struct WindowFeatures;
     
@@ -199,6 +202,13 @@
     static Optional<WebCore::DOMCacheEngine::Record> decode(Decoder&);
 };
 
+#if ENABLE(POINTER_EVENTS)
+template<> struct ArgumentCoder<WebCore::TouchActionData> {
+    static void encode(Encoder&, const WebCore::TouchActionData&);
+    static Optional<WebCore::TouchActionData> decode(Decoder&);
+};
+#endif
+
 template<> struct ArgumentCoder<WebCore::EventTrackingRegions> {
     static void encode(Encoder&, const WebCore::EventTrackingRegions&);
     static bool decode(Decoder&, WebCore::EventTrackingRegions&);
@@ -316,6 +326,7 @@
 template<> struct ArgumentCoder<WebCore::Region> {
     static void encode(Encoder&, const WebCore::Region&);
     static bool decode(Decoder&, WebCore::Region&);
+    static Optional<WebCore::Region> decode(Decoder&);
 };
 
 template<> struct ArgumentCoder<WebCore::Length> {

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm	2019-01-28 15:08:54 UTC (rev 240579)
@@ -2583,6 +2583,14 @@
     // zooming. We'll animate to the right place once the zoom finishes.
     if ([scrollView isZooming])
         *targetContentOffset = [scrollView contentOffset];
+#if ENABLE(POINTER_EVENTS)
+    else {
+        if ([_contentView preventsPanningInXAxis])
+            targetContentOffset->x = scrollView.contentOffset.x;
+        if ([_contentView preventsPanningInYAxis])
+            targetContentOffset->y = scrollView.contentOffset.y;
+    }
+#endif
 #if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
     if (WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy()) {
         // FIXME: Here, I'm finding the maximum horizontal/vertical scroll offsets. There's probably a better way to do this.
@@ -2620,6 +2628,20 @@
     [self _didFinishScrolling];
 }
 
+- (CGPoint)_scrollView:(UIScrollView *)scrollView adjustedOffsetForOffset:(CGPoint)offset translation:(CGPoint)translation startPoint:(CGPoint)start locationInView:(CGPoint)locationInView horizontalVelocity:(inout double *)hv verticalVelocity:(inout double *)vv
+{
+    if (![_contentView preventsPanningInXAxis] && ![_contentView preventsPanningInYAxis])
+        return offset;
+
+    CGPoint adjustedContentOffset = CGPointMake(offset.x, offset.y);
+    if ([_contentView preventsPanningInXAxis])
+        adjustedContentOffset.x = start.x;
+    if ([_contentView preventsPanningInYAxis])
+        adjustedContentOffset.y = start.y;
+
+    return adjustedContentOffset;
+}
+
 - (void)scrollViewDidScroll:(UIScrollView *)scrollView
 {
     if (![self usesStandardContentView] && [_customContentView respondsToSelector:@selector(web_scrollViewDidScroll:)])

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp	2019-01-28 15:08:54 UTC (rev 240579)
@@ -206,6 +206,33 @@
     return emptyString();
 }
 
+#if ENABLE(POINTER_EVENTS)
+Optional<TouchActionData> RemoteScrollingCoordinatorProxy::touchActionDataAtPoint(const IntPoint p) const
+{
+    return m_scrollingTree->touchActionDataAtPoint(p);
+}
+
+Optional<TouchActionData> RemoteScrollingCoordinatorProxy::touchActionDataForScrollNodeID(ScrollingNodeID scrollingNodeID) const
+{
+    for (auto& touchActionData : m_touchActionDataByTouchIdentifier.values()) {
+        if (touchActionData.scrollingNodeID == scrollingNodeID)
+            return touchActionData;
+    }
+    return WTF::nullopt;
+}
+
+void RemoteScrollingCoordinatorProxy::setTouchDataForTouchIdentifier(TouchActionData touchActionData, unsigned touchIdentifier)
+{
+    m_touchActionDataByTouchIdentifier.set(touchIdentifier, touchActionData);
+}
+
+void RemoteScrollingCoordinatorProxy::clearTouchDataForTouchIdentifier(unsigned touchIdentifier)
+{
+    m_touchActionDataByTouchIdentifier.remove(touchIdentifier);
+}
+
+#endif
+
 } // namespace WebKit
 
 #endif // ENABLE(ASYNC_SCROLLING)

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -98,6 +98,13 @@
 
     String scrollingTreeAsText() const;
 
+#if ENABLE(POINTER_EVENTS)
+    Optional<WebCore::TouchActionData> touchActionDataAtPoint(const WebCore::IntPoint) const;
+    Optional<WebCore::TouchActionData> touchActionDataForScrollNodeID(WebCore::ScrollingNodeID) const;
+    void setTouchDataForTouchIdentifier(WebCore::TouchActionData, unsigned);
+    void clearTouchDataForTouchIdentifier(unsigned);
+#endif
+
 private:
     void connectStateNodeLayers(WebCore::ScrollingStateTree&, const RemoteLayerTreeHost&);
 #if ENABLE(CSS_SCROLL_SNAP)
@@ -107,6 +114,9 @@
 
     WebPageProxy& m_webPageProxy;
     RefPtr<RemoteScrollingTree> m_scrollingTree;
+#if ENABLE(POINTER_EVENTS)
+    HashMap<unsigned, WebCore::TouchActionData> m_touchActionDataByTouchIdentifier;
+#endif
     RequestedScrollInfo* m_requestedScrollInfo;
 #if ENABLE(CSS_SCROLL_SNAP)
     unsigned m_currentHorizontalSnapPointIndex { 0 };

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -65,6 +65,9 @@
     WebCore::FloatPoint scrollPosition() const;
     void setScrollLayerPosition(const WebCore::FloatPoint&);
     void updateChildNodesAfterScroll(const WebCore::FloatPoint& scrollPosition);
+#if ENABLE(POINTER_EVENTS)
+    Optional<TouchActionData> touchActionData() const;
+#endif
 
 private:
     RetainPtr<CALayer> m_scrollLayer;

Modified: trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm	2019-01-28 15:08:54 UTC (rev 240579)
@@ -67,9 +67,29 @@
     _scrollingTreeNodeDelegate->scrollWillStart();
 }
 
-#if ENABLE(CSS_SCROLL_SNAP)
 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
 {
+#if ENABLE(POINTER_EVENTS)
+    if (![scrollView isZooming]) {
+        if (auto touchActionData = _scrollingTreeNodeDelegate->touchActionData()) {
+            auto touchActions = touchActionData->touchActions;
+            if (touchActions != WebCore::TouchAction::Auto && touchActions != WebCore::TouchAction::Manipulation) {
+                bool canPanX = true;
+                bool canPanY = true;
+                if (!touchActions.contains(WebCore::TouchAction::PanX)) {
+                    canPanX = false;
+                    targetContentOffset->x = scrollView.contentOffset.x;
+                }
+                if (!touchActions.contains(WebCore::TouchAction::PanY)) {
+                    canPanY = false;
+                    targetContentOffset->y = scrollView.contentOffset.y;
+                }
+            }
+        }
+    }
+#endif
+
+#if ENABLE(CSS_SCROLL_SNAP)
     CGFloat horizontalTarget = targetContentOffset->x;
     CGFloat verticalTarget = targetContentOffset->y;
 
@@ -96,8 +116,8 @@
         || originalVerticalSnapPosition != _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex()) {
         _scrollingTreeNodeDelegate->currentSnapPointIndicesDidChange(_scrollingTreeNodeDelegate->scrollingNode().currentHorizontalSnapPointIndex(), _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex());
     }
+#endif
 }
-#endif
 
 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)willDecelerate
 {
@@ -117,6 +137,28 @@
     }
 }
 
+#if ENABLE(POINTER_EVENTS)
+- (CGPoint)_scrollView:(UIScrollView *)scrollView adjustedOffsetForOffset:(CGPoint)offset translation:(CGPoint)translation startPoint:(CGPoint)start locationInView:(CGPoint)locationInView horizontalVelocity:(inout double *)hv verticalVelocity:(inout double *)vv
+{
+    auto touchActionData = _scrollingTreeNodeDelegate->touchActionData();
+    if (!touchActionData)
+        return offset;
+
+    auto touchActions = touchActionData->touchActions;
+    if (touchActions == WebCore::TouchAction::Auto || touchActions == WebCore::TouchAction::Manipulation)
+        return offset;
+
+    CGPoint adjustedContentOffset = CGPointMake(offset.x, offset.y);
+
+    if (!touchActions.contains(WebCore::TouchAction::PanX))
+        adjustedContentOffset.x = start.x;
+    if (!touchActions.contains(WebCore::TouchAction::PanY))
+        adjustedContentOffset.y = start.y;
+
+    return adjustedContentOffset;
+}
+#endif
+
 @end
 
 namespace WebKit {
@@ -287,6 +329,13 @@
     scrollingTree().currentSnapPointIndicesDidChange(scrollingNode().scrollingNodeID(), horizontal, vertical);
 }
 
+#if ENABLE(POINTER_EVENTS)
+Optional<TouchActionData> ScrollingTreeScrollingNodeDelegateIOS::touchActionData() const
+{
+    return downcast<RemoteScrollingTree>(scrollingTree()).scrollingCoordinatorProxy().touchActionDataForScrollNodeID(scrollingNode().scrollingNodeID());
+}
+#endif
+
 } // namespace WebKit
 
 #endif // PLATFORM(IOS_FAMILY) && ENABLE(ASYNC_SCROLLING)

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -678,6 +678,7 @@
     void startAutoscrollAtPosition(const WebCore::FloatPoint& positionInWindow);
     void cancelAutoscroll();
     void hardwareKeyboardAvailabilityChanged();
+    bool isScrollingOrZooming() const { return m_isScrollingOrZooming; }
 #if ENABLE(DATA_INTERACTION)
     void didHandleDragStartRequest(bool started);
     void didHandleAdditionalDragItemsRequest(bool added);

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-01-28 15:08:54 UTC (rev 240579)
@@ -196,6 +196,10 @@
     RetainPtr<UIWebTouchEventsGestureRecognizer> _touchEventGestureRecognizer;
 
     BOOL _canSendTouchEventsAsynchronously;
+#if ENABLE(POINTER_EVENTS)
+    BOOL _preventsPanningInXAxis;
+    BOOL _preventsPanningInYAxis;
+#endif
 
     RetainPtr<WKSyntheticClickTapGestureRecognizer> _singleTapGestureRecognizer;
     RetainPtr<_UIWebHighlightLongPressGestureRecognizer> _highlightLongPressGestureRecognizer;
@@ -349,6 +353,10 @@
 @property (nonatomic, readonly) const WebKit::FocusedElementInformation& focusedElementInformation;
 @property (nonatomic, readonly) UIWebFormAccessory *formAccessoryView;
 @property (nonatomic, readonly) UITextInputAssistantItem *inputAssistantItemForWebView;
+#if ENABLE(POINTER_EVENTS)
+@property (nonatomic, readonly) BOOL preventsPanningInXAxis;
+@property (nonatomic, readonly) BOOL preventsPanningInYAxis;
+#endif
 
 #if ENABLE(DATALIST_ELEMENT)
 @property (nonatomic, strong) UIView <WKFormControl> *dataListTextSuggestionsInputView;

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (240578 => 240579)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-01-28 13:15:03 UTC (rev 240578)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-01-28 15:08:54 UTC (rev 240579)
@@ -129,6 +129,11 @@
 #import <WebKitAdditions/WKPlatformFileUploadPanel.mm>
 #endif
 
+#if ENABLE(POINTER_EVENTS)
+#import "RemoteScrollingCoordinatorProxy.h"
+#import <WebCore/TouchAction.h>
+#endif
+
 #if PLATFORM(WATCHOS)
 
 @interface WKContentView (WatchSupport) <WKFocusedFormControlViewDelegate, WKSelectMenuListViewControllerDelegate, WKTextInputListViewControllerDelegate>
@@ -608,6 +613,18 @@
     return (focusedElementInformation.elementType != WebKit::InputType::None);
 }
 
+#if ENABLE(POINTER_EVENTS)
+- (BOOL)preventsPanningInXAxis
+{
+    return _preventsPanningInXAxis;
+}
+
+- (BOOL)preventsPanningInYAxis
+{
+    return _preventsPanningInYAxis;
+}
+#endif
+
 - (WKFormInputSession *)_formInputSession
 {
     return _formInputSession.get();
@@ -854,6 +871,10 @@
     _hasSetUpInteractions = NO;
     _suppressSelectionAssistantReasons = { };
     _isZoomingToRevealFocusedElement = NO;
+
+#if ENABLE(POINTER_EVENTS)
+    [self _resetPanningPreventionFlags];
+#endif
 }
 
 - (void)_removeDefaultGestureRecognizers
@@ -1121,16 +1142,63 @@
     WebKit::NativeWebTouchEvent nativeWebTouchEvent(lastTouchEvent);
     nativeWebTouchEvent.setCanPreventNativeGestures(!_canSendTouchEventsAsynchronously || [gestureRecognizer isDefaultPrevented]);
 
+#if ENABLE(POINTER_EVENTS)
+    [self _handleTouchActionsForTouchEvent:nativeWebTouchEvent];
+#endif
+
     if (_canSendTouchEventsAsynchronously)
         _page->handleTouchEventAsynchronously(nativeWebTouchEvent);
     else
         _page->handleTouchEventSynchronously(nativeWebTouchEvent);
 
-    if (nativeWebTouchEvent.allTouchPointsAreReleased())
+    if (nativeWebTouchEvent.allTouchPointsAreReleased()) {
         _canSendTouchEventsAsynchronously = NO;
+
+#if ENABLE(POINTER_EVENTS)
+        if (!_page->isScrollingOrZooming())
+            [self _resetPanningPreventionFlags];
 #endif
+    }
+#endif
 }
 
+#if ENABLE(POINTER_EVENTS)
+- (void)_handleTouchActionsForTouchEvent:(const WebKit::NativeWebTouchEvent&)touchEvent
+{
+    auto* scrollingCoordinator = _page->scrollingCoordinatorProxy();
+    if (!scrollingCoordinator)
+        return;
+
+    for (const auto& touchPoint : touchEvent.touchPoints()) {
+        auto phase = touchPoint.phase();
+        if (phase == WebKit::WebPlatformTouchPoint::TouchPressed) {
+            auto touchActionData = scrollingCoordinator->touchActionDataAtPoint(touchPoint.location());
+            if (!touchActionData)
+                continue;
+            if (touchActionData->touchActions == WebCore::TouchAction::None)
+                [_touchEventGestureRecognizer setDefaultPrevented:YES];
+            else if (!touchActionData->touchActions.contains(WebCore::TouchAction::Manipulation)) {
+                if (auto scrollingNodeID = touchActionData->scrollingNodeID)
+                    scrollingCoordinator->setTouchDataForTouchIdentifier(*touchActionData, touchPoint.identifier());
+                else {
+                    if (!touchActionData->touchActions.contains(WebCore::TouchAction::PinchZoom))
+                        _webView.scrollView.pinchGestureRecognizer.enabled = NO;
+                    _preventsPanningInXAxis = !touchActionData->touchActions.contains(WebCore::TouchAction::PanX);
+                    _preventsPanningInYAxis = !touchActionData->touchActions.contains(WebCore::TouchAction::PanY);
+                }
+            }
+        } else if (phase == WebKit::WebPlatformTouchPoint::TouchReleased || phase == WebKit::WebPlatformTouchPoint::TouchCancelled)
+            scrollingCoordinator->clearTouchDataForTouchIdentifier(touchPoint.identifier());
+    }
+}
+
+- (void)_resetPanningPreventionFlags
+{
+    _preventsPanningInXAxis = NO;
+    _preventsPanningInYAxis = NO;
+}
+#endif
+
 - (void)_inspectorNodeSearchRecognized:(UIGestureRecognizer *)gestureRecognizer
 {
     ASSERT(_inspectorNodeSearchEnabled);
@@ -2192,6 +2260,10 @@
     }
     _page->setIsScrollingOrZooming(false);
 
+#if ENABLE(POINTER_EVENTS)
+    [self _resetPanningPreventionFlags];
+#endif
+
 #if PLATFORM(WATCHOS)
     [_focusedFormControlView engageFocusedFormControlNavigation];
 #endif
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to