Changeset 240579 in webkit


Ignore:
Timestamp:
Jan 28, 2019 7:08:54 AM (5 years ago)
Author:
graouts@webkit.org
Message:

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

Reviewed by Antti Koivisto and Simon Fraser.

Source/WebCore:

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

Tests: pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html

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

  • WebCore.xcodeproj/project.pbxproj: Update how certain headers are exposed such that they can be used from WebKit.
  • dom/Document.cpp:

(WebCore::Document::invalidateRenderingDependentRegions):
(WebCore::Document::nodeWillBeRemoved): Ensure a node that is being removed from this document is no longer listed in its
list of elements with a non-auto touch-action property.
(WebCore::Document::absoluteEventRegionForNode):
(WebCore::Document::absoluteRegionForEventTargets):
(WebCore::Document::updateTouchActionElements): Create a list of elements with a non-auto touch-action property if one doesn't
exist yet and update it to add the given element if it contains a non-auto touch-action, or remove it if it doesn't. If the contents
of that list changed as a result, the scrolling coordinator is informed.

  • dom/Document.h:

(WebCore::Document:: const):

  • dom/Element.cpp:

(WebCore::parentCrossingFrameBoundaries):
(WebCore::Element::computedTouchActions const): Provide the list of allowed touch actions accounting for the "touch-action" property
specified on this element and all of its hierarchy, crossing frame boundary.
(WebCore::Element::nearestScrollingNodeIDUsingTouchOverflowScrolling const): Provide the ScrollingNodeID, if any, for the nearest scrolling node
for that element. This will allow the UI process to identify which scroll view's behavior to customize to reflect the element's allowed
touch actions.

  • dom/Element.h:
  • page/scrolling/ScrollingCoordinator.cpp:

(WebCore::ScrollingCoordinator::absoluteEventTrackingRegionsForFrame const): Compute the region for all elements with a non-auto touch-action property
throughout the provided frame and all of its subframes.

  • page/scrolling/ScrollingCoordinator.h:

(WebCore::ScrollableAreaParameters::operator== const): Deleted.

  • page/scrolling/ScrollingCoordinatorTypes.h: Added.

(WebCore::ScrollableAreaParameters::operator== const):

  • page/scrolling/ScrollingTree.cpp:

(WebCore::ScrollingTree::touchActionDataAtPoint const): Query the list of TouchActionData objects for a match based on the provided point. Right
now the logic is pretty crude, stopping at the first TouchActionData for which the region contains the provided point, but future patches will
account for overlap and nesting.

  • page/scrolling/ScrollingTree.h:
  • page/scrolling/ScrollingTreeNode.h:
  • platform/EventTrackingRegions.cpp:

(WebCore::operator==):

  • platform/EventTrackingRegions.h:

(WebCore::operator!=):

  • style/StyleTreeResolver.cpp:

(WebCore::Style::TreeResolver::resolveElement): Update the list of elements with a non-auto touch-action property when an element's style changes.

Source/WebKit:

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

  • Shared/WebCoreArgumentCoders.cpp:

(IPC::ArgumentCoder<TouchActionData>::encode):
(IPC::ArgumentCoder<TouchActionData>::decode):
(IPC::ArgumentCoder<EventTrackingRegions>::encode):
(IPC::ArgumentCoder<EventTrackingRegions>::decode):
(IPC::ArgumentCoder<Region>::decode):

  • Shared/WebCoreArgumentCoders.h:
  • UIProcess/API/Cocoa/WKWebView.mm:

