Dispatch pointercancel events when content is panned or zoomed on iOS
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Feb 2019 21:53:40 +0000 (21:53 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 1 Feb 2019 21:53:40 +0000 (21:53 +0000)
commit438245cd0ec71d19931602fe911e6a05bc9ef5a1
treead8744211a74b938bb14bdc7e1352c416c95b2b1
parent7002c73287a500a9003f081f2f759949dbe6680b
Dispatch pointercancel events when content is panned or zoomed on iOS
https://bugs.webkit.org/show_bug.cgi?id=193962
<rdar://problem/47629134>

Reviewed by Dean Jackson.

Source/WebCore:

Expose two new methods on PointerCaptureController so that, given a pointer id, it can be established whether this pointer
has been cancelled, which is important because a cancelled pointer should no longer dispatch any further pointer events, and
to cancel a pointer.

Tests: pointerevents/ios/touch-action-pointercancel-pan-x.html
       pointerevents/ios/touch-action-pointercancel-pan-y.html
       pointerevents/ios/touch-action-pointercancel-pinch-zoom.html

* WebCore.xcodeproj/project.pbxproj: Make PointerCaptureController.h Private so that it can be imported from WebKit.
* dom/PointerEvent.h: Remove an unnecessary #if ENABLE(POINTER_EVENTS) since the entire file is already contained in one.
Then we add a new create() method that takes an event type, a pointer id and a pointer type (touch vs. pen) that we use
to create pointercancel events in PointerCaptureController::cancelPointer().
* page/Page.cpp:
(WebCore::Page::Page): Pass the Page as a parameter when creating the PointerCaptureController.
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::PointerCaptureController): Add a Page reference to the constructor since we'll need
the page to access its main frame's EventHandler to perform hit testing in case we do not have a capture target override
in cancelPointer().
(WebCore::PointerCaptureController::releasePointerCapture): Drive-by, remove the the implicit parameter since on iOS we
don't need to differentiate. We'll bring this back for the macOS work.
(WebCore::PointerCaptureController::hasCancelledPointerEventForIdentifier): New method we'll use when dispatching pointer
events to identify whether a pointer id has already been cancelled which will allow for _not_ dispatching any further
pointer events for this pointer id.
(WebCore::PointerCaptureController::pointerEventWillBeDispatched): Keep track of the pointer type so we can preserve it
when dispatching pointercancel events for a given pointer id.
(WebCore::PointerCaptureController::cancelPointer): Dispatch a pointercancel for the provided pointer id, using the capture
target override as the event's target, if there is one, and otherwise hit-testing at the provided location to figure out
what the target should be.
* page/PointerCaptureController.h: Switch the target overrides from Element* to RefPtr<Element> to ensure it may not be
deleted while we still need them. Existing code already ensures these get set to nullptr.

Source/WebKit:

When a user-agent-provided interaction, such as panning or zooming on iOS, uses a set of touches, we should dispatch a pointercancel
event for the pointer ids of the touches involved. To facilitate this, we add a new method on WKContentView to cancel all the pointers
matching active touches for a provided UIGestureRecognizer through an async IPC call into the Web process using the new method
PointerCaptureController::cancelPointer().

* Platform/spi/ios/UIKitSPI.h: Add the necessary forward declaration for a necessary UIKit SPI allowing us to get the set of last-seen
UITouches by the identifier generated for the matching WebKit touch.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView scrollViewWillBeginZooming:withView:]): Dispatch touchcancel events for all pointers involved in a pinch gesture on the
top-level UIScrollView.
(-[WKWebView _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]): Dispatch
touchcancel events for all pointers involved in a pan gesture on the top-level UIScrollView. We can infer this by looking at whether the
adjusted content offset, after accounting for the permitted touch actions, is different from the original content offset.
* UIProcess/PageClient.h: Expose a new virtual cancelPointersForGestureRecognizer() method which will allow the iOS implementation to
forward the call to WKContentViewInteraction.
(WebKit::PageClient::cancelPointersForGestureRecognizer):
* UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h: Expose the WebPageProxy such that we may access it to cancel pointers for
a given gesture recognizer from within ScrollingTreeScrollingNodeDelegateIOS.
(WebKit::RemoteScrollingCoordinatorProxy::webPageProxy const):
* UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h:
* UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm:
(-[WKScrollingNodeScrollViewDelegate _scrollView:adjustedOffsetForOffset:translation:startPoint:locationInView:horizontalVelocity:verticalVelocity:]):
Dispatch touchcancel events for all pointers involved in a pan gesture on a nested UIScrollView. We can infer this by looking at
whether the adjusted content offset, after accounting for the permitted touch actions, is different from the original content offset.
(-[WKScrollingNodeScrollViewDelegate scrollViewWillBeginZooming:withView:]): Dispatch touchcancel events for all pointers involved in a
pinch gesture on a nested UIScrollView.
(-[WKScrollingNodeScrollViewDelegate cancelPointersForGestureRecognizer:]):
(WebKit::ScrollingTreeScrollingNodeDelegateIOS::cancelPointersForGestureRecognizer):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::cancelPointer):
* UIProcess/WebPageProxy.h:
* UIProcess/ios/PageClientImplIOS.h:
* UIProcess/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::cancelPointersForGestureRecognizer):
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView cancelPointersForGestureRecognizer:]): Obtain all active UITouch objects for the view and dispatch a pointercancel event,
through the WebPageProxy, for all touches associated with the provided gesture recognizer.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::cancelPointer):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

