WebKit Bugzilla
Attachment 360338 Details for
Bug 193447
: Limit user-agent interactions based on the touch-action property on iOS
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193447-20190128153813.patch (text/plain), 86.51 KB, created by
Antoine Quint
on 2019-01-28 06:38:15 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Antoine Quint
Created:
2019-01-28 06:38:15 PST
Size:
86.51 KB
patch
obsolete
>Subversion Revision: 240559 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 57c90ac0041c15326a3440a20e6486cac0496a85..d13e271122ba8f0e161c1f1515dd8410732fdec8 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,68 @@ >+2019-01-28 Antoine Quint <graouts@apple.com> >+ >+ 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 NOBODY (OOPS!). >+ >+ 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 <mcatanzaro@igalia.com> > > Unreviewed, fix WPE/GTK debug builds after r240557 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index d93f9222892c3b5fa7a1195611a552d7e430bba7..942e282fc333aa9825a9d7025584f224668ef364 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,52 @@ >+2019-01-28 Antoine Quint <graouts@apple.com> >+ >+ 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 NOBODY (OOPS!). >+ >+ 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]): >+ > 2018-12-15 Darin Adler <darin@apple.com> > > Replace many uses of String::format with more type-safe alternatives >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 7ed125dbd5145add9235be3e618eae54dbe0aad7..60514ecc9e17286ed397c5bdf47c5461ab9e9add 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -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 */, >@@ -17273,8 +17276,8 @@ > 29A812040FBB9B4100510293 /* accessibility */ = { > isa = PBXGroup; > children = ( >- 29AE212921AB9ECB00869283 /* isolatedtree */, > AAA728EF16D1D8BC00D3BBC6 /* ios */, >+ 29AE212921AB9ECB00869283 /* isolatedtree */, > 29A812050FBB9B5200510293 /* mac */, > 2981CA9D131822EC00D12F2A /* AccessibilityARIAGrid.cpp */, > 29A812160FBB9C1D00510293 /* AccessibilityARIAGrid.h */, >@@ -17371,10 +17374,10 @@ > 29AE212921AB9ECB00869283 /* isolatedtree */ = { > isa = PBXGroup; > children = ( >- 29AE212B21AB9EEB00869283 /* AXIsolatedTree.h */, > 29AE212C21AB9EEB00869283 /* AXIsolatedTree.cpp */, >- 29AE213321ABA48A00869283 /* AXIsolatedTreeNode.h */, >+ 29AE212B21AB9EEB00869283 /* AXIsolatedTree.h */, > 29AE213421ABA48A00869283 /* AXIsolatedTreeNode.cpp */, >+ 29AE213321ABA48A00869283 /* AXIsolatedTreeNode.h */, > ); > path = isolatedtree; > sourceTree = "<group>"; >@@ -28262,6 +28265,7 @@ > 76CDD2F51103DA6600680521 /* AccessibilityMenuListPopup.h in Headers */, > 29ACB212143E7128006BCA5F /* AccessibilityMockObject.h in Headers */, > 29A812360FBB9C1D00510293 /* AccessibilityObject.h in Headers */, >+ 2936BF5C21D69E4B004A8FC9 /* AccessibilityObjectInterface.h in Headers */, > A409C985116D0DDD007197BD /* AccessibilityProgressIndicator.h in Headers */, > 29A812390FBB9C1D00510293 /* AccessibilityRenderObject.h in Headers */, > 93C4F6EB1108F9A50099D0DB /* AccessibilityScrollbar.h in Headers */, >@@ -28431,6 +28435,8 @@ > 07F4E93320B3587F002E3803 /* AVFoundationMIMETypeCache.h in Headers */, > CD336F6217F9F64700DDDCD0 /* AVTrackPrivateAVFObjCImpl.h in Headers */, > 070363E6181A1CDC00C074A5 /* AVVideoCaptureSource.h in Headers */, >+ 29AE212D21AB9EEB00869283 /* AXIsolatedTree.h in Headers */, >+ 29AE213521ABA48A00869283 /* AXIsolatedTreeNode.h in Headers */, > F45C231E1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h in Headers */, > 29A812380FBB9C1D00510293 /* AXObjectCache.h in Headers */, > 91C9F2F91AE3BEB00095B61C /* AXTextStateChangeIntent.h in Headers */, >@@ -29573,7 +29579,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 +29641,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 */, >@@ -30004,7 +30010,6 @@ > 1AE2AA980A1CDD2D00B42B25 /* JSHTMLImageElement.h in Headers */, > A80E7E970A1A83E3007FB8C5 /* JSHTMLInputElement.h in Headers */, > 836B09561F5F34D9003C3702 /* JSHTMLInputElementEntriesAPI.h in Headers */, >- 2936BF5C21D69E4B004A8FC9 /* AccessibilityObjectInterface.h in Headers */, > A6148A7912E41E3B0044A784 /* JSHTMLKeygenElement.h in Headers */, > 1AE2AB220A1CE63B00B42B25 /* JSHTMLLabelElement.h in Headers */, > 1AE2AB240A1CE63B00B42B25 /* JSHTMLLegendElement.h in Headers */, >@@ -31412,6 +31417,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 */, >@@ -31460,7 +31466,6 @@ > 51405C89190B014400754F94 /* SelectionRectGatherer.h in Headers */, > E44B4BB4141650D7002B1D8B /* SelectorChecker.h in Headers */, > 432D3FE818A8658400D7DC03 /* SelectorCheckerTestFunctions.h in Headers */, >- 29AE213521ABA48A00869283 /* AXIsolatedTreeNode.h in Headers */, > 26B999971804D54200D01121 /* SelectorCompiler.h in Headers */, > 415071581685067300C3C7B3 /* SelectorFilter.h in Headers */, > 43107BE218CC19DE00CC18E8 /* SelectorPseudoTypeMap.h in Headers */, >@@ -32396,7 +32401,6 @@ > 977E2E0F12F0FC9C00C13380 /* XSSAuditorDelegate.h in Headers */, > A5416FE618810EF80009FC5F /* YouTubeEmbedShadowElement.h in Headers */, > 7A5515F5191830A3009687D2 /* YouTubePluginReplacement.h in Headers */, >- 29AE212D21AB9EEB00869283 /* AXIsolatedTree.h in Headers */, > FD537353137B651800008DCE /* ZeroPole.h in Headers */, > ); > runOnlyForDeploymentPostprocessing = 0; >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index 6d443e7866f48a31157adab1b946f4df211980e9..612c35fd454b8e17308938f45037125dbb550656 100644 >--- a/Source/WebCore/dom/Document.cpp >+++ b/Source/WebCore/dom/Document.cpp >@@ -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 @@ void Document::invalidateRenderingDependentRegions(AnnotationsAction annotations > #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 @@ void Document::nodeWillBeRemoved(Node& node) > > 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 @@ LayoutRect Document::absoluteEventHandlerBounds(bool& includesFixedPositionEleme > 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 @@ Document::RegionFixedPair Document::absoluteRegionForEventTargets(const EventTar > 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 @@ void Document::setPaintWorkletGlobalScopeForName(const String& name, Ref<PaintWo > } > #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 >diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h >index 30f0ee67c991a3b3660d76a7f047cd8abedfb203..8e2878f4d15ab8515067a3aa5da3f25731102d03 100644 >--- a/Source/WebCore/dom/Document.h >+++ b/Source/WebCore/dom/Document.h >@@ -1276,6 +1276,10 @@ public: > 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 @@ public: > 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; >@@ -1874,6 +1879,9 @@ private: > > #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; > >diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp >index ea5493a5a2cd5feadd66c0f6d7b3450f70fc13a2..ca4bc99c33c8bc98f31ae94b7c3a7a1d648cda31 100644 >--- a/Source/WebCore/dom/Element.cpp >+++ b/Source/WebCore/dom/Element.cpp >@@ -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 @@ void Element::setContainsFullScreenElement(bool flag) > 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 @@ void Element::setAttributeStyleMap(Ref<StylePropertyMap>&& map) > } > #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 >diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h >index c5eb6cb8c448b099c5e0126ad5a1e7c4e8842b86..6ae16185e9ac471854a9349d741dd464a11f4e53 100644 >--- a/Source/WebCore/dom/Element.h >+++ b/Source/WebCore/dom/Element.h >@@ -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 @@ enum class SelectionRevealMode { > 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 @@ public: > 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); > >diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp >index c4faedd3e8f5485b300bf43d3aa6f1eab9301545..d056a8b77c894b0517e1f1a3e51e9ddd6beb55a5 100644 >--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp >+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp >@@ -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 @@ EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegionsForFrame( > 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) >diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.h b/Source/WebCore/page/scrolling/ScrollingCoordinator.h >index 6547daab9a903d0b4ee89a28e30664694b26fa35..53322f666160c12f45acaadc90408fe03c5fe8e2 100644 >--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.h >+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.h >@@ -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 @@ class TextStream; > > 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 ViewportConstraints; > 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*); >diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinatorTypes.h b/Source/WebCore/page/scrolling/ScrollingCoordinatorTypes.h >new file mode 100644 >index 0000000000000000000000000000000000000000..137ebd2ffcc9c8fe400c0cec67d6016967914b15 >--- /dev/null >+++ b/Source/WebCore/page/scrolling/ScrollingCoordinatorTypes.h >@@ -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. >+}; >+ >+} >diff --git a/Source/WebCore/page/scrolling/ScrollingTree.cpp b/Source/WebCore/page/scrolling/ScrollingTree.cpp >index 524393dd16aa637ff161d675b80ffd94e7aa1500..434f584079b4454911cbb28a31e577e516c73a69 100644 >--- a/Source/WebCore/page/scrolling/ScrollingTree.cpp >+++ b/Source/WebCore/page/scrolling/ScrollingTree.cpp >@@ -403,6 +403,19 @@ String ScrollingTree::scrollingTreeAsText() > 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) >diff --git a/Source/WebCore/page/scrolling/ScrollingTree.h b/Source/WebCore/page/scrolling/ScrollingTree.h >index efc68415c39430df7f27043fe982332775567632..6d2468307a8ed0243c028374d64f978c98a03ec9 100644 >--- a/Source/WebCore/page/scrolling/ScrollingTree.h >+++ b/Source/WebCore/page/scrolling/ScrollingTree.h >@@ -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 @@ public: > #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*/) { } >diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.h b/Source/WebCore/page/scrolling/ScrollingTreeNode.h >index 2f4415ac8852669c730d28a65751131e5ba2c993..2ae1a361f8197ad78ccf26d15a9c944b3d624060 100644 >--- a/Source/WebCore/page/scrolling/ScrollingTreeNode.h >+++ b/Source/WebCore/page/scrolling/ScrollingTreeNode.h >@@ -31,6 +31,7 @@ > #include "ScrollTypes.h" > #include "ScrollingCoordinator.h" > #include "ScrollingStateNode.h" >+#include "TouchAction.h" > #include <wtf/RefCounted.h> > #include <wtf/TypeCasts.h> > >diff --git a/Source/WebCore/platform/EventTrackingRegions.cpp b/Source/WebCore/platform/EventTrackingRegions.cpp >index 7e763c8953dca8e6dd7cacad6252407c70c5f863..437780098528bed10962f4862071b28671010944 100644 >--- a/Source/WebCore/platform/EventTrackingRegions.cpp >+++ b/Source/WebCore/platform/EventTrackingRegions.cpp >@@ -73,7 +73,19 @@ void EventTrackingRegions::unite(const EventTrackingRegions& eventTrackingRegion > 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 >diff --git a/Source/WebCore/platform/EventTrackingRegions.h b/Source/WebCore/platform/EventTrackingRegions.h >index 3d58ba55efd63ed9bae40501e309b861fc9e9c05..e71f51adadd5c7e1c0e3bcfef4a75f42a85d6bb1 100644 >--- a/Source/WebCore/platform/EventTrackingRegions.h >+++ b/Source/WebCore/platform/EventTrackingRegions.h >@@ -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 @@ enum class TrackingType : uint8_t { > 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 @@ struct EventTrackingRegions { > // 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); >diff --git a/Source/WebCore/style/StyleTreeResolver.cpp b/Source/WebCore/style/StyleTreeResolver.cpp >index 1b134dfea3a250e52cfd864c8bb1573cb854c21f..3d57b267af76e81697ac16bc42bbaa67a97c8a42 100644 >--- a/Source/WebCore/style/StyleTreeResolver.cpp >+++ b/Source/WebCore/style/StyleTreeResolver.cpp >@@ -236,6 +236,11 @@ ElementUpdates TreeResolver::resolveElement(Element& element) > 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) }; > } > >diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >index 3b0529a4a959a23bd5d040f5fa008ad7b0fec71f..54d199e25d84b25183fd9bf9f02cb95b5ac8ca77 100644 >--- a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >@@ -329,10 +329,40 @@ Optional<DOMCacheEngine::Record> ArgumentCoder<DOMCacheEngine::Record>::decode(D > 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 @@ bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTracking > 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 @@ bool ArgumentCoder<Region>::decode(Decoder& decoder, Region& region) > 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); >diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.h b/Source/WebKit/Shared/WebCoreArgumentCoders.h >index 3ae7e475d8336efc27dcf2c51f722cc2db9845a6..2ef5e43adb48951819c9a713d69e013d20dd6e9b 100644 >--- a/Source/WebKit/Shared/WebCoreArgumentCoders.h >+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.h >@@ -121,6 +121,9 @@ struct ResourceLoadStatistics; > struct ScrollableAreaParameters; > struct TextCheckingResult; > struct TextIndicatorData; >+#if ENABLE(POINTER_EVENTS) >+struct TouchActionData; >+#endif > struct ViewportAttributes; > struct WindowFeatures; > >@@ -199,6 +202,13 @@ template<> struct ArgumentCoder<WebCore::DOMCacheEngine::Record> { > 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::Path> { > 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> { >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >index 0a3048055528551ce4d9d698249198bdc9e6af62..b987c9924b986f6402abc8851e3c8ada92da46ff 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >@@ -2583,6 +2583,14 @@ - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi > // 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 @@ - (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView > [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:)]) >diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp >index a959c93bc759d1c98668c81dada01e267f35b9b1..f964fc981ed314cab7eb44ef83cd369287fae34c 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp >@@ -206,6 +206,33 @@ String RemoteScrollingCoordinatorProxy::scrollingTreeAsText() const > 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) >diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h >index b32d79fe9289b1457c8ead2d8d35c3b79daec96a..df0715662f4dc995cbd535ca37e81c26a29d3e13 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h >@@ -98,6 +98,13 @@ public: > > 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 @@ private: > > 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 }; >diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h b/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h >index 397efed636f8f5cf83f461a24c7a84a3eab5f87d..a34c80c7057dfd0c0c3a9044265725321a7a2cb9 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h >@@ -65,6 +65,9 @@ public: > 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; >diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm b/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm >index 4cc7e1a87b85ac70637e15f44cc1e4f8f9219c4c..dc55da941c037fab634b8e08a11decab32515a45 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm >@@ -67,9 +67,29 @@ - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView > _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 @@ - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi > || originalVerticalSnapPosition != _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex()) { > _scrollingTreeNodeDelegate->currentSnapPointIndicesDidChange(_scrollingTreeNodeDelegate->scrollingNode().currentHorizontalSnapPointIndex(), _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex()); > } >-} > #endif >+} > > - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)willDecelerate > { >@@ -117,6 +137,28 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView > } > } > >+#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 @@ void ScrollingTreeScrollingNodeDelegateIOS::currentSnapPointIndicesDidChange(uns > 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) >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index 6c8f85ca72c95fa3fb73e55f0f33227ad4a3df6b..19b12f42d39c556d6ddc647b69d4257a8e75d363 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -678,6 +678,7 @@ public: > 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); >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >index 5ea7776e5ae807dde085f28a2f2971370b007edd..baca3faa3ccf67e35d5cfca4840742cccc2614b0 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >@@ -196,6 +196,10 @@ struct WKAutoCorrectionData { > RetainPtr<UIWebTouchEventsGestureRecognizer> _touchEventGestureRecognizer; > > BOOL _canSendTouchEventsAsynchronously; >+#if ENABLE(POINTER_EVENTS) >+ BOOL _preventsPanningInXAxis; >+ BOOL _preventsPanningInYAxis; >+#endif > > RetainPtr<WKSyntheticClickTapGestureRecognizer> _singleTapGestureRecognizer; > RetainPtr<_UIWebHighlightLongPressGestureRecognizer> _highlightLongPressGestureRecognizer; >@@ -349,6 +353,10 @@ struct WKAutoCorrectionData { > @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; >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >index 8ca9fc2dd2017e3d82ee3344fe7ec5aa17e6ae96..1a12a6cc77c7ef1c59cb73feb2c7873af58d44b6 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >@@ -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 @@ static inline bool hasFocusedElement(WebKit::FocusedElementInformation focusedEl > 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 @@ - (void)cleanupInteraction > _hasSetUpInteractions = NO; > _suppressSelectionAssistantReasons = { }; > _isZoomingToRevealFocusedElement = NO; >+ >+#if ENABLE(POINTER_EVENTS) >+ [self _resetPanningPreventionFlags]; >+#endif > } > > - (void)_removeDefaultGestureRecognizers >@@ -1121,16 +1142,62 @@ - (void)_webTouchEventsRecognized:(UIWebTouchEventsGestureRecognizer *)gestureRe > 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) { >+ if (auto touchActionData = scrollingCoordinator->touchActionDataAtPoint(touchPoint.location())) { >+ 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 +2259,10 @@ - (void)_didEndScrollingOrZooming > } > _page->setIsScrollingOrZooming(false); > >+#if ENABLE(POINTER_EVENTS) >+ [self _resetPanningPreventionFlags]; >+#endif >+ > #if PLATFORM(WATCHOS) > [_focusedFormControlView engageFocusedFormControlNavigation]; > #endif >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index f4992821f8019ef2a4b4ae64a5741a62542dfd1e..8452dda78df3718e1a5f96cf5a31a66ee3482ecb 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,33 @@ >+2019-01-28 Antoine Quint <graouts@apple.com> >+ >+ 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 NOBODY (OOPS!). >+ >+ 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 <nvasilyev@apple.com> > > Web Inspector: Add Changes panel to Elements tab >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-expected.txt b/LayoutTests/pointerevents/ios/touch-action-none-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..727e8af81bd984c8c34070551af5b61e9270ff81 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting touch-action: none on an element prevents page scrolling. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt b/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..2c0072910245ef57587ebe9c52c9fabc0532d1c2 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt >@@ -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. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html b/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html >new file mode 100644 >index 0000000000000000000000000000000000000000..9e9614ffefcefbeafe674174b581541c0f235141 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-on-iframe-expected.txt b/LayoutTests/pointerevents/ios/touch-action-none-on-iframe-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..46751bdd7c3462a1e086ffc73f353ed44daf7fbc >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-on-iframe-expected.txt >@@ -0,0 +1,4 @@ >+ >+ >+PASS Testing that setting touch-action: none on an iframe and interacting with its content prevents page scrolling. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-on-iframe.html b/LayoutTests/pointerevents/ios/touch-action-none-on-iframe.html >new file mode 100644 >index 0000000000000000000000000000000000000000..d927ea8db46174341c51a0c4cc5253e5b6207a2d >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-on-iframe.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-on-parent-expected.txt b/LayoutTests/pointerevents/ios/touch-action-none-on-parent-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..d02b1304968a291eadd13739526fc0d8cbe2a29b >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-on-parent-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting touch-action: none on a parent element prevents page scrolling. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-on-parent.html b/LayoutTests/pointerevents/ios/touch-action-none-on-parent.html >new file mode 100644 >index 0000000000000000000000000000000000000000..9a480793f790a5c86241769f9931e8f480cf3b74 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-on-parent.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-none.html b/LayoutTests/pointerevents/ios/touch-action-none.html >new file mode 100644 >index 0000000000000000000000000000000000000000..ad00b83bb98e4ae5ddc9a59c98672a6a0329ce8b >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-pan-x-expected.txt b/LayoutTests/pointerevents/ios/touch-action-pan-x-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..87e78379df45a7177476c8be7b5d64040f0aacde >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pan-x-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting touch-action: pan-x on an element prevents page scrolling in the y-axis. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y-expected.txt b/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..be97bde327fc29c3ae4b780a111647cd68fd5f82 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting 'touch-action: pan-x pan-y' on an element allows page scrolling in both axes. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html b/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html >new file mode 100644 >index 0000000000000000000000000000000000000000..52291a4d8c67c22151c229d837d71a8f3d00ab14 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-pan-x.html b/LayoutTests/pointerevents/ios/touch-action-pan-x.html >new file mode 100644 >index 0000000000000000000000000000000000000000..cb9205f7ef5da2cab70019cfb8ea70f95d77c6f7 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pan-x.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt b/LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..3ff658c3864226715ae67ea42fbb928680692848 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting touch-action: pan-x on an element prevents page scrolling in the x-axis. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-pan-y.html b/LayoutTests/pointerevents/ios/touch-action-pan-y.html >new file mode 100644 >index 0000000000000000000000000000000000000000..9090d39601fbee17bfd1b95f243e9fabc522795e >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pan-y.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..094e67615e2a5998f3333f90fda30dd1dca5a468 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting touch-action: pinch-zoom on an element allows page zooming. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html >new file mode 100644 >index 0000000000000000000000000000000000000000..2da63c9429e1aa139026ed4313cea6d5d4787976 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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 >diff --git a/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..60c85b9aa552df9b71d9ae43974050e0c2899800 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting touch-action: pinch-zoom on an element prevents page scrolling. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html >new file mode 100644 >index 0000000000000000000000000000000000000000..02341c621507a3ee83734d27713d84bff559d7dd >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html >@@ -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="../../resources/testharness.js"></script> >+<script src="../../resources/testharnessreport.js"></script> >+<script src="../utils.js"></script> >+<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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
koivisto
:
review+
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193447
:
359189
|
359208
|
359257
|
359258
|
359260
|
359363
|
359365
|
360028
|
360029
|
360031
|
360089
|
360090
|
360100
| 360338