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