2019-01-29 03:15:02 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 Apple Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
|
|
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
|
|
* DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
|
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2019-10-10 00:03:47 +00:00
|
|
|
#include "ExceptionOr.h"
|
2019-02-04 16:22:49 +00:00
|
|
|
#include "PointerID.h"
|
2019-01-29 03:15:02 +00:00
|
|
|
#include <wtf/HashMap.h>
|
|
|
|
|
|
|
|
namespace WebCore {
|
|
|
|
|
2019-10-10 00:03:47 +00:00
|
|
|
class Document;
|
2019-01-29 03:15:02 +00:00
|
|
|
class Element;
|
|
|
|
class EventTarget;
|
2019-10-10 00:03:47 +00:00
|
|
|
class IntPoint;
|
|
|
|
class MouseEvent;
|
|
|
|
class Page;
|
2019-10-10 03:08:32 +00:00
|
|
|
class PlatformTouchEvent;
|
2019-01-29 03:15:02 +00:00
|
|
|
class PointerEvent;
|
2019-10-10 03:08:32 +00:00
|
|
|
class WindowProxy;
|
2019-01-29 03:15:02 +00:00
|
|
|
|
|
|
|
class PointerCaptureController {
|
|
|
|
WTF_MAKE_NONCOPYABLE(PointerCaptureController);
|
|
|
|
WTF_MAKE_FAST_ALLOCATED;
|
|
|
|
public:
|
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.
Canonical link: https://commits.webkit.org/208642@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-02-01 21:53:40 +00:00
|
|
|
explicit PointerCaptureController(Page&);
|
2019-01-29 03:15:02 +00:00
|
|
|
|
2021-02-03 18:41:16 +00:00
|
|
|
Element* pointerCaptureElement(Document*, PointerID) const;
|
2019-02-04 16:22:49 +00:00
|
|
|
ExceptionOr<void> setPointerCapture(Element*, PointerID);
|
|
|
|
ExceptionOr<void> releasePointerCapture(Element*, PointerID);
|
|
|
|
bool hasPointerCapture(Element*, PointerID);
|
2019-05-28 12:33:11 +00:00
|
|
|
void reset();
|
2019-01-29 03:15:02 +00:00
|
|
|
|
|
|
|
void pointerLockWasApplied();
|
2019-04-18 13:31:17 +00:00
|
|
|
void elementWasRemoved(Element&);
|
2019-01-29 03:15:02 +00:00
|
|
|
|
2020-12-09 17:03:08 +00:00
|
|
|
RefPtr<PointerEvent> pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType);
|
[Pointer Events] Add support for chorded button interactions
https://bugs.webkit.org/show_bug.cgi?id=198462
Reviewed by Dean Jackson.
LayoutTests/imported/w3c:
Mark the progression for web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html which
proves the correct implementation of the chorded button interactions section of the Pointer Events spec. To do that,
we also had to make use of the "button" parameter used in WPT tests action sequences, which allows the test to indicate
which mouse button is pressed. Finally, there is now a change in the pointerevent_pointermove_on_chorded_mouse_button.html
results, another source change is required to get this test to fully pass.
* web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* web-platform-tests/pointerevents/pointerevent_pointermove_on_chorded_mouse_button-expected.txt:
* web-platform-tests/resources/testdriver-vendor.js:
(dispatchMouseActions):
Source/WebCore:
Pointer events differ from mouse events in that pressing a button on a mouse and then pressing a second button
would yield two "mousedown" events but a single "pointerdown" event, for the first time we're transitioning from
a state where no button is pressed at all, and then a "pointermove" event to indicate an additional button has been
pressed. This is what the Pointer Events specification calls "chorded button interactions".
See https://w3c.github.io/pointerevents/#chorded-button-interactions for the full details.
To implement this, we no longer directly call PointerEvent::create() from Element::dispatchMouseEvent() but instead
call the new PointerCaptureController::pointerEventForMouseEvent() which implements the required logic to determine
for "mousedown" and "mouseup" mouse events, if we're transitioning from or to a state where no button is pressed at
all.
While that basic change is pretty small, a wider change was required to report the correct value for a PointerEvents'
"button" property which should return "-1" when there is no change in pressed button state compared to any previous
pointer event.
Up until now, MouseEvent.button was an "unsigned short", as specified up to and including DOM Level 2 Events. But the
UI Events spec says that property is a "short", and PointerEvent is the only interface where a "-1" value is used. This
required some changes throughout our codebase since we used a "-1" value to specify that no button was pressed when dealing
with NSEvent input and going through PlatformMouseEvent and eventually MouseEvent. So now we change the various NoButton
enum values to be "-2" and use that value, which is not going to be used for any mouse button, as the value reflected as
"0" through MouseEvent.button, as specified by UI Events.
Furthermore, we identified another issue: MouseEvent.buttons would always return 0 in DRT and WKTR. We rely upon that
value in PointerCaptureController::pointerEventForMouseEvent() and so we had to make that work for the relevant WPT test,
web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html, to pass and show a correct implementation
of chorded button interactions. The details of the work required for this is in Tools/ChangeLog.
* dom/Element.cpp:
(WebCore::Element::dispatchMouseEvent):
* dom/MouseEvent.cpp:
(WebCore::MouseEvent::create):
(WebCore::MouseEvent::MouseEvent):
(WebCore::MouseEvent::initMouseEvent):
(WebCore::MouseEvent::initMouseEventQuirk):
* dom/MouseEvent.h:
(WebCore::MouseEvent::button const):
* dom/MouseEvent.idl:
* dom/MouseEventInit.h:
* dom/MouseEventInit.idl:
* dom/PointerEvent.cpp:
(WebCore::PointerEvent::create):
(WebCore::PointerEvent::PointerEvent):
* dom/PointerEvent.h:
* loader/NavigationAction.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::pointerEventForMouseEvent):
* page/PointerCaptureController.h:
* platform/PlatformMouseEvent.h:
Source/WebKit:
Update to use -2 instead of -1 for NoButton.
* Shared/API/c/WKEvent.h:
* Shared/WebEvent.h:
Source/WebKitLegacy/mac:
Update -[DOMMouseEvent button] to be a "short" and update the noButton value from -1 to -2.
* DOM/DOMMouseEvent.h:
* DOM/DOMMouseEvent.mm:
(-[DOMMouseEvent button]):
* WebView/WebPDFView.mm:
(-[WebPDFView PDFViewWillClickOnLink:withURL:]):
Tools:
Until now, MouseEvent.buttons would always return 0 when used within DRT and WKTR as [NSEvent pressedMouseButtons], used
by PlatformMouseEventBuilder to set the m_buttons value eventually used to set MouseEvent.buttons, not account for the
NSEvent created through the eventSender JS object in tests. To fix this, we now track the pressed mouse buttons within
DRT and WKTR as mouseDown() and mouseUp() are called, and swizzle [NSEvent pressedMouseButtons] to return that value.
In the case of DRT, one test would fail when swizzling this method in the case where the target view for the event would
be the DRTMockScroller, a subclass of NSScroller. So we only swizzle when the target view is *not* an NSScroller or a
subclass.
Finally, we change the NoMouseButton enum value from -1 to -2 to adjust to MouseEvent.button now being a "short".
* DumpRenderTree/mac/EventSendingController.mm:
(swizzledEventPressedMouseButtons):
(-[EventSendingController mouseDown:withModifiers:]):
(-[EventSendingController mouseUp:withModifiers:]):
(-[EventSendingController mouseMoveToX:Y:]):
* TestWebKitAPI/Tests/mac/IsNavigationActionTrusted.mm:
* WebKitTestRunner/EventSenderProxy.h:
(WTR::EventSenderProxy::mouseButtonsCurrentlyDown const):
* WebKitTestRunner/mac/EventSenderProxy.mm:
(WTR::swizzledEventPressedMouseButtons):
(WTR::EventSenderProxy::mouseDown):
(WTR::EventSenderProxy::mouseUp):
(WTR::EventSenderProxy::mouseMoveTo):
LayoutTests:
Update some tests and their expectations due to MouseEvent.buttons now returning the correct value in DRT and WKTR
and MouseEvent.button now being a "short" instead of an "unsigned short".
* fast/events/constructors/mouse-event-constructor-expected.txt:
* fast/events/constructors/mouse-event-constructor.html: Update the test to test the boundary values for "short" instead
of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.
* fast/events/constructors/wheel-event-constructor-expected.txt:
* fast/events/constructors/wheel-event-constructor.html: Update the test to test the boundary values for "short" instead
of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.
* fast/events/fire-mousedown-while-pressing-mouse-button.html: Rewrite this test to always use MouseEvent.buttons and
adjust the bitmask expectations which were way off.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
This test fails differently in WK1 and WK2 and will be addressed in a future patch.
Canonical link: https://commits.webkit.org/212560@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@246103 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-06-05 08:41:30 +00:00
|
|
|
|
2019-02-18 17:52:34 +00:00
|
|
|
#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
|
2019-04-24 18:00:11 +00:00
|
|
|
void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&);
|
2019-02-18 17:52:34 +00:00
|
|
|
#endif
|
|
|
|
|
[iOS] Compatibility mouse events aren't prevented by calling preventDefault() on pointerdown
https://bugs.webkit.org/show_bug.cgi?id=198124
<rdar://problem/50410863>
Reviewed by Tim Horton.
LayoutTests/imported/w3c:
We add basic support to run a test that wasn't specifically designed for a touch-based interaction such that the test
at imported/w3c/web-platform-tests/pointerevents/pointerevent_suppress_compat_events_on_click.html may run on iOS. The
trick here is to add a pause after a touch ends to avoid the likelihood or two tap gestures triggering a double tap.
* web-platform-tests/resources/testdriver-vendor.js:
Source/WebCore:
This fix builds atop the one made for wkb.ug/198072 which fixes this bug on macOS alone.
In order to correctly prevent "compatibility" mouse events from being dispatched when the initial "pointerdown" event had preventDefault()
called while handled, we need to pass the PointerID for the touch that triggered a tap gesture in the UI process down in the Web process
and into the resulting PlatformMouseEvent. This will allow upon dispatch of a PlatformMouseEvent to call into PointerCaptureController
to identify if the dispatch of mouse events is allowed for the event's PointerID.
To support this, some refactoring was required. The PointerID header is now under platform/ such that PlatformMouseEvent may safely use it.
Additionally, PointerEvent::defaultMousePointerIdentifier() is now a global mousePointerID defined in PointerID.h.
Finally, PointerCaptureController::touchEndedOrWasCancelledForIdentifier() has been renamed to PointerCaptureController::touchWithIdentifierWasRemoved() and
has WEBCORE_EXPORT such that it may be called from WebKit as the indication that a pointer is no longer active will now be initiated in WebKit
on the UI process side.
Testing is covered by the pre-existing imported/w3c/web-platform-tests/pointerevents/pointerevent_suppress_compat_events_on_click.html
which will now run on iOS through a change to WebKitAdditions.
* Headers.cmake:
* WebCore.xcodeproj/project.pbxproj:
* dom/Element.cpp:
(WebCore::Element::dispatchMouseEvent): When dealing with a mouse event on iOS, check whether the mouse event's PointerID allows for compatibility
mouse events to be dispatched using PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(). The "click" event is not a compatibility
mouse event.
* dom/PointerEvent.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::PointerCaptureController):
(WebCore::PointerCaptureController::touchWithIdentifierWasRemoved):
(WebCore::PointerCaptureController::touchEndedOrWasCancelledForIdentifier): Deleted.
* page/PointerCaptureController.h:
* platform/PlatformMouseEvent.h:
(WebCore::PlatformMouseEvent::PlatformMouseEvent):
(WebCore::PlatformMouseEvent::pointerId const):
* platform/PointerID.h: Renamed from Source/WebCore/dom/PointerID.h.
(WebCore::mousePointerID):
Source/WebKit:
In order to correctly prevent "compatibility" mouse events from being dispatched when the initial "pointerdown" event had preventDefault()
called while handled, we need to pass the PointerID for the touch that triggered a tap gesture in the UI process down in the Web process
and into the resulting PlatformMouseEvent.
This means we need to identify the touch identifier, which is the same as the PointerID used for Pointer Events, in the single tap gesture
recognizer, an instance of WKSyntheticTapGestureRecognizer. To do this, we subclass the -[UIResponder touchesEnded:withEvent:] method and
track the touch identifier as the lastActiveTouchIdentifier, a new public property of WKSyntheticTapGestureRecognizer. To allow for this,
we need the support of the content view's UIWebTouchEventsGestureRecognizer which is exposed to the WKSyntheticTapGestureRecognizer as its
supportingWebTouchEventsGestureRecognizer property. This lastActiveTouchIdentifier property is cleared as the gesture recognizer is reset.
This allows the content view to pass the PointerID down to the Web process starting from -[WKContentView _singleTapRecognized:], going
through WebPageProxy::commitPotentialTap() and eventually WebPage::completeSyntheticClick().
While we used to tell the PointerCaptureController that a PointerID was no longer active when a given touch ended or was canceled (in
WebKitAdditions code), we can no longer do this as the dispatch of a synthetic tap is performed asynchronously and will happen past the
dispatch of "pointerup" and "pointercancel" Pointer Events. To clear inactive PointerIDs from the PointerCaptureController, we add a new
touchWithIdentifierWasRemoved() method on the WebPage and its proxy. When the WKSyntheticTapGestureRecognizer resets and -[WKContentView _singleTapDidReset:]
is called, we call that method which allows for only active PointerIDs to be tracked by the PointerCaptureController.
* UIProcess/WebPageProxy.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setupInteraction]):
(-[WKContentView cleanupInteraction]):
(-[WKContentView _singleTapDidReset:]):
(-[WKContentView _singleTapRecognized:]):
* UIProcess/ios/WKSyntheticTapGestureRecognizer.h:
* UIProcess/ios/WKSyntheticTapGestureRecognizer.m:
(-[WKSyntheticTapGestureRecognizer reset]):
(-[WKSyntheticTapGestureRecognizer touchesEnded:withEvent:]):
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::touchWithIdentifierWasRemoved):
(WebKit::WebPageProxy::commitPotentialTap):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::dispatchSyntheticMouseMove):
(WebKit::WebPage::handleSyntheticClick):
(WebKit::WebPage::completePendingSyntheticClickForContentChangeObserver):
(WebKit::WebPage::completeSyntheticClick):
(WebKit::WebPage::commitPotentialTap):
(WebKit::WebPage::touchWithIdentifierWasRemoved):
LayoutTests:
We're adding an iOS-specific expectation since this test prints out the pointer type detected while it runs, which is "touch"
on iOS and "mouse" in the expectation that already exists for macOS.
* platform/ios/imported/w3c/web-platform-tests/pointerevents/pointerevent_suppress_compat_events_on_click-expected.txt: Added.
Canonical link: https://commits.webkit.org/212200@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@245639 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-05-22 19:58:15 +00:00
|
|
|
WEBCORE_EXPORT void touchWithIdentifierWasRemoved(PointerID);
|
2021-02-03 18:41:16 +00:00
|
|
|
bool hasCancelledPointerEventForIdentifier(PointerID) const;
|
|
|
|
bool preventsCompatibilityMouseEventsForIdentifier(PointerID) const;
|
2019-02-18 17:52:34 +00:00
|
|
|
void dispatchEvent(PointerEvent&, EventTarget*);
|
2019-02-04 16:22:49 +00:00
|
|
|
WEBCORE_EXPORT void cancelPointer(PointerID, const IntPoint&);
|
[Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
https://bugs.webkit.org/show_bug.cgi?id=198999
<rdar://problem/51979477>
Reviewed by Dean Jackson.
LayoutTests/imported/w3c:
Mark the progressions in 3 WPT tests.
* web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
* web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
Source/WebCore:
Up until now, we would not account for pointer capture (see https://w3c.github.io/pointerevents/#pointer-capture) when dispatching
mouse boundary events (mouseover, mouseout, mouseenter, mouseleave) and their counterpart pointer events. We would also not account
for it when updating :hover styles.
Now, when pointer capture changes for an element, we call setCapturingMouseEventsElement() on the EventHandler such that the element
that would naturally hit-test is overridden by the pointer capture element when identifying which target to use for the dispatch of
boundary mouse events. Additionally, when calling Document::prepareMouseEvent(), we also use the pointer capture element to
pass down to Document::updateHoverActiveState() such that :hover styles are applied to the correct element.
* dom/Document.cpp:
(WebCore::Document::prepareMouseEvent): When a new event is going to be dispatched, we must run the Process Pending Capture Element
steps as mandated by the Pointer Events spec. Calling this will dispatch the appropriate pointer capture change events and also
required boundary events since EventHandler::setCapturingMouseEventsElement() calls into EventHandler::updateMouseEventTargetNode().
Since this may update the capturing mouse events element, we ensure that we call updateHoverActiveState() with a flag that indicates that.
Finally, we use the capturing mouse events element instead of the hit-testing element to pass to updateHoverActiveState() to ensure
that is has :hover styles applied.
(WebCore::Document::updateHoverActiveState): Account for the new CaptureChange flag to force the invalidation of the :hover and :active
elements chain at all times when the capturing mouse events element changed.
* dom/Document.h:
* dom/PointerEvent.h: Update PointerEvent::createForPointerCapture() to take specific parameters rather than a single PointerEvent to
set the pointerId, isPrimary and pointerType properties of the generated event. This is required to call processPendingPointerCapture()
outside of PointerEvent dispatch logic since we now call it from Document::prepareMouseEvent() where we haven't yet generated such an
event.
* page/EventHandler.cpp:
(WebCore::EventHandler::pointerCaptureElementDidChange): When a new pointer capture element is set, call updateMouseEventTargetNode()
to ensure that boundary events are fired to indicate the pointer capture state change.
(WebCore::EventHandler::prepareMouseEvent): Keep track of the last PlatformMouseEvent used to prepare a mouse event so that we can use
it when setCapturingMouseEventsElement() is called.
* page/EventHandler.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::pointerCaptureElement): Since Document::prepareMouseEvent() needs to know the current pointer capture
element, add a new public method that indicates the pointer capture element if that element is contained in the provided document. We need
to provide the document since PointerCaptureController is owned by the Page and may manage several documents.
(WebCore::PointerCaptureController::dispatchEvent): Only run the Process Pending Capture Element steps when dealing with a touch or pen
event since those steps are already ran for mouse events in Document::prepareMouseEvent(). Additionally, since the element target is already
set to be the pointer capture element with the changes made to processPendingPointerCapture(), and because on iOS pointer capture is always
active, we can remove the code that would retarget the event to the pointer capture element.
(WebCore::PointerCaptureController::pointerEventWasDispatched):
(WebCore::PointerCaptureController::cancelPointer):
(WebCore::PointerCaptureController::processPendingPointerCapture): We now call into EventHandler::setCapturingMouseEventsElement() when the
capture target element changes. We must be careful to call this method prior to dispatching the "gotpointercapture" event and after dispatching
the "lostpointercapture" event so that boundary events are fired at the right time.
* page/PointerCaptureController.h:
LayoutTests:
Update some WK1-specific expectations.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
Canonical link: https://commits.webkit.org/213414@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247148 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-05 10:25:06 +00:00
|
|
|
void processPendingPointerCapture(PointerID);
|
2019-01-29 03:15:02 +00:00
|
|
|
|
|
|
|
private:
|
2021-07-08 20:45:38 +00:00
|
|
|
struct CapturingData : public RefCounted<CapturingData> {
|
|
|
|
static Ref<CapturingData> create(const String& pointerType)
|
|
|
|
{
|
|
|
|
return adoptRef(*new CapturingData(pointerType));
|
|
|
|
}
|
|
|
|
|
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.
Canonical link: https://commits.webkit.org/208642@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-02-01 21:53:40 +00:00
|
|
|
RefPtr<Element> pendingTargetOverride;
|
|
|
|
RefPtr<Element> targetOverride;
|
2019-09-21 15:34:43 +00:00
|
|
|
#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
|
|
|
|
RefPtr<Element> previousTarget;
|
|
|
|
#endif
|
2021-02-03 18:41:16 +00:00
|
|
|
bool hasAnyElement() const {
|
|
|
|
return pendingTargetOverride || targetOverride
|
|
|
|
#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
|
|
|
|
|| previousTarget
|
|
|
|
#endif
|
|
|
|
;
|
|
|
|
}
|
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.
Canonical link: https://commits.webkit.org/208642@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-02-01 21:53:40 +00:00
|
|
|
String pointerType;
|
2021-05-13 23:20:07 +00:00
|
|
|
enum class State : uint8_t {
|
|
|
|
Ready,
|
|
|
|
Finished,
|
|
|
|
Cancelled,
|
|
|
|
};
|
|
|
|
State state { State::Ready };
|
2019-05-07 18:43:27 +00:00
|
|
|
bool isPrimary { false };
|
2019-05-21 17:50:37 +00:00
|
|
|
bool preventsCompatibilityMouseEvents { false };
|
2019-05-23 18:13:56 +00:00
|
|
|
bool pointerIsPressed { false };
|
[Pointer Events] Add support for chorded button interactions
https://bugs.webkit.org/show_bug.cgi?id=198462
Reviewed by Dean Jackson.
LayoutTests/imported/w3c:
Mark the progression for web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html which
proves the correct implementation of the chorded button interactions section of the Pointer Events spec. To do that,
we also had to make use of the "button" parameter used in WPT tests action sequences, which allows the test to indicate
which mouse button is pressed. Finally, there is now a change in the pointerevent_pointermove_on_chorded_mouse_button.html
results, another source change is required to get this test to fully pass.
* web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* web-platform-tests/pointerevents/pointerevent_pointermove_on_chorded_mouse_button-expected.txt:
* web-platform-tests/resources/testdriver-vendor.js:
(dispatchMouseActions):
Source/WebCore:
Pointer events differ from mouse events in that pressing a button on a mouse and then pressing a second button
would yield two "mousedown" events but a single "pointerdown" event, for the first time we're transitioning from
a state where no button is pressed at all, and then a "pointermove" event to indicate an additional button has been
pressed. This is what the Pointer Events specification calls "chorded button interactions".
See https://w3c.github.io/pointerevents/#chorded-button-interactions for the full details.
To implement this, we no longer directly call PointerEvent::create() from Element::dispatchMouseEvent() but instead
call the new PointerCaptureController::pointerEventForMouseEvent() which implements the required logic to determine
for "mousedown" and "mouseup" mouse events, if we're transitioning from or to a state where no button is pressed at
all.
While that basic change is pretty small, a wider change was required to report the correct value for a PointerEvents'
"button" property which should return "-1" when there is no change in pressed button state compared to any previous
pointer event.
Up until now, MouseEvent.button was an "unsigned short", as specified up to and including DOM Level 2 Events. But the
UI Events spec says that property is a "short", and PointerEvent is the only interface where a "-1" value is used. This
required some changes throughout our codebase since we used a "-1" value to specify that no button was pressed when dealing
with NSEvent input and going through PlatformMouseEvent and eventually MouseEvent. So now we change the various NoButton
enum values to be "-2" and use that value, which is not going to be used for any mouse button, as the value reflected as
"0" through MouseEvent.button, as specified by UI Events.
Furthermore, we identified another issue: MouseEvent.buttons would always return 0 in DRT and WKTR. We rely upon that
value in PointerCaptureController::pointerEventForMouseEvent() and so we had to make that work for the relevant WPT test,
web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover.html, to pass and show a correct implementation
of chorded button interactions. The details of the work required for this is in Tools/ChangeLog.
* dom/Element.cpp:
(WebCore::Element::dispatchMouseEvent):
* dom/MouseEvent.cpp:
(WebCore::MouseEvent::create):
(WebCore::MouseEvent::MouseEvent):
(WebCore::MouseEvent::initMouseEvent):
(WebCore::MouseEvent::initMouseEventQuirk):
* dom/MouseEvent.h:
(WebCore::MouseEvent::button const):
* dom/MouseEvent.idl:
* dom/MouseEventInit.h:
* dom/MouseEventInit.idl:
* dom/PointerEvent.cpp:
(WebCore::PointerEvent::create):
(WebCore::PointerEvent::PointerEvent):
* dom/PointerEvent.h:
* loader/NavigationAction.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::pointerEventForMouseEvent):
* page/PointerCaptureController.h:
* platform/PlatformMouseEvent.h:
Source/WebKit:
Update to use -2 instead of -1 for NoButton.
* Shared/API/c/WKEvent.h:
* Shared/WebEvent.h:
Source/WebKitLegacy/mac:
Update -[DOMMouseEvent button] to be a "short" and update the noButton value from -1 to -2.
* DOM/DOMMouseEvent.h:
* DOM/DOMMouseEvent.mm:
(-[DOMMouseEvent button]):
* WebView/WebPDFView.mm:
(-[WebPDFView PDFViewWillClickOnLink:withURL:]):
Tools:
Until now, MouseEvent.buttons would always return 0 when used within DRT and WKTR as [NSEvent pressedMouseButtons], used
by PlatformMouseEventBuilder to set the m_buttons value eventually used to set MouseEvent.buttons, not account for the
NSEvent created through the eventSender JS object in tests. To fix this, we now track the pressed mouse buttons within
DRT and WKTR as mouseDown() and mouseUp() are called, and swizzle [NSEvent pressedMouseButtons] to return that value.
In the case of DRT, one test would fail when swizzling this method in the case where the target view for the event would
be the DRTMockScroller, a subclass of NSScroller. So we only swizzle when the target view is *not* an NSScroller or a
subclass.
Finally, we change the NoMouseButton enum value from -1 to -2 to adjust to MouseEvent.button now being a "short".
* DumpRenderTree/mac/EventSendingController.mm:
(swizzledEventPressedMouseButtons):
(-[EventSendingController mouseDown:withModifiers:]):
(-[EventSendingController mouseUp:withModifiers:]):
(-[EventSendingController mouseMoveToX:Y:]):
* TestWebKitAPI/Tests/mac/IsNavigationActionTrusted.mm:
* WebKitTestRunner/EventSenderProxy.h:
(WTR::EventSenderProxy::mouseButtonsCurrentlyDown const):
* WebKitTestRunner/mac/EventSenderProxy.mm:
(WTR::swizzledEventPressedMouseButtons):
(WTR::EventSenderProxy::mouseDown):
(WTR::EventSenderProxy::mouseUp):
(WTR::EventSenderProxy::mouseMoveTo):
LayoutTests:
Update some tests and their expectations due to MouseEvent.buttons now returning the correct value in DRT and WKTR
and MouseEvent.button now being a "short" instead of an "unsigned short".
* fast/events/constructors/mouse-event-constructor-expected.txt:
* fast/events/constructors/mouse-event-constructor.html: Update the test to test the boundary values for "short" instead
of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.
* fast/events/constructors/wheel-event-constructor-expected.txt:
* fast/events/constructors/wheel-event-constructor.html: Update the test to test the boundary values for "short" instead
of "unsigned short" as well as the new "magic" value of -2 for no button, which ends up being reported as 0.
* fast/events/fire-mousedown-while-pressing-mouse-button.html: Rewrite this test to always use MouseEvent.buttons and
adjust the bitmask expectations which were way off.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* platform/mac-highsierra/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* platform/mac-highsierra-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
This test fails differently in WK1 and WK2 and will be addressed in a future patch.
Canonical link: https://commits.webkit.org/212560@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@246103 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-06-05 08:41:30 +00:00
|
|
|
short previousMouseButton { -1 };
|
2021-07-08 20:45:38 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
CapturingData(const String& pointerType)
|
|
|
|
: pointerType(pointerType)
|
|
|
|
{ }
|
2019-01-29 03:15:02 +00:00
|
|
|
};
|
|
|
|
|
2021-07-08 20:45:38 +00:00
|
|
|
Ref<CapturingData> ensureCapturingDataForPointerEvent(const PointerEvent&);
|
2019-02-18 17:52:34 +00:00
|
|
|
void pointerEventWillBeDispatched(const PointerEvent&, EventTarget*);
|
|
|
|
void pointerEventWasDispatched(const PointerEvent&);
|
2021-07-08 20:45:38 +00:00
|
|
|
|
2021-02-03 18:41:16 +00:00
|
|
|
void updateHaveAnyCapturingElement();
|
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.
Canonical link: https://commits.webkit.org/208642@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@240875 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-02-01 21:53:40 +00:00
|
|
|
|
|
|
|
Page& m_page;
|
2019-03-13 18:14:21 +00:00
|
|
|
// While PointerID is defined as int32_t, we use int64_t here so that we may use a value outside of the int32_t range to have safe
|
|
|
|
// empty and removed values, allowing any int32_t to be provided through the API for lookup in this hashmap.
|
2021-07-08 20:45:38 +00:00
|
|
|
using PointerIdToCapturingDataMap = HashMap<int64_t, Ref<CapturingData>, WTF::IntHash<int64_t>, WTF::SignedWithZeroKeyHashTraits<int64_t>>;
|
2019-03-13 18:14:21 +00:00
|
|
|
PointerIdToCapturingDataMap m_activePointerIdsToCapturingData;
|
[Pointer Events] Respect pointer capture when dispatching mouse boundary events and updating :hover
https://bugs.webkit.org/show_bug.cgi?id=198999
<rdar://problem/51979477>
Reviewed by Dean Jackson.
LayoutTests/imported/w3c:
Mark the progressions in 3 WPT tests.
* web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
* web-platform-tests/pointerevents/pointerevent_mouse_capture_change_hover-expected.txt:
* web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
Source/WebCore:
Up until now, we would not account for pointer capture (see https://w3c.github.io/pointerevents/#pointer-capture) when dispatching
mouse boundary events (mouseover, mouseout, mouseenter, mouseleave) and their counterpart pointer events. We would also not account
for it when updating :hover styles.
Now, when pointer capture changes for an element, we call setCapturingMouseEventsElement() on the EventHandler such that the element
that would naturally hit-test is overridden by the pointer capture element when identifying which target to use for the dispatch of
boundary mouse events. Additionally, when calling Document::prepareMouseEvent(), we also use the pointer capture element to
pass down to Document::updateHoverActiveState() such that :hover styles are applied to the correct element.
* dom/Document.cpp:
(WebCore::Document::prepareMouseEvent): When a new event is going to be dispatched, we must run the Process Pending Capture Element
steps as mandated by the Pointer Events spec. Calling this will dispatch the appropriate pointer capture change events and also
required boundary events since EventHandler::setCapturingMouseEventsElement() calls into EventHandler::updateMouseEventTargetNode().
Since this may update the capturing mouse events element, we ensure that we call updateHoverActiveState() with a flag that indicates that.
Finally, we use the capturing mouse events element instead of the hit-testing element to pass to updateHoverActiveState() to ensure
that is has :hover styles applied.
(WebCore::Document::updateHoverActiveState): Account for the new CaptureChange flag to force the invalidation of the :hover and :active
elements chain at all times when the capturing mouse events element changed.
* dom/Document.h:
* dom/PointerEvent.h: Update PointerEvent::createForPointerCapture() to take specific parameters rather than a single PointerEvent to
set the pointerId, isPrimary and pointerType properties of the generated event. This is required to call processPendingPointerCapture()
outside of PointerEvent dispatch logic since we now call it from Document::prepareMouseEvent() where we haven't yet generated such an
event.
* page/EventHandler.cpp:
(WebCore::EventHandler::pointerCaptureElementDidChange): When a new pointer capture element is set, call updateMouseEventTargetNode()
to ensure that boundary events are fired to indicate the pointer capture state change.
(WebCore::EventHandler::prepareMouseEvent): Keep track of the last PlatformMouseEvent used to prepare a mouse event so that we can use
it when setCapturingMouseEventsElement() is called.
* page/EventHandler.h:
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::pointerCaptureElement): Since Document::prepareMouseEvent() needs to know the current pointer capture
element, add a new public method that indicates the pointer capture element if that element is contained in the provided document. We need
to provide the document since PointerCaptureController is owned by the Page and may manage several documents.
(WebCore::PointerCaptureController::dispatchEvent): Only run the Process Pending Capture Element steps when dealing with a touch or pen
event since those steps are already ran for mouse events in Document::prepareMouseEvent(). Additionally, since the element target is already
set to be the pointer capture element with the changes made to processPendingPointerCapture(), and because on iOS pointer capture is always
active, we can remove the code that would retarget the event to the pointer capture element.
(WebCore::PointerCaptureController::pointerEventWasDispatched):
(WebCore::PointerCaptureController::cancelPointer):
(WebCore::PointerCaptureController::processPendingPointerCapture): We now call into EventHandler::setCapturingMouseEventsElement() when the
capture target element changes. We must be careful to call this method prior to dispatching the "gotpointercapture" event and after dispatching
the "lostpointercapture" event so that boundary events are fired at the right time.
* page/PointerCaptureController.h:
LayoutTests:
Update some WK1-specific expectations.
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_boundary_events_at_implicit_release_hoverable_pointers-expected.txt:
* platform/mac-wk1/imported/w3c/web-platform-tests/pointerevents/pointerevent_setpointercapture_relatedtarget-expected.txt:
Canonical link: https://commits.webkit.org/213414@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247148 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-05 10:25:06 +00:00
|
|
|
bool m_processingPendingPointerCapture { false };
|
2021-02-03 18:41:16 +00:00
|
|
|
bool m_haveAnyCapturingElement { false };
|
2019-01-29 03:15:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace WebCore
|