LayoutTests:

Adding a few tests for "pointercancel" and adding "touch-action: none" on tests that would now be affected by canceling pointers. We also unflake a few tests.

* pointerevents/ios/pointer-events-implicit-capture.html:
* pointerevents/ios/pointer-events-is-primary.html:
* pointerevents/ios/touch-action-pan-x-pan-y.html:
* pointerevents/ios/touch-action-pan-x.html:
* pointerevents/ios/touch-action-pan-y-expected.txt:
* pointerevents/ios/touch-action-pan-y.html:
* pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html:
* pointerevents/ios/touch-action-pointercancel-pan-x-expected.txt: Added.
* pointerevents/ios/touch-action-pointercancel-pan-x.html: Added.
* pointerevents/ios/touch-action-pointercancel-pan-y-expected.txt: Added.
* pointerevents/ios/touch-action-pointercancel-pan-y.html: Added.
* pointerevents/ios/touch-action-pointercancel-pinch-zoom-expected.txt: Added.
* pointerevents/ios/touch-action-pointercancel-pinch-zoom.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
36 files changed:
LayoutTests/ChangeLog
LayoutTests/pointerevents/ios/pointer-events-implicit-capture.html
LayoutTests/pointerevents/ios/pointer-events-is-primary.html
LayoutTests/pointerevents/ios/touch-action-pan-x-pan-y.html
LayoutTests/pointerevents/ios/touch-action-pan-x.html
LayoutTests/pointerevents/ios/touch-action-pan-y-expected.txt
LayoutTests/pointerevents/ios/touch-action-pan-y.html
LayoutTests/pointerevents/ios/touch-action-pinch-zoom-allows-zooming.html
LayoutTests/pointerevents/ios/touch-action-pointercancel-pan-x-expected.txt [new file with mode: 0644]
LayoutTests/pointerevents/ios/touch-action-pointercancel-pan-x.html [new file with mode: 0644]
LayoutTests/pointerevents/ios/touch-action-pointercancel-pan-y-expected.txt [new file with mode: 0644]
LayoutTests/pointerevents/ios/touch-action-pointercancel-pan-y.html [new file with mode: 0644]
LayoutTests/pointerevents/ios/touch-action-pointercancel-pinch-zoom-expected.txt [new file with mode: 0644]
LayoutTests/pointerevents/ios/touch-action-pointercancel-pinch-zoom.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/PointerEvent.h
Source/WebCore/page/Page.cpp
Source/WebCore/page/PointerCaptureController.cpp
Source/WebCore/page/PointerCaptureController.h
Source/WebKit/ChangeLog
Source/WebKit/Platform/spi/ios/UIKitSPI.h
Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit/UIProcess/PageClient.h
Source/WebKit/UIProcess/RemoteLayerTree/RemoteScrollingCoordinatorProxy.h
Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.h
Source/WebKit/UIProcess/RemoteLayerTree/ios/ScrollingTreeScrollingNodeDelegateIOS.mm
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebPageProxy.h
Source/WebKit/UIProcess/ios/PageClientImplIOS.h
Source/WebKit/UIProcess/ios/PageClientImplIOS.mm
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKit/WebProcess/WebPage/WebPage.h
Source/WebKit/WebProcess/WebPage/WebPage.messages.in