WebKit Bugzilla
Attachment 359258 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-20190116085841.patch (text/plain), 72.83 KB, created by
Antoine Quint
on 2019-01-15 23:58:43 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Antoine Quint
Created:
2019-01-15 23:58:43 PST
Size:
72.83 KB
patch
obsolete
>Subversion Revision: 240032 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index d6adce9fbf75a41b2f62b65f3a293c916ec82cbb..e86a1a9f95ab8e6c0aafec078dbcaa37406aca78 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,66 @@ >+2019-01-15 Antoine Quint <graouts@apple.com> >+ >+ Limit user-agent interactions based on the touch-action property >+ 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 compute >+ a Region containing the bounds of each of those elements and send it up to the UI process along with touch regions. >+ >+ Additionally, we allow a list of allowed touch actions to be computed for a given element accounting 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-conflicting-values-in-hierarchy.html >+ pointerevents/ios/touch-action-none-in-iframe.html >+ 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: >+ * dom/Document.cpp: >+ (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::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::touchActionElements 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/ScrollingTree.cpp: >+ (WebCore::ScrollingTree::mayHaveTouchActionsForPoint const): Provide a quick way to indentify whether the provided point is contained in the region >+ of elements with a non-auto touch-action property. >+ (WebCore::ScrollingTree::setTouchActionsForScrollingNodeID): >+ * page/scrolling/ScrollingTree.h: >+ * page/scrolling/ScrollingTreeNode.h: >+ (WebCore::ScrollingTreeNode::touchActions const): >+ (WebCore::ScrollingTreeNode::setTouchActions): >+ * platform/EventTrackingRegions.cpp: >+ (WebCore::operator==): >+ * platform/EventTrackingRegions.h: >+ * rendering/RenderLayer.cpp: >+ (WebCore::RenderLayer::scrollTo): Ensure the region of elements with a non-auto touch-action property is updated when scrolling has occured. >+ * 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-15 Fujii Hironori <Hironori.Fujii@sony.com> > > Unreviewed WinCairo build fix. >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index bc216476e6a064f860d87e50dc8cee7454846413..122e11013c89db86c995950dc5d60ed475084279 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,58 @@ >+2019-01-15 Antoine Quint <graouts@apple.com> >+ >+ Limit user-agent interactions based on the touch-action property >+ 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 may be contained within the region of elements with a non-auto touch-action property. If it is, we call into the >+ Web process, synchronously, to compile the list of permitted touch actions such that we may then customize the behavior of the nearest scroll view >+ to pan or zoom only as instructed. >+ >+ * Scripts/webkit/messages.py: >+ * Shared/WebCoreArgumentCoders.cpp: >+ (IPC::ArgumentCoder<EventTrackingRegions>::encode): >+ (IPC::ArgumentCoder<EventTrackingRegions>::decode): >+ * 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::mayHaveTouchActionsForPoint const): >+ (WebKit::RemoteScrollingCoordinatorProxy::setTouchActionsForScrollingNodeID): >+ * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h: >+ * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm: >+ (-[WKScrollingNodeScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Apply the same logic as in WKWebView. >+ (-[WKScrollingNodeScrollViewDelegate scrollViewDidEndDragging:willDecelerate:]): Reset the touch actions for the associated scroll node to start the next interaction >+ in the default state. >+ (-[WKScrollingNodeScrollViewDelegate scrollViewDidEndDecelerating:]): Reset the touch actions for the associated scroll node to start the next interaction in the >+ default state. >+ (-[WKScrollingNodeScrollViewDelegate _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Apply the same logic as in WKWebView. >+ * UIProcess/WebPageProxy.h: >+ (WebKit::WebPageProxy::isScrollingOrZooming const): >+ * UIProcess/ios/WKContentViewInteraction.h: >+ * UIProcess/ios/WKContentViewInteraction.mm: >+ (-[WKContentView preventsPanningInXAxis]): >+ (-[WKContentView preventsPanningInYAxis]): >+ (-[WKContentView cleanupInteraction]): Reset the panning prevention ivars to their default state. >+ (-[WKContentView _webTouchEventsRecognized:]): As we process touches, check whether there may be touch actions set for this touch's location, and if we haven't excluded >+ that possibility, call into the Web process synchronously to find which touch actions these might be exactly. Then, based on those touch actions, either setDefaultPrevented >+ on the _touchEventGestureRecognizer if the touch action is "none" or selectively disable panning and zooming as well as all the other tap-related user interactions. >+ (-[WKContentView _resetPanningPreventionFlags]): >+ (-[WKContentView _didEndScrollingOrZooming]): >+ * UIProcess/ios/WebPageProxyIOS.mm: >+ (WebKit::WebPageProxy::mayHaveTouchActionsForTouchEvent const): Check all touch points for a given event to see if it might have associated touch actions. This checks that >+ these are new touches and that their location is contained within the touch action region computed in the Web process and sent to the UI process. >+ (WebKit::WebPageProxy::touchActionsForTouchEvent): >+ * WebProcess/WebPage/WebPage.h: >+ * WebProcess/WebPage/WebPage.messages.in: >+ * WebProcess/WebPage/ios/WebPageIOS.mm: >+ (WebKit::WebPage::touchActionsForTouchEvent): Iterate over all touch points for a given event and return, if there is a non-auto touch action set, create a pair consisting of a >+ list of touch-actions and the scrolling node ID for the nearest scroll node to the element that hit tests for this location. >+ > 2019-01-15 Fujii Hironori <Hironori.Fujii@sony.com> > > Unreviewed WinCairo build fix. >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index b96fa2dec41e49e314142d0b64522ba3c7924c6a..2978a67a41d2ea38343876fa8be86a4efb589669 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -31951,6 +31951,7 @@ > 49E912AE0EFAC906009D0CAF /* TimingFunction.h in Headers */, > 0F54DD081881D5F5003EEDBB /* Touch.h in Headers */, > 71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */, >+ 71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */, > 0F54DD091881D5F5003EEDBB /* TouchEvent.h in Headers */, > 0F54DD0A1881D5F5003EEDBB /* TouchList.h in Headers */, > 070334D71459FFD5008D8D45 /* TrackBase.h in Headers */, >diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp >index fe5c951bc64d662daec515f9e43ea4ec904e81c6..a98b4216caec9f3336c40512609b7685912d4c04 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" >@@ -4142,6 +4143,12 @@ void Document::invalidateRenderingDependentRegions(AnnotationsAction annotations > > #if PLATFORM(IOS_FAMILY) && ENABLE(TOUCH_EVENTS) > setTouchEventRegionsNeedUpdate(); >+ if (auto* page = this->page()) { >+ if (auto* frameView = view()) { >+ if (auto* scrollingCoordinator = page->scrollingCoordinator()) >+ scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView); >+ } >+ } > #endif > } > >@@ -4526,6 +4533,11 @@ void Document::nodeWillBeRemoved(Node& node) > > if (is<Text>(node)) > m_markers->removeMarkers(&node); >+ >+#if ENABLE(TOUCH_EVENTS) >+ if (m_touchActionElements) >+ m_touchActionElements->removeAll(&node); >+#endif > } > > static Node* fallbackFocusNavigationStartingNodeAfterRemoval(Node& node) >@@ -8648,4 +8660,33 @@ void Document::setPaintWorkletGlobalScopeForName(const String& name, Ref<PaintWo > } > #endif > >+#if ENABLE(TOUCH_EVENTS) >+void Document::updateTouchActionElements(Node& node, RenderStyle* style) >+{ >+ if (!m_touchActionElements) >+ m_touchActionElements = std::make_unique<EventTargetSet>(); >+ >+ bool changed = false; >+ >+ if (style && style->touchActions() != TouchAction::Auto) >+ changed |= m_touchActionElements->add(&node).isNewEntry; >+ else >+ changed |= m_touchActionElements->removeAll(&node); >+ >+#if ENABLE(TOUCH_EVENTS) && 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 eb44551ccaf34a09b89378aa871349771396e319..886888ea984a7473639f0e6e8b3cb3af915264e1 100644 >--- a/Source/WebCore/dom/Document.h >+++ b/Source/WebCore/dom/Document.h >@@ -1273,6 +1273,7 @@ public: > #if ENABLE(TOUCH_EVENTS) > bool hasTouchEventHandlers() const { return (m_touchEventTargets.get()) ? m_touchEventTargets->size() : false; } > bool touchEventTargetsContain(Node& node) const { return m_touchEventTargets ? m_touchEventTargets->contains(&node) : false; } >+ void updateTouchActionElements(Node&, RenderStyle*); > #else > bool hasTouchEventHandlers() const { return false; } > bool touchEventTargetsContain(Node&) const { return false; } >@@ -1292,6 +1293,15 @@ public: > #endif > } > >+ const EventTargetSet* touchActionElements() const >+ { >+#if ENABLE(TOUCH_EVENTS) >+ return m_touchActionElements.get(); >+#else >+ return nullptr; >+#endif >+ } >+ > const EventTargetSet* wheelEventTargets() const { return m_wheelEventTargets.get(); } > > typedef std::pair<Region, bool> RegionFixedPair; >@@ -1873,6 +1883,7 @@ private: > > #if ENABLE(TOUCH_EVENTS) > std::unique_ptr<EventTargetSet> m_touchEventTargets; >+ std::unique_ptr<EventTargetSet> m_touchActionElements; > #endif > std::unique_ptr<EventTargetSet> m_wheelEventTargets; > >diff --git a/Source/WebCore/dom/Element.cpp b/Source/WebCore/dom/Element.cpp >index da5cd2f081c1e88f8111efff326df2026444c43a..42d5551439d05d5c7eabc2461fe90f166f5e73e1 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" >@@ -3416,7 +3418,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(); >@@ -4120,4 +4122,66 @@ void Element::setAttributeStyleMap(Ref<StylePropertyMap>&& map) > } > #endif > >+#if ENABLE(TOUCH_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; >+} >+#endif >+ >+#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 >+ > } // namespace WebCore >diff --git a/Source/WebCore/dom/Element.h b/Source/WebCore/dom/Element.h >index 169fde13adb627041fdd8b5e6f5b8f2adcb386f3..ed726c95b92150510a7555745d0257d84bc5126a 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" >@@ -56,6 +57,7 @@ class PseudoElement; > class RenderTreePosition; > class StylePropertyMap; > class WebAnimation; >+enum class TouchAction : uint8_t; > struct ElementStyle; > struct ScrollIntoViewOptions; > >@@ -588,6 +590,14 @@ public: > ExceptionOr<Ref<WebAnimation>> animate(JSC::ExecState&, JSC::Strong<JSC::JSObject>&&, Optional<Variant<double, KeyframeAnimationOptions>>&&); > Vector<RefPtr<WebAnimation>> getAnimations(); > >+#if ENABLE(TOUCH_EVENTS) >+ WEBCORE_EXPORT OptionSet<TouchAction> computedTouchActions() const; >+#endif >+ >+#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) >+ WEBCORE_EXPORT ScrollingNodeID nearestScrollingNodeIDUsingTouchOverflowScrolling() const; >+#endif >+ > protected: > Element(const QualifiedName&, Document&, ConstructionType); > >diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp >index cb8738396a3a58ef4520ee548cf831eb415471b8..9ca7859aaf0e33ea7c22bcada15096f8c34c5d34 100644 >--- a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp >+++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp >@@ -99,7 +99,25 @@ EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegionsForFrame( > auto* document = frame.document(); > if (!document) > return EventTrackingRegions(); >- return document->eventTrackingRegions(); >+ auto eventTrackingRegions = document->eventTrackingRegions(); >+ eventTrackingRegions.touchActionRegion = frame.document()->absoluteRegionForEventTargets(frame.document()->touchActionElements()).first; >+ >+ for (auto* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) { >+ auto* subframeView = subframe->view(); >+ if (!subframeView) >+ continue; >+ >+ if (auto* subframeDocument = subframe->document()) { >+ auto subframeRegion = subframeDocument->absoluteRegionForEventTargets(subframeDocument->touchActionElements()).first; >+ // Map from the frame document to our document. >+ auto offset = subframeView->contentsToContainingViewContents(IntPoint()); >+ // FIXME: this translation ignores non-trival transforms on the frame. >+ subframeRegion.translate(toIntSize(offset)); >+ eventTrackingRegions.touchActionRegion.unite(subframeRegion); >+ } >+ } >+ >+ return eventTrackingRegions; > #else > auto* frameView = frame.view(); > if (!frameView) >diff --git a/Source/WebCore/page/scrolling/ScrollingTree.cpp b/Source/WebCore/page/scrolling/ScrollingTree.cpp >index 524393dd16aa637ff161d675b80ffd94e7aa1500..33a2ffb7c747e631de293964926c901e5dcbd7b6 100644 >--- a/Source/WebCore/page/scrolling/ScrollingTree.cpp >+++ b/Source/WebCore/page/scrolling/ScrollingTree.cpp >@@ -247,6 +247,11 @@ TrackingType ScrollingTree::eventTrackingTypeForPoint(const AtomicString& eventN > return m_eventTrackingRegions.trackingTypeForPoint(eventName, p); > } > >+bool ScrollingTree::mayHaveTouchActionsForPoint(const IntPoint p) const >+{ >+ return m_eventTrackingRegions.touchActionRegion.contains(p); >+} >+ > bool ScrollingTree::isRubberBandInProgress() > { > LockHolder lock(m_mutex); >@@ -403,6 +408,12 @@ String ScrollingTree::scrollingTreeAsText() > return ts.release(); > } > >+void ScrollingTree::setTouchActionsForScrollingNodeID(OptionSet<TouchAction> touchActions, ScrollingNodeID scrollingNodeID) >+{ >+ if (auto* scrollingTreeNode = nodeForID(scrollingNodeID)) >+ scrollingTreeNode->setTouchActions(touchActions); >+} >+ > } // namespace WebCore > > #endif // ENABLE(ASYNC_SCROLLING) >diff --git a/Source/WebCore/page/scrolling/ScrollingTree.h b/Source/WebCore/page/scrolling/ScrollingTree.h >index efc68415c39430df7f27043fe982332775567632..3693332eb36ef1d9a8a440e577dbdbcc70039b98 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,8 @@ public: > #endif > > WEBCORE_EXPORT TrackingType eventTrackingTypeForPoint(const AtomicString& eventName, IntPoint); >- >+ WEBCORE_EXPORT bool mayHaveTouchActionsForPoint(const IntPoint) const; >+ > #if PLATFORM(MAC) > virtual void handleWheelEventPhase(PlatformWheelEventPhase) = 0; > virtual void setActiveScrollSnapIndices(ScrollingNodeID, unsigned /*horizontalIndex*/, unsigned /*verticalIndex*/) { } >@@ -151,6 +153,7 @@ public: > } > > WEBCORE_EXPORT String scrollingTreeAsText(); >+ WEBCORE_EXPORT void setTouchActionsForScrollingNodeID(OptionSet<TouchAction>, ScrollingNodeID); > > protected: > void setMainFrameScrollPosition(FloatPoint); >diff --git a/Source/WebCore/page/scrolling/ScrollingTreeNode.h b/Source/WebCore/page/scrolling/ScrollingTreeNode.h >index bf7f61a361b93b47dfe434e05f93288ccf590bb6..fab7f4ae615ea6c381e5bf76b5a90213f302ab5a 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> > >@@ -70,6 +71,9 @@ public: > > WEBCORE_EXPORT void dump(WTF::TextStream&, ScrollingStateTreeAsTextBehavior) const; > >+ OptionSet<TouchAction> touchActions() const { return m_touchActions; } >+ void setTouchActions(OptionSet<TouchAction> touchActions) { m_touchActions = touchActions; } >+ > protected: > ScrollingTreeNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID); > ScrollingTree& scrollingTree() const { return m_scrollingTree; } >@@ -85,6 +89,7 @@ private: > const ScrollingNodeID m_nodeID; > > ScrollingTreeNode* m_parent; >+ OptionSet<TouchAction> m_touchActions; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/platform/EventTrackingRegions.cpp b/Source/WebCore/platform/EventTrackingRegions.cpp >index 7e763c8953dca8e6dd7cacad6252407c70c5f863..9fbe1008a136db33fa1b84195b304e536b5208c2 100644 >--- a/Source/WebCore/platform/EventTrackingRegions.cpp >+++ b/Source/WebCore/platform/EventTrackingRegions.cpp >@@ -73,7 +73,8 @@ void EventTrackingRegions::unite(const EventTrackingRegions& eventTrackingRegion > bool operator==(const EventTrackingRegions& a, const EventTrackingRegions& b) > { > return a.asynchronousDispatchRegion == b.asynchronousDispatchRegion >- && a.eventSpecificSynchronousDispatchRegions == b.eventSpecificSynchronousDispatchRegions; >+ && a.eventSpecificSynchronousDispatchRegions == b.eventSpecificSynchronousDispatchRegions >+ && a.touchActionRegion == b.touchActionRegion; > } > > } // namespace WebCore >diff --git a/Source/WebCore/platform/EventTrackingRegions.h b/Source/WebCore/platform/EventTrackingRegions.h >index 3d58ba55efd63ed9bae40501e309b861fc9e9c05..bbcdbda3aaa6fd1da11c864c1cb77ab1167c43fe 100644 >--- a/Source/WebCore/platform/EventTrackingRegions.h >+++ b/Source/WebCore/platform/EventTrackingRegions.h >@@ -46,6 +46,8 @@ struct EventTrackingRegions { > // The key is the Event Name with an active handler. > HashMap<String, Region> eventSpecificSynchronousDispatchRegions; > >+ Region touchActionRegion; >+ > bool isEmpty() const; > > void translate(IntSize); >diff --git a/Source/WebCore/style/StyleTreeResolver.cpp b/Source/WebCore/style/StyleTreeResolver.cpp >index 34f8f3c3c86e3fdf95f18606b6aca6132e5d8ee3..90917139713b3acdc32bf2c5d6be7557d0b16fdb 100644 >--- a/Source/WebCore/style/StyleTreeResolver.cpp >+++ b/Source/WebCore/style/StyleTreeResolver.cpp >@@ -232,6 +232,10 @@ ElementUpdates TreeResolver::resolveElement(Element& element) > auto beforeUpdate = resolvePseudoStyle(element, update, PseudoId::Before); > auto afterUpdate = resolvePseudoStyle(element, update, PseudoId::After); > >+#if ENABLE(TOUCH_EVENTS) >+ m_document.updateTouchActionElements(element, update.style.get()); >+#endif >+ > return { WTFMove(update), descendantsToResolve, WTFMove(beforeUpdate), WTFMove(afterUpdate) }; > } > >diff --git a/Source/WebKit/Scripts/webkit/messages.py b/Source/WebKit/Scripts/webkit/messages.py >index c774bc41c8294f0811671d6b74ca86d48ee17944..7a475a1638c60eeb53b172e8df02e5ddc09a8adb 100644 >--- a/Source/WebKit/Scripts/webkit/messages.py >+++ b/Source/WebKit/Scripts/webkit/messages.py >@@ -422,6 +422,7 @@ def headers_for_type(type): > 'WebCore::RecentSearch': ['<WebCore/SearchPopupMenu.h>'], > 'WebCore::RouteSharingPolicy': ['<WebCore/AudioSession.h>'], > 'WebCore::SWServerConnectionIdentifier': ['<WebCore/ServiceWorkerTypes.h>'], >+ 'WebCore::ScrollingNodeID': ['<WebCore/ScrollingCoordinator.h>'], > 'WebCore::ServiceWorkerJobIdentifier': ['<WebCore/ServiceWorkerTypes.h>'], > 'WebCore::ServiceWorkerOrClientData': ['<WebCore/ServiceWorkerTypes.h>', '<WebCore/ServiceWorkerClientData.h>', '<WebCore/ServiceWorkerData.h>'], > 'WebCore::ServiceWorkerOrClientIdentifier': ['<WebCore/ServiceWorkerTypes.h>', '<WebCore/ServiceWorkerClientIdentifier.h>'], >diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >index 3b0529a4a959a23bd5d040f5fa008ad7b0fec71f..164953bcb61a94b3f43f9e5f28f162a937c5d098 100644 >--- a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp >@@ -333,6 +333,7 @@ void ArgumentCoder<EventTrackingRegions>::encode(Encoder& encoder, const EventTr > { > encoder << eventTrackingRegions.asynchronousDispatchRegion; > encoder << eventTrackingRegions.eventSpecificSynchronousDispatchRegions; >+ encoder << eventTrackingRegions.touchActionRegion; > } > > bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTrackingRegions& eventTrackingRegions) >@@ -343,8 +344,12 @@ bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTracking > HashMap<String, Region> eventSpecificSynchronousDispatchRegions; > if (!decoder.decode(eventSpecificSynchronousDispatchRegions)) > return false; >+ Region touchActionRegion; >+ if (!decoder.decode(touchActionRegion)) >+ return false; > eventTrackingRegions.asynchronousDispatchRegion = WTFMove(asynchronousDispatchRegion); > eventTrackingRegions.eventSpecificSynchronousDispatchRegions = WTFMove(eventSpecificSynchronousDispatchRegions); >+ eventTrackingRegions.touchActionRegion = WTFMove(touchActionRegion); > return true; > } > >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >index 074cddfd2784e869128d020bed59213a1cbdde68..0fde781c57818d73cbc40288dac0e1b795d9d329 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >@@ -2580,6 +2580,12 @@ - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoi > // zooming. We'll animate to the right place once the zoom finishes. > if ([scrollView isZooming]) > *targetContentOffset = [scrollView contentOffset]; >+ else { >+ if ([_contentView preventsPanningInXAxis]) >+ targetContentOffset->x = scrollView.contentOffset.x; >+ if ([_contentView preventsPanningInYAxis]) >+ targetContentOffset->y = scrollView.contentOffset.y; >+ } > #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. >@@ -2617,6 +2623,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 a367e15f00536f8cb5c850907ab43a7c3166730a..1c2a551f307747892d0787920c2feb76dcf7a921 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp >@@ -164,6 +164,11 @@ TrackingType RemoteScrollingCoordinatorProxy::eventTrackingTypeForPoint(const At > return m_scrollingTree->eventTrackingTypeForPoint(eventName, p); > } > >+bool RemoteScrollingCoordinatorProxy::mayHaveTouchActionsForPoint(IntPoint p) const >+{ >+ return m_scrollingTree->mayHaveTouchActionsForPoint(p); >+} >+ > void RemoteScrollingCoordinatorProxy::viewportChangedViaDelegatedScrolling(ScrollingNodeID nodeID, const FloatRect& fixedPositionRect, double scale) > { > m_scrollingTree->viewportChangedViaDelegatedScrolling(nodeID, fixedPositionRect, scale); >@@ -205,6 +210,12 @@ String RemoteScrollingCoordinatorProxy::scrollingTreeAsText() const > return emptyString(); > } > >+void RemoteScrollingCoordinatorProxy::setTouchActionsForScrollingNodeID(OptionSet<TouchAction> touchActions, ScrollingNodeID scrollingNodeID) >+{ >+ >+ m_scrollingTree->setTouchActionsForScrollingNodeID(touchActions, scrollingNodeID); >+} >+ > } // namespace WebKit > > #endif // ENABLE(ASYNC_SCROLLING) >diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h >index b32d79fe9289b1457c8ead2d8d35c3b79daec96a..c698729cb79e7d8075e2562cb4add7fd2beda8aa 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h >@@ -58,6 +58,7 @@ public: > void scrollingTreeNodeRequestsScroll(WebCore::ScrollingNodeID, const WebCore::FloatPoint& scrollPosition, bool representsProgrammaticScroll); > > WebCore::TrackingType eventTrackingTypeForPoint(const AtomicString& eventName, WebCore::IntPoint) const; >+ bool mayHaveTouchActionsForPoint(WebCore::IntPoint) const; > > // Called externally when native views move around. > void viewportChangedViaDelegatedScrolling(WebCore::ScrollingNodeID, const WebCore::FloatRect& fixedPositionRect, double scale); >@@ -97,6 +98,7 @@ public: > #endif > > String scrollingTreeAsText() const; >+ void setTouchActionsForScrollingNodeID(OptionSet<WebCore::TouchAction>, WebCore::ScrollingNodeID); > > private: > void connectStateNodeLayers(WebCore::ScrollingStateTree&, const RemoteLayerTreeHost&); >diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm b/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm >index 4cc7e1a87b85ac70637e15f44cc1e4f8f9219c4c..1813eefdada41868293a17218a46ffec241f9b0a 100644 >--- a/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm >+++ b/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm >@@ -67,9 +67,25 @@ - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView > _scrollingTreeNodeDelegate->scrollWillStart(); > } > >-#if ENABLE(CSS_SCROLL_SNAP) > - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset > { >+ if (![scrollView isZooming]) { >+ auto touchActions = _scrollingTreeNodeDelegate->scrollingNode().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; >+ } >+ } >+ } >+ >+#if ENABLE(CSS_SCROLL_SNAP) > CGFloat horizontalTarget = targetContentOffset->x; > CGFloat verticalTarget = targetContentOffset->y; > >@@ -96,8 +112,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 > { >@@ -105,6 +121,7 @@ - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL > _inUserInteraction = NO; > _scrollingTreeNodeDelegate->scrollViewDidScroll(scrollView.contentOffset, _inUserInteraction); > _scrollingTreeNodeDelegate->scrollDidEnd(); >+ _scrollingTreeNodeDelegate->scrollingNode().setTouchActions(WebCore::TouchAction::Auto); > } > } > >@@ -114,9 +131,32 @@ - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView > _inUserInteraction = NO; > _scrollingTreeNodeDelegate->scrollViewDidScroll(scrollView.contentOffset, _inUserInteraction); > _scrollingTreeNodeDelegate->scrollDidEnd(); >+ _scrollingTreeNodeDelegate->scrollingNode().setTouchActions(WebCore::TouchAction::Auto); > } > } > >+- (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 touchActions = _scrollingTreeNodeDelegate->scrollingNode().touchActions(); >+ if (touchActions == WebCore::TouchAction::Auto || touchActions == WebCore::TouchAction::Manipulation) >+ return offset; >+ >+ CGPoint adjustedContentOffset = CGPointMake(offset.x, offset.y); >+ >+ bool canPanX = true; >+ bool canPanY = true; >+ if (!touchActions.contains(WebCore::TouchAction::PanX)) { >+ adjustedContentOffset.x = start.x; >+ canPanX = false; >+ } >+ if (!touchActions.contains(WebCore::TouchAction::PanY)) { >+ adjustedContentOffset.y = start.y; >+ canPanY = false; >+ } >+ >+ return adjustedContentOffset; >+} >+ > @end > > namespace WebKit { >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index de98694aa37db3c7f2ce27cc829a9200211de10d..56c4c6fe0af404253e8cbabb874ba813c82fa555 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -81,9 +81,11 @@ > #include <WebCore/MediaProducer.h> > #include <WebCore/PlatformScreen.h> > #include <WebCore/ScrollTypes.h> >+#include <WebCore/ScrollingCoordinator.h> > #include <WebCore/SearchPopupMenu.h> > #include <WebCore/TextChecking.h> > #include <WebCore/TextGranularity.h> >+#include <WebCore/TouchAction.h> > #include <WebCore/UserInterfaceLayoutDirection.h> > #include <memory> > #include <wtf/CompletionHandler.h> >@@ -680,6 +682,7 @@ public: > void requestStartDataInteraction(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition); > void requestAdditionalItemsForDragSession(const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition); > void didConcludeEditDataInteraction(Optional<WebCore::TextIndicatorData>); >+bool isScrollingOrZooming() const { return m_isScrollingOrZooming; } > #endif > #endif > #if ENABLE(DATA_DETECTION) >@@ -1156,6 +1159,10 @@ public: > void cancelPotentialTap(); > void tapHighlightAtPosition(const WebCore::FloatPoint&, uint64_t& requestID); > void handleTap(const WebCore::FloatPoint&, uint64_t layerTreeTransactionIdAtLastTouchStart); >+#if ENABLE(TOUCH_EVENTS) >+ bool mayHaveTouchActionsForTouchEvent(const WebTouchEvent&) const; >+ Vector<std::pair<OptionSet<WebCore::TouchAction>, WebCore::ScrollingNodeID>> touchActionsForTouchEvent(const WebTouchEvent&); >+#endif > > void inspectorNodeSearchMovedToPosition(const WebCore::FloatPoint&); > void inspectorNodeSearchEndedAtPosition(const WebCore::FloatPoint&); >diff --git a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >index a7ffff78f30a70f4fc590d705a1d19e3a3881bef..d688a1120fb9d7a45b4afadd1c78978db83b5c83 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h >@@ -196,6 +196,8 @@ struct WKAutoCorrectionData { > RetainPtr<UIWebTouchEventsGestureRecognizer> _touchEventGestureRecognizer; > > BOOL _canSendTouchEventsAsynchronously; >+ BOOL _preventsPanningInXAxis; >+ BOOL _preventsPanningInYAxis; > > RetainPtr<WKSyntheticClickTapGestureRecognizer> _singleTapGestureRecognizer; > RetainPtr<_UIWebHighlightLongPressGestureRecognizer> _highlightLongPressGestureRecognizer; >@@ -349,6 +351,8 @@ struct WKAutoCorrectionData { > @property (nonatomic, readonly) const WebKit::FocusedElementInformation& focusedElementInformation; > @property (nonatomic, readonly) UIWebFormAccessory *formAccessoryView; > @property (nonatomic, readonly) UITextInputAssistantItem *inputAssistantItemForWebView; >+@property (nonatomic, readonly) BOOL preventsPanningInXAxis; >+@property (nonatomic, readonly) BOOL preventsPanningInYAxis; > > #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 3e5292a78c2acf461a68293b3aac422c90d7b3c5..9c5efb0bd0a21a6e5b373508fb12c27274f39405 100644 >--- a/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >+++ b/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm >@@ -37,6 +37,7 @@ > #import "NativeWebKeyboardEvent.h" > #import "NativeWebTouchEvent.h" > #import "RemoteLayerTreeDrawingAreaProxy.h" >+#import "RemoteScrollingCoordinatorProxy.h" > #import "SmartMagnificationController.h" > #import "TextInputSPI.h" > #import "UIKitSPI.h" >@@ -91,6 +92,7 @@ > #import <WebCore/Scrollbar.h> > #import <WebCore/ShareData.h> > #import <WebCore/TextIndicator.h> >+#import <WebCore/TouchAction.h> > #import <WebCore/VisibleSelection.h> > #import <WebCore/WebEvent.h> > #import <WebCore/WritingDirection.h> >@@ -615,6 +617,16 @@ static inline bool hasFocusedElement(WebKit::FocusedElementInformation focusedEl > return (focusedElementInformation.elementType != WebKit::InputType::None); > } > >+- (BOOL)preventsPanningInXAxis >+{ >+ return _preventsPanningInXAxis; >+} >+ >+- (BOOL)preventsPanningInYAxis >+{ >+ return _preventsPanningInYAxis; >+} >+ > - (WKFormInputSession *)_formInputSession > { > return _formInputSession.get(); >@@ -861,6 +873,9 @@ - (void)cleanupInteraction > _hasSetUpInteractions = NO; > _suppressSelectionAssistantReasons = { }; > _isZoomingToRevealFocusedElement = NO; >+ >+ _preventsPanningInXAxis = NO; >+ _preventsPanningInYAxis = NO; > } > > - (void)_removeDefaultGestureRecognizers >@@ -1128,16 +1143,56 @@ - (void)_webTouchEventsRecognized:(UIWebTouchEventsGestureRecognizer *)gestureRe > WebKit::NativeWebTouchEvent nativeWebTouchEvent(lastTouchEvent); > nativeWebTouchEvent.setCanPreventNativeGestures(!_canSendTouchEventsAsynchronously || [gestureRecognizer isDefaultPrevented]); > >+ if (_page->mayHaveTouchActionsForTouchEvent(nativeWebTouchEvent)) { >+ for (auto touchActionsAndScrollingNodeIDPair : _page->touchActionsForTouchEvent(nativeWebTouchEvent)) { >+ auto touchActions = touchActionsAndScrollingNodeIDPair.first; >+ if (touchActions == WebCore::TouchAction::None) >+ [_touchEventGestureRecognizer setDefaultPrevented:YES]; >+ else { >+ // Disable all tap-related recognizers. >+ [_singleTapGestureRecognizer setEnabled:NO]; >+ [_nonBlockingDoubleTapGestureRecognizer setEnabled:NO]; >+ [_twoFingerDoubleTapGestureRecognizer setEnabled:NO]; >+ [_highlightLongPressGestureRecognizer setEnabled:NO]; >+ [_twoFingerSingleTapGestureRecognizer setEnabled:NO]; >+ [_stylusSingleTapGestureRecognizer setEnabled:NO]; >+ [_doubleTapGestureRecognizer setEnabled:NO]; >+ [_longPressGestureRecognizer setEnabled:NO]; >+ if (!touchActions.contains(WebCore::TouchAction::Manipulation)) { >+ if (auto scrollingNodeID = touchActionsAndScrollingNodeIDPair.second) { >+ if (auto* scrollingCoordinator = _page->scrollingCoordinatorProxy()) >+ scrollingCoordinator->setTouchActionsForScrollingNodeID(touchActions, scrollingNodeID); >+ } else { >+ if (!touchActions.contains(WebCore::TouchAction::PinchZoom)) >+ _webView.scrollView.pinchGestureRecognizer.enabled = NO; >+ _preventsPanningInXAxis = !touchActions.contains(WebCore::TouchAction::PanX); >+ _preventsPanningInYAxis = !touchActions.contains(WebCore::TouchAction::PanY); >+ } >+ } >+ } >+ } >+ } >+ > if (_canSendTouchEventsAsynchronously) > _page->handleTouchEventAsynchronously(nativeWebTouchEvent); > else > _page->handleTouchEventSynchronously(nativeWebTouchEvent); > >- if (nativeWebTouchEvent.allTouchPointsAreReleased()) >+ if (nativeWebTouchEvent.allTouchPointsAreReleased()) { > _canSendTouchEventsAsynchronously = NO; >+ >+ if (!_page->isScrollingOrZooming()) >+ [self _resetPanningPreventionFlags]; >+ } > #endif > } > >+- (void)_resetPanningPreventionFlags >+{ >+ _preventsPanningInXAxis = NO; >+ _preventsPanningInYAxis = NO; >+} >+ > - (void)_inspectorNodeSearchRecognized:(UIGestureRecognizer *)gestureRecognizer > { > ASSERT(_inspectorNodeSearchEnabled); >@@ -2194,6 +2249,8 @@ - (void)_didEndScrollingOrZooming > } > _page->setIsScrollingOrZooming(false); > >+ [self _resetPanningPreventionFlags]; >+ > #if PLATFORM(WATCHOS) > [_focusedFormControlView engageFocusedFormControlNavigation]; > #endif >diff --git a/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm b/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm >index b9bd70c9bee1069e1b4f123098b9cae12d6487c5..44e381bff0abc28c528119134016efab582e159f 100644 >--- a/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm >+++ b/Source/WebKit/UIProcess/ios/WebPageProxyIOS.mm >@@ -41,6 +41,7 @@ > #import "RemoteLayerTreeDrawingAreaProxy.h" > #import "RemoteLayerTreeDrawingAreaProxyMessages.h" > #import "RemoteLayerTreeTransaction.h" >+#import "RemoteScrollingCoordinatorProxy.h" > #import "UIKitSPI.h" > #import "UserData.h" > #import "VideoFullscreenManagerProxy.h" >@@ -824,6 +825,24 @@ void WebPageProxy::potentialTapAtPosition(const WebCore::FloatPoint& position, u > process().send(Messages::WebPage::PotentialTapAtPosition(requestID, position), m_pageID); > } > >+#if ENABLE(TOUCH_EVENTS) >+bool WebPageProxy::mayHaveTouchActionsForTouchEvent(const WebTouchEvent& event) const >+{ >+ for (auto& touchPoint : event.touchPoints()) { >+ if (touchPoint.phase() == WebPlatformTouchPoint::TouchPressed && m_scrollingCoordinatorProxy->mayHaveTouchActionsForPoint(touchPoint.location())) >+ return true; >+ } >+ return false; >+} >+ >+Vector<std::pair<OptionSet<WebCore::TouchAction>, WebCore::ScrollingNodeID>> WebPageProxy::touchActionsForTouchEvent(const WebTouchEvent& event) >+{ >+ Vector<std::pair<OptionSet<WebCore::TouchAction>, WebCore::ScrollingNodeID>> touchActions; >+ process().sendSync(Messages::WebPage::TouchActionsForTouchEvent(event), Messages::WebPage::TouchActionsForTouchEvent::Reply(touchActions), m_pageID); >+ return touchActions; >+} >+#endif >+ > void WebPageProxy::commitPotentialTap(uint64_t layerTreeTransactionIdAtLastTouchStart) > { > process().send(Messages::WebPage::CommitPotentialTap(layerTreeTransactionIdAtLastTouchStart), m_pageID); >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h >index 715e124520ff076b960aed70e9b92075a6552aef..58e5b6e45bf00dcd0fc279fbb62d0b2597cfd860 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.h >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.h >@@ -618,6 +618,7 @@ public: > void cancelPotentialTap(); > void cancelPotentialTapInFrame(WebFrame&); > void tapHighlightAtPosition(uint64_t requestID, const WebCore::FloatPoint&); >+ void touchActionsForTouchEvent(const WebTouchEvent&, Vector<std::pair<OptionSet<WebCore::TouchAction>, WebCore::ScrollingNodeID>>&); > > void inspectorNodeSearchMovedToPosition(const WebCore::FloatPoint&); > void inspectorNodeSearchEndedAtPosition(const WebCore::FloatPoint&); >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in >index 54abbaf8934ccdcf8e4f20f783fcb6b9f03040eb..37fed333b972da8fc92a44655e55206d35c094f5 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in >@@ -108,6 +108,7 @@ messages -> WebPage LegacyReceiver { > CancelAutoscroll() > RequestFocusedElementInformation(WebKit::CallbackID callbackID) > HardwareKeyboardAvailabilityChanged() >+ TouchActionsForTouchEvent(WebKit::WebTouchEvent event) -> (Vector<std::pair<OptionSet<WebCore::TouchAction>, WebCore::ScrollingNodeID>> touchActions) LegacySync > #endif > > SetControlledByAutomation(bool controlled) >diff --git a/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm b/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm >index 06696c065cc7748c1cbde00545e37364ea694e53..b615225d47fe4e1546912b3ce28dc6f5b8300e7d 100644 >--- a/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm >+++ b/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm >@@ -103,6 +103,7 @@ > #import <WebCore/PlatformMouseEvent.h> > #import <WebCore/RenderBlock.h> > #import <WebCore/RenderImage.h> >+#import <WebCore/RenderLayerBacking.h> > #import <WebCore/RenderThemeIOS.h> > #import <WebCore/RenderView.h> > #import <WebCore/RuntimeApplicationChecks.h> >@@ -862,6 +863,29 @@ void WebPage::tapHighlightAtPosition(uint64_t requestID, const FloatPoint& posit > sendTapHighlightForNodeIfNecessary(requestID, mainframe.nodeRespondingToClickEvents(position, adjustedPoint)); > } > >+void WebPage::touchActionsForTouchEvent(const WebTouchEvent& event, Vector<std::pair<OptionSet<TouchAction>, ScrollingNodeID>>& touchActions) >+{ >+ layoutIfNeeded(); >+ >+#if ENABLE(IOS_TOUCH_EVENTS) >+ auto& eventHandler = m_page->mainFrame().eventHandler(); >+ for (auto& touch : event.touchPoints()) { >+ auto result = eventHandler.hitTestResultAtPoint((touch.location()), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent); >+ std::pair<OptionSet<TouchAction>, ScrollingNodeID> touchActionsAndScrollingNodeIDPair; >+ if (auto* element = result.innerNonSharedElement()) { >+ touchActionsAndScrollingNodeIDPair.first = element->computedTouchActions(); >+#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING) >+ // Now we should also look to see if our element is or is contained within an "overflow-scroll: touch" element >+ // so that we can report its layer id to the UI process. >+ if (auto scrollingNodeID = element->nearestScrollingNodeIDUsingTouchOverflowScrolling()) >+ touchActionsAndScrollingNodeIDPair.second = scrollingNodeID; >+#endif >+ } >+ touchActions.append(touchActionsAndScrollingNodeIDPair); >+ } >+#endif >+} >+ > void WebPage::inspectorNodeSearchMovedToPosition(const FloatPoint& position) > { > IntPoint adjustedPoint = roundedIntPoint(position); >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 173660a6d6d39314c27e7cb00e7b3c974ef2ca3e..4acc963d582b185d53ffedacc1703f60da520fb7 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,37 @@ >+2019-01-15 Antoine Quint <graouts@apple.com> >+ >+ Limit user-agent interactions based on the touch-action property >+ 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-conflicting-values-in-hierarchy-expected.txt: Added. >+ * pointerevents/ios/touch-action-conflicting-values-in-hierarchy.html: Added. >+ * pointerevents/ios/touch-action-none-expected.txt: Added. >+ * pointerevents/ios/touch-action-none-in-iframe-expected.txt: Added. >+ * pointerevents/ios/touch-action-none-in-iframe.html: 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-15 Ryosuke Niwa <rniwa@webkit.org> > > VisualViewport API should be updated upon opening of keyboard >diff --git a/LayoutTests/pointerevents/ios/touch-action-conflicting-values-in-hierarchy-expected.txt b/LayoutTests/pointerevents/ios/touch-action-conflicting-values-in-hierarchy-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..510b8f72ea74b38ade2134593d265218d2b9bb0d >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-conflicting-values-in-hierarchy-expected.txt >@@ -0,0 +1,3 @@ >+ >+PASS Testing that setting conflicting touch-action values on the target element and parent prevents page scrolling. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-conflicting-values-in-hierarchy.html b/LayoutTests/pointerevents/ios/touch-action-conflicting-values-in-hierarchy.html >new file mode 100644 >index 0000000000000000000000000000000000000000..75b5076bbebe6b1e134a5a05aa4e8c30d08f4f3b >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-conflicting-values-in-hierarchy.html >@@ -0,0 +1,31 @@ >+<!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 = "pan-x"; >+ >+ 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_equals(window.pageYOffset, 0, "The page was not scrolled in the y-axis."); >+ test.done(); >+ }); >+}, "Testing that setting conflicting touch-action values on the target element and parent prevents page scrolling."); >+ >+</script> >+</body> >+</html> >\ No newline at end of file >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-iframe-expected.txt b/LayoutTests/pointerevents/ios/touch-action-none-in-iframe-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..b8584103239f1bc7f7e9feb7537f5c997e99e277 >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-in-iframe-expected.txt >@@ -0,0 +1,4 @@ >+ >+ >+PASS Testing that setting touch-action: none in content hosted in an iframe prevents page scrolling. >+ >diff --git a/LayoutTests/pointerevents/ios/touch-action-none-in-iframe.html b/LayoutTests/pointerevents/ios/touch-action-none-in-iframe.html >new file mode 100644 >index 0000000000000000000000000000000000000000..728b82b335d3dbc9561451db5008342120aff83c >--- /dev/null >+++ b/LayoutTests/pointerevents/ios/touch-action-none-in-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; >+} >+ >+</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%; >+ touch-action: 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 in content hosted in an iframe prevents page scrolling."); >+ >+</script> >+</body> >+</html> >\ No newline at end of file >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
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193447
:
359189
|
359208
|
359257
|
359258
|
359260
|
359363
|
359365
|
360028
|
360029
|
360031
|
360089
|
360090
|
360100
|
360338