(-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Account for panning constraints set on the content view to prevent deceleration
to pan the view if it ought not.
(-[WKWebView _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Implement an additional
UIScrollView delegation method to apply the panning constraints set on the content view while panning.

  • UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:

(WebKit::RemoteScrollingCoordinatorProxy::touchActionDataAtPoint const):
(WebKit::RemoteScrollingCoordinatorProxy::touchActionDataForScrollNodeID const):
(WebKit::RemoteScrollingCoordinatorProxy::setTouchDataForTouchIdentifier):
(WebKit::RemoteScrollingCoordinatorProxy::clearTouchDataForTouchIdentifier):

  • UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
  • UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
  • UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:

(-[WKScrollingNodeScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Apply the same logic as in WKWebView.
(-[WKScrollingNodeScrollViewDelegate _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Apply
the same logic as in WKWebView.
(WebKit::ScrollingTreeScrollingNodeDelegateIOS::touchActionData const):

  • UIProcess/WebPageProxy.h:

(WebKit::WebPageProxy::isScrollingOrZooming const):

  • UIProcess/ios/WKContentViewInteraction.h:
  • UIProcess/ios/WKContentViewInteraction.mm:

(-[WKContentView preventsPanningInXAxis]):
(-[WKContentView preventsPanningInYAxis]):
(-[WKContentView cleanupInteraction]):
(-[WKContentView _webTouchEventsRecognized:]):
(-[WKContentView _handleTouchActionsForTouchEvent:]): As we process touches, check whether there are touch actions set for this touch's points' locations. Based
on those touch actions, either setDefaultPrevented on the _touchEventGestureRecognizer if the touch action is "none" or selectively disable panning and zooming.
(-[WKContentView _resetPanningPreventionFlags]):
(-[WKContentView _didEndScrollingOrZooming]):

LayoutTests:

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

  • pointerevents/ios/touch-action-none-expected.txt: Added.
  • pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt: Added.
  • pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html: Added.
  • pointerevents/ios/touch-action-none-on-iframe-expected.txt: Added.
  • pointerevents/ios/touch-action-none-on-iframe.html: Added.
  • pointerevents/ios/touch-action-none-on-parent-expected.txt: Added.
  • pointerevents/ios/touch-action-none-on-parent.html: Added.
  • pointerevents/ios/touch-action-none.html: Added.
  • pointerevents/ios/touch-action-pan-x-expected.txt: Added.
  • pointerevents/ios/touch-action-pan-x-pan-y-expected.txt: Added.
  • pointerevents/ios/touch-action-pan-x-pan-y.html: Added.
  • pointerevents/ios/touch-action-pan-x.html: Added.
  • pointerevents/ios/touch-action-pan-y-expected.txt: Added.
  • pointerevents/ios/touch-action-pan-y.html: Added.
  • pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt: Added.
  • pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html: Added.
  • pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt: Added.
  • pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html: Added.
Location:
trunk
Files:
19 added
26 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r240559 r240579  
     12019-01-28  Antoine Quint  <graouts@apple.com>
     2
     3        Limit user-agent interactions based on the touch-action property on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=193447
     5        <rdar://problem/47283874>
     6
     7        Reviewed by Antti Koivisto and Simon Fraser.
     8
     9        Add a new series of tests that check that the "none", "pan-x", "pan-y" and "pinch-zoom" values have the expected
     10        impact on page panning on iOS.
     11
     12        * pointerevents/ios/touch-action-none-expected.txt: Added.
     13        * pointerevents/ios/touch-action-none-in-overflow-scrolling-touch-expected.txt: Added.
     14        * pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html: Added.
     15        * pointerevents/ios/touch-action-none-on-iframe-expected.txt: Added.
     16        * pointerevents/ios/touch-action-none-on-iframe.html: Added.
     17        * pointerevents/ios/touch-action-none-on-parent-expected.txt: Added.
     18        * pointerevents/ios/touch-action-none-on-parent.html: Added.
     19        * pointerevents/ios/touch-action-none.html: Added.
     20        * pointerevents/ios/touch-action-pan-x-expected.txt: Added.
     21        * pointerevents/ios/touch-action-pan-x-pan-y-expected.txt: Added.
     22        * pointerevents/ios/touch-action-pan-x-pan-y.html: Added.
     23        * pointerevents/ios/touch-action-pan-x.html: Added.
     24        * pointerevents/ios/touch-action-pan-y-expected.txt: Added.
     25        * pointerevents/ios/touch-action-pan-y.html: Added.
     26        * pointerevents/ios/touch-action-pinch-zoom-allows-zooming-expected.txt: Added.
     27        * pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html: Added.
     28        * pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling-expected.txt: Added.
     29        * pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html: Added.
     30
    1312019-01-28  Nikita Vasilyev  <nvasilyev@apple.com>
    232
  • trunk/Source/WebCore/ChangeLog

    r240558 r240579  
     12019-01-28  Antoine Quint  <graouts@apple.com>
     2
     3        Limit user-agent interactions based on the touch-action property on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=193447
     5        <rdar://problem/47283874>
     6
     7        Reviewed by Antti Koivisto and Simon Fraser.
     8
     9        We now compile a list of elements with a non-auto touch-action property that is updated whenever an element has its style changed
     10        or is removed from its document. When the content of that list changes, we inform the scrolling coordinator such that it can compile
     11        a list of TouchActionData structures which hold the touch-action value, the ID of the nearest scroll node and the Region containing
     12        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
     13        actions for a given element accounts for not only the value specified directly on that element's style, but also in its hierarchy,
     14        crossing any frame boundary towards the top-level document's root node.
     15
     16        Tests: pointerevents/ios/touch-action-none-in-overflow-scrolling-touch.html
     17               pointerevents/ios/touch-action-none-on-iframe.html
     18               pointerevents/ios/touch-action-none-on-parent.html
     19               pointerevents/ios/touch-action-none.html
     20               pointerevents/ios/touch-action-pan-x-pan-y.html
     21               pointerevents/ios/touch-action-pan-x.html
     22               pointerevents/ios/touch-action-pan-y.html
     23               pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html
     24               pointerevents/ios/touch-action-pinch-zoom-prevents-scrolling.html
     25
     26        * WebCore.xcodeproj/project.pbxproj: Update how certain headers are exposed such that they can be used from WebKit.
     27        * dom/Document.cpp:
     28        (WebCore::Document::invalidateRenderingDependentRegions):
     29        (WebCore::Document::nodeWillBeRemoved): Ensure a node that is being removed from this document is no longer listed in its
     30        list of elements with a non-auto touch-action property.
     31        (WebCore::Document::absoluteEventRegionForNode):
     32        (WebCore::Document::absoluteRegionForEventTargets):
     33        (WebCore::Document::updateTouchActionElements): Create a list of elements with a non-auto touch-action property if one doesn't
     34        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
     35        of that list changed as a result, the scrolling coordinator is informed.
     36        * dom/Document.h:
     37        (WebCore::Document:: const):
     38        * dom/Element.cpp:
     39        (WebCore::parentCrossingFrameBoundaries):
     40        (WebCore::Element::computedTouchActions const): Provide the list of allowed touch actions accounting for the "touch-action" property
     41        specified on this element and all of its hierarchy, crossing frame boundary.
     42        (WebCore::Element::nearestScrollingNodeIDUsingTouchOverflowScrolling const): Provide the ScrollingNodeID, if any, for the nearest scrolling node
     43        for that element. This will allow the UI process to identify which scroll view's behavior to customize to reflect the element's allowed
     44        touch actions.
     45        * dom/Element.h:
     46        * page/scrolling/ScrollingCoordinator.cpp:
     47        (WebCore::ScrollingCoordinator::absoluteEventTrackingRegionsForFrame const): Compute the region for all elements with a non-auto touch-action property
     48        throughout the provided frame and all of its subframes.
     49        * page/scrolling/ScrollingCoordinator.h:
     50        (WebCore::ScrollableAreaParameters::operator== const): Deleted.
     51        * page/scrolling/ScrollingCoordinatorTypes.h: Added.
     52        (WebCore::ScrollableAreaParameters::operator== const):
     53        * page/scrolling/ScrollingTree.cpp:
     54        (WebCore::ScrollingTree::touchActionDataAtPoint const): Query the list of TouchActionData objects for a match based on the provided point. Right
     55        now the logic is pretty crude, stopping at the first TouchActionData for which the region contains the provided point, but future patches will
     56        account for overlap and nesting.
     57        * page/scrolling/ScrollingTree.h:
     58        * page/scrolling/ScrollingTreeNode.h:
     59        * platform/EventTrackingRegions.cpp:
     60        (WebCore::operator==):
     61        * platform/EventTrackingRegions.h:
     62        (WebCore::operator!=):
     63        * style/StyleTreeResolver.cpp:
     64        (WebCore::Style::TreeResolver::resolveElement): Update the list of elements with a non-auto touch-action property when an element's style changes.
     65
    1662019-01-27  Michael Catanzaro  <mcatanzaro@igalia.com>
    267
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r240552 r240579  
    20972097                712BE4881FE8686A002031CC /* JSFillMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 712BE4851FE86818002031CC /* JSFillMode.h */; };
    20982098                712BE4891FE86875002031CC /* JSPlaybackDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 712BE4861FE86859002031CC /* JSPlaybackDirection.h */; };
     2099                712DBA4921F8AD83008F36B2 /* ScrollingCoordinatorTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 712DBA4721F8AD79008F36B2 /* ScrollingCoordinatorTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
    20992100                713171341FBE78DB00F758DE /* CSSPropertyBlendingClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 713171321FBE78C500F758DE /* CSSPropertyBlendingClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
    21002101                7132445120109DA500AE7FB2 /* WebAnimationUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 7132444F20109D9B00AE7FB2 /* WebAnimationUtilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    24192420                8348BFAC1B85729800912F36 /* ClassCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8348BFAA1B85729500912F36 /* ClassCollection.h */; };
    24202421                834DFAD01F7DAE5D00C2725B /* SharedStringHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 834DFACC1F7DAE5600C2725B /* SharedStringHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
    2421                 83520C7E1A71BFCC006BD2AA /* CSSFontFamily.h in Headers */ = {isa = PBXBuildFile; fileRef = 83520C7D1A71BFCC006BD2AA /* CSSFontFamily.h */; };
     2422                83520C7E1A71BFCC006BD2AA /* CSSFontFamily.h in Headers */ = {isa = PBXBuildFile; fileRef = 83520C7D1A71BFCC006BD2AA /* CSSFontFamily.h */; settings = {ATTRIBUTES = (Private, ); }; };
    24222423                8358CB701C53277500E0C2D8 /* JSXMLDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 83F570AD1C53268E007FD6CB /* JSXMLDocument.h */; };
    24232424                835D2D781F5F1FBD00141DED /* HTMLInputElementEntriesAPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 835D2D751F5F1FB800141DED /* HTMLInputElementEntriesAPI.h */; };
     
    29052906                996E59DF1DF0128D006612B9 /* NavigatorWebDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 996E59DC1DF00D90006612B9 /* NavigatorWebDriver.h */; };
    29062907                9A528E8417D7F52F00AA9518 /* FloatingObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A528E8217D7F52F00AA9518 /* FloatingObjects.h */; settings = {ATTRIBUTES = (Private, ); }; };
    2907                 9AB1F38018E2489A00534743 /* CSSToLengthConversionData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AB1F37E18E2489A00534743 /* CSSToLengthConversionData.h */; };
     2908                9AB1F38018E2489A00534743 /* CSSToLengthConversionData.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AB1F37E18E2489A00534743 /* CSSToLengthConversionData.h */; settings = {ATTRIBUTES = (Private, ); }; };
    29082909                9B24DE8E15194B9500C59C27 /* HTMLBDIElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B24DE8C15194B9500C59C27 /* HTMLBDIElement.h */; };
    29092910                9B2D8A7914997CCF00ECEF3E /* UndoStep.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B2D8A7814997CCF00ECEF3E /* UndoStep.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    47834784                E1E6EEA80B628DB3005F2F70 /* JSHTMLSelectElement.h in Headers */ = {isa = PBXBuildFile; fileRef = E1E6EEA70B628DB3005F2F70 /* JSHTMLSelectElement.h */; };
    47844785                E1EC29A00BB04C6B00EA187B /* XPathNodeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = E1EC299E0BB04C6B00EA187B /* XPathNodeSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
    4785                 E1ED8AC30CC49BE000BFC557 /* CSSPrimitiveValueMappings.h in Headers */ = {isa = PBXBuildFile; fileRef = E1ED8AC20CC49BE000BFC557 /* CSSPrimitiveValueMappings.h */; };
     4786                E1ED8AC30CC49BE000BFC557 /* CSSPrimitiveValueMappings.h in Headers */ = {isa = PBXBuildFile; fileRef = E1ED8AC20CC49BE000BFC557 /* CSSPrimitiveValueMappings.h */; settings = {ATTRIBUTES = (Private, ); }; };
    47864787                E1F1E8300C3C2BB9006DB391 /* XSLTExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F1E82E0C3C2BB9006DB391 /* XSLTExtensions.h */; };
    47874788                E1F80B8818317252007885C3 /* CryptoKeyPair.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F80B8618317252007885C3 /* CryptoKeyPair.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    93079308                712BE4861FE86859002031CC /* JSPlaybackDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSPlaybackDirection.h; sourceTree = "<group>"; };
    93089309                712BE4871FE8685A002031CC /* JSPlaybackDirection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPlaybackDirection.cpp; sourceTree = "<group>"; };
     9310                712DBA4721F8AD79008F36B2 /* ScrollingCoordinatorTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingCoordinatorTypes.h; sourceTree = "<group>"; };
    93099311                7130141D1DC9C08600CA3A88 /* pip-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "pip-support.js"; sourceTree = "<group>"; };
    93109312                713171321FBE78C500F758DE /* CSSPropertyBlendingClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSPropertyBlendingClient.h; sourceTree = "<group>"; };
     
    1690716909                                1AF62EE414DA22A70041556C /* ScrollingCoordinator.cpp */,
    1690816910                                1AF62EE514DA22A70041556C /* ScrollingCoordinator.h */,
     16911                                712DBA4721F8AD79008F36B2 /* ScrollingCoordinatorTypes.h */,
    1690916912                                51C61B081DE536E7008A212D /* ScrollingMomentumCalculator.cpp */,
    1691016913                                51C61B091DE536E7008A212D /* ScrollingMomentumCalculator.h */,
     
    2957429577                                089582560E857A7E00F82C83 /* ImageLoader.h in Headers */,
    2957529578                                BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */,
    29576                                 A59C230A21F29206004EC939 /* InspectorCPUProfilerAgent.h in Headers */,
    2957729579                                2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */,
    2957829580                                B51A2F3F17D7D3AE0072517A /* ImageQualityController.h in Headers */,
     
    2963729639                                1C81B95C0E97330800266E07 /* InspectorClient.h in Headers */,
    2963829640                                1C81B95A0E97330800266E07 /* InspectorController.h in Headers */,
     29641                                A59C230A21F29206004EC939 /* InspectorCPUProfilerAgent.h in Headers */,
    2963929642                                A5B81CA91FAA44620037D1E6 /* InspectorCSSAgent.h in Headers */,
    2964029643                                4A9CC82116BF9BB400EC645A /* InspectorCSSOMWrappers.h in Headers */,
     
    3141331416                                0FC4E40D187F82E10045882C /* ScrollingCoordinatorIOS.h in Headers */,
    3141431417                                9391A991162746CB00297330 /* ScrollingCoordinatorMac.h in Headers */,
     31418                                712DBA4921F8AD83008F36B2 /* ScrollingCoordinatorTypes.h in Headers */,
    3141531419                                51C61B0B1DE536E7008A212D /* ScrollingMomentumCalculator.h in Headers */,
    3141631420                                517DEEE81DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h in Headers */,
  • trunk/Source/WebCore/dom/Document.cpp

    r240552 r240579  
    209209#include "TextEvent.h"
    210210#include "TextNodeTraversal.h"
     211#include "TouchAction.h"
    211212#include "TransformSource.h"
    212213#include "TreeWalker.h"
     
    41524153    setTouchEventRegionsNeedUpdate();
    41534154#endif
     4155
     4156#if ENABLE(POINTER_EVENTS)
     4157    if (auto* page = this->page()) {
     4158        if (auto* frameView = view()) {
     4159            if (auto* scrollingCoordinator = page->scrollingCoordinator())
     4160                scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
     4161        }
     4162    }
     4163#endif
    41544164}
    41554165
     
    45354545    if (is<Text>(node))
    45364546        m_markers->removeMarkers(node);
     4547
     4548#if ENABLE(POINTER_EVENTS)
     4549    if (m_touchActionElements && is<Element>(node))
     4550        m_touchActionElements->remove(&downcast<Element>(node));
     4551#endif
    45374552}
    45384553
     
    70977112}
    70987113
     7114Document::RegionFixedPair Document::absoluteEventRegionForNode(Node& node)
     7115{
     7116    Region region;
     7117    LayoutRect rootRelativeBounds;
     7118    bool insideFixedPosition = false;
     7119
     7120    if (is<Document>(node)) {
     7121        auto& document = downcast<Document>(node);
     7122        if (&document == this)
     7123            rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
     7124        else if (Element* element = document.ownerElement())
     7125            rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
     7126    } else if (is<Element>(node)) {
     7127        auto& element = downcast<Element>(node);
     7128        if (is<HTMLBodyElement>(element)) {
     7129            // For the body, just use the document bounds.
     7130            // The body may not cover this whole area, but it's OK for this region to be an overestimate.
     7131            rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
     7132        } else
     7133            rootRelativeBounds = element.absoluteEventHandlerBounds(insideFixedPosition);
     7134    }
     7135
     7136    if (!rootRelativeBounds.isEmpty())
     7137        region.unite(Region(enclosingIntRect(rootRelativeBounds)));
     7138
     7139    return RegionFixedPair(region, insideFixedPosition);
     7140}
     7141
    70997142Document::RegionFixedPair Document::absoluteRegionForEventTargets(const EventTargetSet* targets)
    71007143{
     
    71087151
    71097152    for (auto& keyValuePair : *targets) {
    7110         LayoutRect rootRelativeBounds;
    7111 
    7112         if (is<Document>(keyValuePair.key)) {
    7113             Document* document = downcast<Document>(keyValuePair.key);
    7114             if (document == this)
    7115                 rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
    7116             else if (Element* element = document->ownerElement())
    7117                 rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
    7118         } else if (is<Element>(keyValuePair.key)) {
    7119             Element* element = downcast<Element>(keyValuePair.key);
    7120             if (is<HTMLBodyElement>(element)) {
    7121                 // For the body, just use the document bounds.
    7122                 // The body may not cover this whole area, but it's OK for this region to be an overestimate.
    7123                 rootRelativeBounds = absoluteEventHandlerBounds(insideFixedPosition);
    7124             } else
    7125                 rootRelativeBounds = element->absoluteEventHandlerBounds(insideFixedPosition);
     7153        if (auto* node = keyValuePair.key) {
     7154            auto targetRegionFixedPair = absoluteEventRegionForNode(*node);
     7155            targetRegion.unite(targetRegionFixedPair.first);
     7156            insideFixedPosition |= targetRegionFixedPair.second;
    71267157        }
    7127        
    7128         if (!rootRelativeBounds.isEmpty())
    7129             targetRegion.unite(Region(enclosingIntRect(rootRelativeBounds)));
    71307158    }
    71317159
     
    86598687#endif
    86608688
     8689#if ENABLE(POINTER_EVENTS)
     8690void Document::updateTouchActionElements(Element& element, const RenderStyle& style)
     8691{
     8692    bool changed = false;
     8693
     8694    if (style.touchActions() != TouchAction::Auto) {
     8695        if (!m_touchActionElements)
     8696            m_touchActionElements = std::make_unique<HashSet<Element*>>();
     8697        changed |= m_touchActionElements->add(&element).isNewEntry;
     8698    } else if (m_touchActionElements)
     8699        changed |= m_touchActionElements->remove(&element);
     8700
     8701#if PLATFORM(IOS_FAMILY)
     8702    if (!changed)
     8703        return;
     8704
     8705    Page* page = this->page();
     8706    if (!page)
     8707        return;
     8708
     8709    if (FrameView* frameView = view()) {
     8710        if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator())
     8711            scrollingCoordinator->frameViewEventTrackingRegionsChanged(*frameView);
     8712    }
     8713#endif
     8714}
     8715#endif
     8716
    86618717} // namespace WebCore
  • trunk/Source/WebCore/dom/Document.h

    r240552 r240579  
    12771277    bool touchEventTargetsContain(Node&) const { return false; }
    12781278#endif
     1279#if ENABLE(POINTER_EVENTS)
     1280    void updateTouchActionElements(Element&, const RenderStyle&);
     1281    const HashSet<Element*>* touchActionElements() const { return m_touchActionElements.get(); }
     1282#endif
    12791283
    12801284    void didAddTouchEventHandler(Node&);
     
    12951299
    12961300    typedef std::pair<Region, bool> RegionFixedPair;
     1301    RegionFixedPair absoluteEventRegionForNode(Node&);
    12971302    RegionFixedPair absoluteRegionForEventTargets(const EventTargetSet*);
    12981303
     
    18761881    std::unique_ptr<EventTargetSet> m_touchEventTargets;
    18771882#endif
     1883#if ENABLE(POINTER_EVENTS)
     1884    std::unique_ptr<HashSet<Element*>> m_touchActionElements;
     1885#endif
    18781886    std::unique_ptr<EventTargetSet> m_wheelEventTargets;
    18791887
  • trunk/Source/WebCore/dom/Element.cpp

    r240472 r240579  
    8282#include "RenderFragmentContainer.h"
    8383#include "RenderLayer.h"
     84#include "RenderLayerBacking.h"
     85#include "RenderLayerCompositor.h"
    8486#include "RenderListBox.h"
    8587#include "RenderTheme.h"
     
    34193421}
    34203422
    3421 static Element* parentCrossingFrameBoundaries(Element* element)
     3423static Element* parentCrossingFrameBoundaries(const Element* element)
    34223424{
    34233425    ASSERT(element);
     
    41234125#endif
    41244126
     4127#if ENABLE(POINTER_EVENTS)
     4128OptionSet<TouchAction> Element::computedTouchActions() const
     4129{
     4130    OptionSet<TouchAction> computedTouchActions = TouchAction::Auto;
     4131    for (auto* element = this; element; element = parentCrossingFrameBoundaries(element)) {
     4132        auto* renderer = element->renderer();
     4133        if (!renderer)
     4134            continue;
     4135
     4136        auto touchActions = renderer->style().touchActions();
     4137
     4138        // Once we've encountered touch-action: none, we know that this will be the computed value.
     4139        if (touchActions == TouchAction::None)
     4140            return touchActions;
     4141
     4142        // If the computed touch-action so far was "auto", we can just use the current element's touch-action.
     4143        if (computedTouchActions == TouchAction::Auto) {
     4144            computedTouchActions = touchActions;
     4145            continue;
     4146        }
     4147
     4148        // If the current element has touch-action: auto or the same touch-action as the computed touch-action,
     4149        // we need to keep going up the ancestry chain.
     4150        if (touchActions == TouchAction::Auto || touchActions == computedTouchActions)
     4151            continue;
     4152
     4153        // Now, the element's touch-action and the computed touch-action are different and are neither "auto" nor "none".
     4154        if (computedTouchActions == TouchAction::Manipulation) {
     4155            // If the computed touch-action is "manipulation", we can take the current element's touch-action as the newly
     4156            // computed touch-action.
     4157            computedTouchActions = touchActions;
     4158        } else if (touchActions == TouchAction::Manipulation) {
     4159            // Otherwise, we have a restricted computed touch-action so far. If the current element's touch-action is "manipulation"
     4160            // then we can just keep going and leave the computed touch-action untouched.
     4161            continue;
     4162        }
     4163
     4164        // In any other case, we have competing restrictive touch-action values that can only yield "none".
     4165        return TouchAction::None;
     4166    }
     4167    return computedTouchActions;
     4168}
     4169
     4170#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
     4171ScrollingNodeID Element::nearestScrollingNodeIDUsingTouchOverflowScrolling() const
     4172{
     4173    if (!renderer())
     4174        return 0;
     4175
     4176    // We are not interested in the root, so check that we also have a valid parent.
     4177    for (auto* layer = renderer()->enclosingLayer(); layer && layer->parent(); layer = layer->parent()) {
     4178        if (layer->isComposited()) {
     4179            if (auto scrollingNodeID = layer->backing()->scrollingNodeIDForRole(ScrollCoordinationRole::Scrolling))
     4180                return scrollingNodeID;
     4181        }
     4182    }
     4183
     4184    return 0;
     4185}
     4186#endif
     4187#endif
     4188
    41254189} // namespace WebCore
  • trunk/Source/WebCore/dom/Element.h

    r240237 r240579  
    3232#include "ScrollToOptions.h"
    3333#include "ScrollTypes.h"
     34#include "ScrollingCoordinator.h"
    3435#include "ShadowRootMode.h"
    3536#include "SimulatedClickOptions.h"
     
    7677};
    7778
     79#if ENABLE(POINTER_EVENTS)
     80enum class TouchAction : uint8_t;
     81#endif
     82
    7883class Element : public ContainerNode {
    7984    WTF_MAKE_ISO_ALLOCATED(Element);
     
    589594    Vector<RefPtr<WebAnimation>> getAnimations();
    590595
     596#if ENABLE(POINTER_EVENTS)
     597    OptionSet<TouchAction> computedTouchActions() const;
     598#if ENABLE(ACCELERATED_OVERFLOW_SCROLLING)
     599    ScrollingNodeID nearestScrollingNodeIDUsingTouchOverflowScrolling() const;
     600#endif
     601#endif
     602
    591603protected:
    592604    Element(const QualifiedName&, Document&, ConstructionType);
  • trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp

    r240435 r240579  
    3939#include "RenderLayerCompositor.h"
    4040#include "RenderView.h"
     41#include "RuntimeEnabledFeatures.h"
    4142#include "ScrollAnimator.h"
    4243#include "Settings.h"
     
    108109    if (!document)
    109110        return EventTrackingRegions();
    110     return document->eventTrackingRegions();
     111    auto eventTrackingRegions = document->eventTrackingRegions();
     112
     113#if ENABLE(POINTER_EVENTS)
     114    if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled()) {
     115        if (auto* touchActionElements = frame.document()->touchActionElements()) {
     116            auto& touchActionData = eventTrackingRegions.touchActionData;
     117            for (const auto& element : *touchActionElements) {
     118                ASSERT(element);
     119                touchActionData.append({
     120                    element->computedTouchActions(),
     121                    element->nearestScrollingNodeIDUsingTouchOverflowScrolling(),
     122                    element->document().absoluteEventRegionForNode(*element).first
     123                });
     124            }
     125        }
     126    }
     127#endif
     128
     129    return eventTrackingRegions;
    111130#else
    112131    auto* frameView = frame.view();
  • trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h

    r240551 r240579  
    3131#include "ScrollSnapOffsetsInfo.h"
    3232#include "ScrollTypes.h"
     33#include "ScrollingCoordinatorTypes.h"
    3334#include <wtf/Forward.h>
    3435#include <wtf/ThreadSafeRefCounted.h>
     
    5152
    5253namespace WebCore {
    53 
    54 typedef unsigned SynchronousScrollingReasons;
    55 typedef uint64_t ScrollingNodeID;
    56 
    57 enum class ScrollingNodeType : uint8_t {
    58     MainFrame,
    59     Subframe,
    60     FrameHosting,
    61     Overflow,
    62     Fixed,
    63     Sticky
    64 };
    65 
    66 enum ScrollingStateTreeAsTextBehaviorFlags {
    67     ScrollingStateTreeAsTextBehaviorNormal                  = 0,
    68     ScrollingStateTreeAsTextBehaviorIncludeLayerIDs         = 1 << 0,
    69     ScrollingStateTreeAsTextBehaviorIncludeNodeIDs          = 1 << 1,
    70     ScrollingStateTreeAsTextBehaviorIncludeLayerPositions   = 1 << 2,
    71     ScrollingStateTreeAsTextBehaviorDebug                   = ScrollingStateTreeAsTextBehaviorIncludeLayerIDs | ScrollingStateTreeAsTextBehaviorIncludeNodeIDs | ScrollingStateTreeAsTextBehaviorIncludeLayerPositions
    72 };
    73 typedef unsigned ScrollingStateTreeAsTextBehavior;
    7454
    7555class Document;
     
    8666class ScrollingTree;
    8767#endif
    88 
    89 enum class ScrollingLayerPositionAction {
    90     Set,
    91     SetApproximate,
    92     Sync
    93 };
    94 
    95 struct ScrollableAreaParameters {
    96     ScrollElasticity horizontalScrollElasticity { ScrollElasticityNone };
    97     ScrollElasticity verticalScrollElasticity { ScrollElasticityNone };
    98 
    99     ScrollbarMode horizontalScrollbarMode { ScrollbarAuto };
    100     ScrollbarMode verticalScrollbarMode { ScrollbarAuto };
    101 
    102     bool hasEnabledHorizontalScrollbar { false };
    103     bool hasEnabledVerticalScrollbar { false };
    104 
    105     bool useDarkAppearanceForScrollbars { false };
    106 
    107     bool operator==(const ScrollableAreaParameters& other) const
    108     {
    109         return horizontalScrollElasticity == other.horizontalScrollElasticity
    110             && verticalScrollElasticity == other.verticalScrollElasticity
    111             && horizontalScrollbarMode == other.horizontalScrollbarMode
    112             && verticalScrollbarMode == other.verticalScrollbarMode
    113             && hasEnabledHorizontalScrollbar == other.hasEnabledHorizontalScrollbar
    114             && hasEnabledVerticalScrollbar == other.hasEnabledVerticalScrollbar
    115             && useDarkAppearanceForScrollbars == other.useDarkAppearanceForScrollbars;
    116     }
    117 };
    118 
    119 enum class ViewportRectStability {
    120     Stable,
    121     Unstable,
    122     ChangingObscuredInsetsInteractively // This implies Unstable.
    123 };
    12468
    12569class ScrollingCoordinator : public ThreadSafeRefCounted<ScrollingCoordinator> {
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.cpp

    r239427 r240579  
    404404}
    405405
     406#if ENABLE(POINTER_EVENTS)
     407Optional<TouchActionData> ScrollingTree::touchActionDataAtPoint(IntPoint p) const
     408{
     409    // FIXME: This does not handle the case where there are multiple regions matching this point.
     410    for (auto& touchActionData : m_eventTrackingRegions.touchActionData) {
     411        if (touchActionData.region.contains(p))
     412            return touchActionData;
     413    }
     414
     415    return WTF::nullopt;
     416}
     417#endif
     418
    406419} // namespace WebCore
    407420
  • trunk/Source/WebCore/page/scrolling/ScrollingTree.h

    r239427 r240579  
    3131#include "Region.h"
    3232#include "ScrollingCoordinator.h"
     33#include "TouchAction.h"
    3334#include "WheelEventTestTrigger.h"
    3435#include <wtf/HashMap.h>
     
    105106
    106107    WEBCORE_EXPORT TrackingType eventTrackingTypeForPoint(const AtomicString& eventName, IntPoint);
    107    
     108#if ENABLE(POINTER_EVENTS)
     109    WEBCORE_EXPORT Optional<TouchActionData> touchActionDataAtPoint(IntPoint) const;
     110#endif
     111
    108112#if PLATFORM(MAC)
    109113    virtual void handleWheelEventPhase(PlatformWheelEventPhase) = 0;
  • trunk/Source/WebCore/page/scrolling/ScrollingTreeNode.h

    r240435 r240579  
    3232#include "ScrollingCoordinator.h"
    3333#include "ScrollingStateNode.h"
     34#include "TouchAction.h"
    3435#include <wtf/RefCounted.h>
    3536#include <wtf/TypeCasts.h>
  • trunk/Source/WebCore/platform/EventTrackingRegions.cpp

    r202408 r240579  
    7474{
    7575    return a.asynchronousDispatchRegion == b.asynchronousDispatchRegion
     76#if ENABLE(POINTER_EVENTS)
     77        && a.touchActionData == b.touchActionData
     78#endif
    7679        && a.eventSpecificSynchronousDispatchRegions == b.eventSpecificSynchronousDispatchRegions;
    7780}
    7881
     82#if ENABLE(POINTER_EVENTS)
     83bool operator==(const TouchActionData& a, const TouchActionData& b)
     84{
     85    return a.touchActions == b.touchActions
     86        && a.scrollingNodeID == b.scrollingNodeID
     87        && a.region == b.region;
     88}
     89#endif
     90
    7991} // namespace WebCore
  • trunk/Source/WebCore/platform/EventTrackingRegions.h

    r202408 r240579  
    3131#include <wtf/text/WTFString.h>
    3232
     33#if ENABLE(POINTER_EVENTS)
     34#include "CSSPrimitiveValueMappings.h"
     35#include "ScrollingCoordinatorTypes.h"
     36#include "TouchAction.h"
     37#endif
     38
    3339namespace WebCore {
    3440
     
    3945};
    4046
     47#if ENABLE(POINTER_EVENTS)
     48typedef uint64_t ScrollingNodeID;
     49struct TouchActionData {
     50    OptionSet<TouchAction> touchActions { TouchAction::Auto };
     51    ScrollingNodeID scrollingNodeID { 0 };
     52    Region region;
     53};
     54
     55bool operator==(const TouchActionData&, const TouchActionData&);
     56inline bool operator!=(const TouchActionData& a, const TouchActionData& b) { return !(a == b); }
     57#endif
     58
    4159struct EventTrackingRegions {
    4260    // Region for which events can be dispatched without blocking scrolling.
     
    4664    // The key is the Event Name with an active handler.
    4765    HashMap<String, Region> eventSpecificSynchronousDispatchRegions;
     66
     67#if ENABLE(POINTER_EVENTS)
     68    Vector<TouchActionData> touchActionData;
     69#endif
    4870
    4971    bool isEmpty() const;
  • trunk/Source/WebCore/style/StyleTreeResolver.cpp

    r240037 r240579  
    237237    auto afterUpdate = resolvePseudoStyle(element, update, PseudoId::After);
    238238
     239#if ENABLE(POINTER_EVENTS)
     240    if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled())
     241        m_document.updateTouchActionElements(element, *update.style.get());
     242#endif
     243
    239244    return { WTFMove(update), descendantsToResolve, WTFMove(beforeUpdate), WTFMove(afterUpdate) };
    240245}
  • trunk/Source/WebKit/ChangeLog

    r240578 r240579  
     12019-01-28  Antoine Quint  <graouts@apple.com>
     2
     3        Limit user-agent interactions based on the touch-action property on iOS
     4        https://bugs.webkit.org/show_bug.cgi?id=193447
     5        <rdar://problem/47283874>
     6
     7        Reviewed by Antti Koivisto and Simon Fraser.
     8
     9        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
     10        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
     11        permitted touch actions such to then customize the behavior of the nearest scroll view to pan or zoom only as instructed.
     12
     13        * Shared/WebCoreArgumentCoders.cpp:
     14        (IPC::ArgumentCoder<TouchActionData>::encode):
     15        (IPC::ArgumentCoder<TouchActionData>::decode):
     16        (IPC::ArgumentCoder<EventTrackingRegions>::encode):
     17        (IPC::ArgumentCoder<EventTrackingRegions>::decode):
     18        (IPC::ArgumentCoder<Region>::decode):
     19        * Shared/WebCoreArgumentCoders.h:
     20        * UIProcess/API/Cocoa/WKWebView.mm:
     21        (-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Account for panning constraints set on the content view to prevent deceleration
     22        to pan the view if it ought not.
     23        (-[WKWebView _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Implement an additional
     24        UIScrollView delegation method to apply the panning constraints set on the content view while panning.
     25        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp:
     26        (WebKit::RemoteScrollingCoordinatorProxy::touchActionDataAtPoint const):
     27        (WebKit::RemoteScrollingCoordinatorProxy::touchActionDataForScrollNodeID const):
     28        (WebKit::RemoteScrollingCoordinatorProxy::setTouchDataForTouchIdentifier):
     29        (WebKit::RemoteScrollingCoordinatorProxy::clearTouchDataForTouchIdentifier):
     30        * UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h:
     31        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
     32        * UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
     33        (-[WKScrollingNodeScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): Apply the same logic as in WKWebView.
     34        (-[WKScrollingNodeScrollViewDelegate _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Apply
     35        the same logic as in WKWebView.
     36        (WebKit::ScrollingTreeScrollingNodeDelegateIOS::touchActionData const):
     37        * UIProcess/WebPageProxy.h:
     38        (WebKit::WebPageProxy::isScrollingOrZooming const):
     39        * UIProcess/ios/WKContentViewInteraction.h:
     40        * UIProcess/ios/WKContentViewInteraction.mm:
     41        (-[WKContentView preventsPanningInXAxis]):
     42        (-[WKContentView preventsPanningInYAxis]):
     43        (-[WKContentView cleanupInteraction]):
     44        (-[WKContentView _webTouchEventsRecognized:]):
     45        (-[WKContentView _handleTouchActionsForTouchEvent:]): As we process touches, check whether there are touch actions set for this touch's points' locations. Based
     46        on those touch actions, either setDefaultPrevented on the _touchEventGestureRecognizer if the touch action is "none" or selectively disable panning and zooming.
     47        (-[WKContentView _resetPanningPreventionFlags]):
     48        (-[WKContentView _didEndScrollingOrZooming]):
     49
    1502019-01-28  Antti Koivisto  <antti@apple.com>
    251
  • trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp

    r239888 r240579  
    330330}
    331331
     332#if ENABLE(POINTER_EVENTS)
     333void ArgumentCoder<TouchActionData>::encode(Encoder& encoder, const TouchActionData& touchActionData)
     334{
     335    encoder << touchActionData.touchActions << touchActionData.scrollingNodeID << touchActionData.region;
     336}
     337
     338Optional<TouchActionData> ArgumentCoder<TouchActionData>::decode(Decoder& decoder)
     339{
     340    Optional<OptionSet<TouchAction>> touchActions;
     341    decoder >> touchActions;
     342    if (!touchActions)
     343        return WTF::nullopt;
     344
     345    Optional<ScrollingNodeID> scrollingNodeID;
     346    decoder >> scrollingNodeID;
     347    if (!scrollingNodeID)
     348        return WTF::nullopt;
     349
     350    Optional<Region> region;
     351    decoder >> region;
     352    if (!region)
     353        return WTF::nullopt;
     354
     355    return {{ WTFMove(*touchActions), WTFMove(*scrollingNodeID), WTFMove(*region) }};
     356}
     357#endif
     358
    332359void ArgumentCoder<EventTrackingRegions>::encode(Encoder& encoder, const EventTrackingRegions& eventTrackingRegions)
    333360{
    334361    encoder << eventTrackingRegions.asynchronousDispatchRegion;
    335362    encoder << eventTrackingRegions.eventSpecificSynchronousDispatchRegions;
     363#if ENABLE(POINTER_EVENTS)
     364    encoder << eventTrackingRegions.touchActionData;
     365#endif
    336366}
    337367
     
    344374    if (!decoder.decode(eventSpecificSynchronousDispatchRegions))
    345375        return false;
     376#if ENABLE(POINTER_EVENTS)
     377    Vector<TouchActionData> touchActionData;
     378    if (!decoder.decode(touchActionData))
     379        return false;
     380#endif
    346381    eventTrackingRegions.asynchronousDispatchRegion = WTFMove(asynchronousDispatchRegion);
    347382    eventTrackingRegions.eventSpecificSynchronousDispatchRegions = WTFMove(eventSpecificSynchronousDispatchRegions);
     383#if ENABLE(POINTER_EVENTS)
     384    eventTrackingRegions.touchActionData = WTFMove(touchActionData);
     385#endif
    348386    return true;
    349387}
     
    914952
    915953    return true;
     954}
     955
     956Optional<Region> ArgumentCoder<Region>::decode(Decoder& decoder)
     957{
     958    Region region;
     959    if (!decode(decoder, region))
     960        return WTF::nullopt;
     961
     962    return region;
    916963}
    917964
  • trunk/Source/WebKit/Shared/WebCoreArgumentCoders.h

    r240199 r240579  
    122122struct TextCheckingResult;
    123123struct TextIndicatorData;
     124#if ENABLE(POINTER_EVENTS)
     125struct TouchActionData;
     126#endif
    124127struct ViewportAttributes;
    125128struct WindowFeatures;
     
    200203};
    201204
     205#if ENABLE(POINTER_EVENTS)
     206template<> struct ArgumentCoder<WebCore::TouchActionData> {
     207    static void encode(Encoder&, const WebCore::TouchActionData&);
     208    static Optional<WebCore::TouchActionData> decode(Decoder&);
     209};
     210#endif
     211
    202212template<> struct ArgumentCoder<WebCore::EventTrackingRegions> {
    203213    static void encode(Encoder&, const WebCore::EventTrackingRegions&);
     
    317327    static void encode(Encoder&, const WebCore::Region&);
    318328    static bool decode(Decoder&, WebCore::Region&);
     329    static Optional<WebCore::Region> decode(Decoder&);
    319330};
    320331
  • trunk/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm

    r240490 r240579  
    25842584    if ([scrollView isZooming])
    25852585        *targetContentOffset = [scrollView contentOffset];
     2586#if ENABLE(POINTER_EVENTS)
     2587    else {
     2588        if ([_contentView preventsPanningInXAxis])
     2589            targetContentOffset->x = scrollView.contentOffset.x;
     2590        if ([_contentView preventsPanningInYAxis])
     2591            targetContentOffset->y = scrollView.contentOffset.y;
     2592    }
     2593#endif
    25862594#if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
    25872595    if (WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy()) {
     
    26192627{
    26202628    [self _didFinishScrolling];
     2629}
     2630
     2631- (CGPoint)_scrollView:(UIScrollView *)scrollView adjustedOffsetForOffset:(CGPoint)offset translation:(CGPoint)translation startPoint:(CGPoint)start locationInView:(CGPoint)locationInView horizontalVelocity:(inout double *)hv verticalVelocity:(inout double *)vv
     2632{
     2633    if (![_contentView preventsPanningInXAxis] && ![_contentView preventsPanningInYAxis])
     2634        return offset;
     2635
     2636    CGPoint adjustedContentOffset = CGPointMake(offset.x, offset.y);
     2637    if ([_contentView preventsPanningInXAxis])
     2638        adjustedContentOffset.x = start.x;
     2639    if ([_contentView preventsPanningInYAxis])
     2640        adjustedContentOffset.y = start.y;
     2641
     2642    return adjustedContentOffset;
    26212643}
    26222644
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.cpp

    r240435 r240579  
    207207}
    208208
     209#if ENABLE(POINTER_EVENTS)
     210Optional<TouchActionData> RemoteScrollingCoordinatorProxy::touchActionDataAtPoint(const IntPoint p) const
     211{
     212    return m_scrollingTree->touchActionDataAtPoint(p);
     213}
     214
     215Optional<TouchActionData> RemoteScrollingCoordinatorProxy::touchActionDataForScrollNodeID(ScrollingNodeID scrollingNodeID) const
     216{
     217    for (auto& touchActionData : m_touchActionDataByTouchIdentifier.values()) {
     218        if (touchActionData.scrollingNodeID == scrollingNodeID)
     219            return touchActionData;
     220    }
     221    return WTF::nullopt;
     222}
     223
     224void RemoteScrollingCoordinatorProxy::setTouchDataForTouchIdentifier(TouchActionData touchActionData, unsigned touchIdentifier)
     225{
     226    m_touchActionDataByTouchIdentifier.set(touchIdentifier, touchActionData);
     227}
     228
     229void RemoteScrollingCoordinatorProxy::clearTouchDataForTouchIdentifier(unsigned touchIdentifier)
     230{
     231    m_touchActionDataByTouchIdentifier.remove(touchIdentifier);
     232}
     233
     234#endif
     235
    209236} // namespace WebKit
    210237
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h

    r239689 r240579  
    9999    String scrollingTreeAsText() const;
    100100
     101#if ENABLE(POINTER_EVENTS)
     102    Optional<WebCore::TouchActionData> touchActionDataAtPoint(const WebCore::IntPoint) const;
     103    Optional<WebCore::TouchActionData> touchActionDataForScrollNodeID(WebCore::ScrollingNodeID) const;
     104    void setTouchDataForTouchIdentifier(WebCore::TouchActionData, unsigned);
     105    void clearTouchDataForTouchIdentifier(unsigned);
     106#endif
     107
    101108private:
    102109    void connectStateNodeLayers(WebCore::ScrollingStateTree&, const RemoteLayerTreeHost&);
     
    108115    WebPageProxy& m_webPageProxy;
    109116    RefPtr<RemoteScrollingTree> m_scrollingTree;
     117#if ENABLE(POINTER_EVENTS)
     118    HashMap<unsigned, WebCore::TouchActionData> m_touchActionDataByTouchIdentifier;
     119#endif
    110120    RequestedScrollInfo* m_requestedScrollInfo;
    111121#if ENABLE(CSS_SCROLL_SNAP)
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h

    r237266 r240579  
    6666    void setScrollLayerPosition(const WebCore::FloatPoint&);
    6767    void updateChildNodesAfterScroll(const WebCore::FloatPoint& scrollPosition);
     68#if ENABLE(POINTER_EVENTS)
     69    Optional<TouchActionData> touchActionData() const;
     70#endif
    6871
    6972private:
  • trunk/Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm

    r239548 r240579  
    6868}
    6969
     70- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
     71{
     72#if ENABLE(POINTER_EVENTS)
     73    if (![scrollView isZooming]) {
     74        if (auto touchActionData = _scrollingTreeNodeDelegate->touchActionData()) {
     75            auto touchActions = touchActionData->touchActions;
     76            if (touchActions != WebCore::TouchAction::Auto && touchActions != WebCore::TouchAction::Manipulation) {
     77                bool canPanX = true;
     78                bool canPanY = true;
     79                if (!touchActions.contains(WebCore::TouchAction::PanX)) {
     80                    canPanX = false;
     81                    targetContentOffset->x = scrollView.contentOffset.x;
     82                }
     83                if (!touchActions.contains(WebCore::TouchAction::PanY)) {
     84                    canPanY = false;
     85                    targetContentOffset->y = scrollView.contentOffset.y;
     86                }
     87            }
     88        }
     89    }
     90#endif
     91
    7092#if ENABLE(CSS_SCROLL_SNAP)
    71 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
    72 {
    7393    CGFloat horizontalTarget = targetContentOffset->x;
    7494    CGFloat verticalTarget = targetContentOffset->y;
     
    97117        _scrollingTreeNodeDelegate->currentSnapPointIndicesDidChange(_scrollingTreeNodeDelegate->scrollingNode().currentHorizontalSnapPointIndex(), _scrollingTreeNodeDelegate->scrollingNode().currentVerticalSnapPointIndex());
    98118    }
    99 }
    100 #endif
     119#endif
     120}
    101121
    102122- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)willDecelerate
     
    117137    }
    118138}
     139
     140#if ENABLE(POINTER_EVENTS)
     141- (CGPoint)_scrollView:(UIScrollView *)scrollView adjustedOffsetForOffset:(CGPoint)offset translation:(CGPoint)translation startPoint:(CGPoint)start locationInView:(CGPoint)locationInView horizontalVelocity:(inout double *)hv verticalVelocity:(inout double *)vv
     142{
     143    auto touchActionData = _scrollingTreeNodeDelegate->touchActionData();
     144    if (!touchActionData)
     145        return offset;
     146
     147    auto touchActions = touchActionData->touchActions;
     148    if (touchActions == WebCore::TouchAction::Auto || touchActions == WebCore::TouchAction::Manipulation)
     149        return offset;
     150
     151    CGPoint adjustedContentOffset = CGPointMake(offset.x, offset.y);
     152
     153    if (!touchActions.contains(WebCore::TouchAction::PanX))
     154        adjustedContentOffset.x = start.x;
     155    if (!touchActions.contains(WebCore::TouchAction::PanY))
     156        adjustedContentOffset.y = start.y;
     157
     158    return adjustedContentOffset;
     159}
     160#endif
    119161
    120162@end
     
    288330}
    289331
     332#if ENABLE(POINTER_EVENTS)
     333Optional<TouchActionData> ScrollingTreeScrollingNodeDelegateIOS::touchActionData() const
     334{
     335    return downcast<RemoteScrollingTree>(scrollingTree()).scrollingCoordinatorProxy().touchActionDataForScrollNodeID(scrollingNode().scrollingNodeID());
     336}
     337#endif
     338
    290339} // namespace WebKit
    291340
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r240491 r240579  
    679679    void cancelAutoscroll();
    680680    void hardwareKeyboardAvailabilityChanged();
     681    bool isScrollingOrZooming() const { return m_isScrollingOrZooming; }
    681682#if ENABLE(DATA_INTERACTION)
    682683    void didHandleDragStartRequest(bool started);
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h

    r240491 r240579  
    197197
    198198    BOOL _canSendTouchEventsAsynchronously;
     199#if ENABLE(POINTER_EVENTS)
     200    BOOL _preventsPanningInXAxis;
     201    BOOL _preventsPanningInYAxis;
     202#endif
    199203
    200204    RetainPtr<WKSyntheticClickTapGestureRecognizer> _singleTapGestureRecognizer;
     
    350354@property (nonatomic, readonly) UIWebFormAccessory *formAccessoryView;
    351355@property (nonatomic, readonly) UITextInputAssistantItem *inputAssistantItemForWebView;
     356#if ENABLE(POINTER_EVENTS)
     357@property (nonatomic, readonly) BOOL preventsPanningInXAxis;
     358@property (nonatomic, readonly) BOOL preventsPanningInYAxis;
     359#endif
    352360
    353361#if ENABLE(DATALIST_ELEMENT)
  • trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm

    r240514 r240579  
    130130#endif
    131131
     132#if ENABLE(POINTER_EVENTS)
     133#import "RemoteScrollingCoordinatorProxy.h"
     134#import <WebCore/TouchAction.h>
     135#endif
     136
    132137#if PLATFORM(WATCHOS)
    133138
     
    609614}
    610615
     616#if ENABLE(POINTER_EVENTS)
     617- (BOOL)preventsPanningInXAxis
     618{
     619    return _preventsPanningInXAxis;
     620}
     621
     622- (BOOL)preventsPanningInYAxis
     623{
     624    return _preventsPanningInYAxis;
     625}
     626#endif
     627
    611628- (WKFormInputSession *)_formInputSession
    612629{
     
    855872    _suppressSelectionAssistantReasons = { };
    856873    _isZoomingToRevealFocusedElement = NO;
     874
     875#if ENABLE(POINTER_EVENTS)
     876    [self _resetPanningPreventionFlags];
     877#endif
    857878}
    858879
     
    11221143    nativeWebTouchEvent.setCanPreventNativeGestures(!_canSendTouchEventsAsynchronously || [gestureRecognizer isDefaultPrevented]);
    11231144
     1145#if ENABLE(POINTER_EVENTS)
     1146    [self _handleTouchActionsForTouchEvent:nativeWebTouchEvent];
     1147#endif
     1148
    11241149    if (_canSendTouchEventsAsynchronously)
    11251150        _page->handleTouchEventAsynchronously(nativeWebTouchEvent);
     
    11271152        _page->handleTouchEventSynchronously(nativeWebTouchEvent);
    11281153
    1129     if (nativeWebTouchEvent.allTouchPointsAreReleased())
     1154    if (nativeWebTouchEvent.allTouchPointsAreReleased()) {
    11301155        _canSendTouchEventsAsynchronously = NO;
    1131 #endif
    1132 }
     1156
     1157#if ENABLE(POINTER_EVENTS)
     1158        if (!_page->isScrollingOrZooming())
     1159            [self _resetPanningPreventionFlags];
     1160#endif
     1161    }
     1162#endif
     1163}
     1164
     1165#if ENABLE(POINTER_EVENTS)
     1166- (void)_handleTouchActionsForTouchEvent:(const WebKit::NativeWebTouchEvent&)touchEvent
     1167{
     1168    auto* scrollingCoordinator = _page->scrollingCoordinatorProxy();
     1169    if (!scrollingCoordinator)
     1170        return;
     1171
     1172    for (const auto& touchPoint : touchEvent.touchPoints()) {
     1173        auto phase = touchPoint.phase();
     1174        if (phase == WebKit::WebPlatformTouchPoint::TouchPressed) {
     1175            auto touchActionData = scrollingCoordinator->touchActionDataAtPoint(touchPoint.location());
     1176            if (!touchActionData)
     1177                continue;
     1178            if (touchActionData->touchActions == WebCore::TouchAction::None)
     1179                [_touchEventGestureRecognizer setDefaultPrevented:YES];
     1180            else if (!touchActionData->touchActions.contains(WebCore::TouchAction::Manipulation)) {
     1181                if (auto scrollingNodeID = touchActionData->scrollingNodeID)
     1182                    scrollingCoordinator->setTouchDataForTouchIdentifier(*touchActionData, touchPoint.identifier());
     1183                else {
     1184                    if (!touchActionData->touchActions.contains(WebCore::TouchAction::PinchZoom))
     1185                        _webView.scrollView.pinchGestureRecognizer.enabled = NO;
     1186                    _preventsPanningInXAxis = !touchActionData->touchActions.contains(WebCore::TouchAction::PanX);
     1187                    _preventsPanningInYAxis = !touchActionData->touchActions.contains(WebCore::TouchAction::PanY);
     1188                }
     1189            }
     1190        } else if (phase == WebKit::WebPlatformTouchPoint::TouchReleased || phase == WebKit::WebPlatformTouchPoint::TouchCancelled)
     1191            scrollingCoordinator->clearTouchDataForTouchIdentifier(touchPoint.identifier());
     1192    }
     1193}
     1194
     1195- (void)_resetPanningPreventionFlags
     1196{
     1197    _preventsPanningInXAxis = NO;
     1198    _preventsPanningInYAxis = NO;
     1199}
     1200#endif
    11331201
    11341202- (void)_inspectorNodeSearchRecognized:(UIGestureRecognizer *)gestureRecognizer
     
    21922260    }
    21932261    _page->setIsScrollingOrZooming(false);
     2262
     2263#if ENABLE(POINTER_EVENTS)
     2264    [self _resetPanningPreventionFlags];
     2265#endif
    21942266
    21952267#if PLATFORM(WATCHOS)
Note: See TracChangeset for help on using the changeset viewer.