macCatalyst: Cursor should send mouse events, not touch events
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Oct 2019 05:48:14 +0000 (05:48 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Oct 2019 05:48:14 +0000 (05:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=203175
<rdar://problem/56321134>

Reviewed by Simon Fraser.

Source/WebCore:

* dom/Element.cpp:
(WebCore::shouldIgnoreMouseEvent):
(WebCore::Element::dispatchMouseEvent):
* page/PointerCaptureController.cpp:
(WebCore::PointerCaptureController::reset):
Share more code between platforms that support touch events and platforms that don't;
we want to be able to dispatch pointer events that originate from mouse events
in macCatalyst despite touch events being enabled (by virtue of being iOS WebKit),
so un-ifdef that code.

Source/WebKit:

* Platform/spi/ios/UIKitSPI.h:
* Shared/NativeWebMouseEvent.h:
* Shared/ios/NativeWebMouseEventIOS.mm:
(WebKit::NativeWebMouseEvent::NativeWebMouseEvent):
Add a NativeWebMouseEvent constructor that doesn't actually wrap a native event,
for creating totally-synthetic events.

* UIProcess/ios/WKMouseGestureRecognizer.h: Added.
* UIProcess/ios/WKMouseGestureRecognizer.mm: Added.
(webEventModifiersForUIKeyModifierFlags):
(-[WKMouseGestureRecognizer initWithTarget:action:]):
(-[WKMouseGestureRecognizer setView:]):
(-[WKMouseGestureRecognizer lastMouseEvent]):
(-[WKMouseGestureRecognizer lastMouseLocation]):
(-[WKMouseGestureRecognizer mouseTouch]):
(-[WKMouseGestureRecognizer _wantsHoverEvents]):
(-[WKMouseGestureRecognizer reset]):
(-[WKMouseGestureRecognizer _shouldReceiveTouch:forEvent:recognizerView:]):
(-[WKMouseGestureRecognizer _shouldReceivePress:]):
(-[WKMouseGestureRecognizer createMouseEventWithType:]):
(-[WKMouseGestureRecognizer touchesBegan:withEvent:]):
(-[WKMouseGestureRecognizer touchesMoved:withEvent:]):
(-[WKMouseGestureRecognizer touchesEnded:withEvent:]):
(-[WKMouseGestureRecognizer touchesCancelled:withEvent:]):
(-[WKMouseGestureRecognizer _hoverEntered:withEvent:]):
(-[WKMouseGestureRecognizer _hoverMoved:withEvent:]):
(-[WKMouseGestureRecognizer _hoverExited:withEvent:]):
(-[WKMouseGestureRecognizer _hoverCancelled:withEvent:]):
(-[WKMouseGestureRecognizer locationInView:]):
(-[WKMouseGestureRecognizer canPreventGestureRecognizer:]):
(-[WKMouseGestureRecognizer canBePreventedByGestureRecognizer:]):
Instead of just using UIHoverGestureRecognizer, introduce a new gesture
recognizer that does what it did, but also supports cases where the button
is pressed (so, mousedown and mouseup instead of just mousemove),
and synthesizes mouse events for all state transitions. These events
should look roughly identical to what a non-macCatalyst app would get
in AppKit's mouseUp/mouseDown/mouseMoved NSResponder methods.

* SourcesCocoa.txt:
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setupInteraction]):
(-[WKContentView cleanupInteraction]):
(-[WKContentView _removeDefaultGestureRecognizers]):
(-[WKContentView _addDefaultGestureRecognizers]):
(-[WKContentView gestureRecognizer:shouldReceiveTouch:]):
(-[WKContentView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):
(-[WKContentView _showShareSheet:inRect:completionHandler:]):
(-[WKContentView _mouseGestureRecognizerChanged:]):
(webEventFlagsForUIKeyModifierFlags): Deleted.
(-[WKContentView _hoverGestureRecognizerChanged:]): Deleted.
* WebKit.xcodeproj/project.pbxproj:
Make use of WKMouseGestureRecognizer to plumb the synthesized events directly
to the macOS-style "handleMouseEvent" codepath, instead of going through
the touch events path (and then subsequently generating synthetic clicks).
Also, ensure that other gesture recognizers ignore the mouse "touch" entirely
by returning NO in shouldReceiveTouch.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@251320 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/Element.cpp
Source/WebCore/page/PointerCaptureController.cpp
Source/WebKit/ChangeLog
Source/WebKit/Platform/spi/ios/UIKitSPI.h
Source/WebKit/Shared/NativeWebMouseEvent.h
Source/WebKit/Shared/ios/NativeWebMouseEventIOS.mm
Source/WebKit/SourcesCocoa.txt
Source/WebKit/UIProcess/ios/WKContentViewInteraction.h
Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm
Source/WebKit/UIProcess/ios/WKMouseGestureRecognizer.h [new file with mode: 0644]
Source/WebKit/UIProcess/ios/WKMouseGestureRecognizer.mm [new file with mode: 0644]
Source/WebKit/WebKit.xcodeproj/project.pbxproj

index c4d1b64..5ff25ab 100644 (file)
@@ -1,3 +1,21 @@
+2019-10-18  Tim Horton  <timothy_horton@apple.com>
+
+        macCatalyst: Cursor should send mouse events, not touch events
+        https://bugs.webkit.org/show_bug.cgi?id=203175
+        <rdar://problem/56321134>
+
+        Reviewed by Simon Fraser.
+
+        * dom/Element.cpp:
+        (WebCore::shouldIgnoreMouseEvent):
+        (WebCore::Element::dispatchMouseEvent):
+        * page/PointerCaptureController.cpp:
+        (WebCore::PointerCaptureController::reset):
+        Share more code between platforms that support touch events and platforms that don't;
+        we want to be able to dispatch pointer events that originate from mouse events
+        in macCatalyst despite touch events being enabled (by virtue of being iOS WebKit),
+        so un-ifdef that code.
+
 2019-10-18  Simon Fraser  <simon.fraser@apple.com>
 
         Make it possible to query scrollbar pseudo-style without having a scrollbar
index 965c40e..d1b47ea 100644 (file)
@@ -303,7 +303,7 @@ static bool isForceEvent(const PlatformMouseEvent& platformEvent)
     return platformEvent.type() == PlatformEvent::MouseForceChanged || platformEvent.type() == PlatformEvent::MouseForceDown || platformEvent.type() == PlatformEvent::MouseForceUp;
 }
 
-#if ENABLE(POINTER_EVENTS) && !ENABLE(TOUCH_EVENTS)
+#if ENABLE(POINTER_EVENTS)
 static bool isCompatibilityMouseEvent(const MouseEvent& mouseEvent)
 {
     // https://www.w3.org/TR/pointerevents/#compatibility-mapping-with-mouse-events
@@ -312,44 +312,53 @@ static bool isCompatibilityMouseEvent(const MouseEvent& mouseEvent)
 }
 #endif
 
-bool Element::dispatchMouseEvent(const PlatformMouseEvent& platformEvent, const AtomString& eventType, int detail, Element* relatedTarget)
+static bool shouldIgnoreMouseEvent(Element& element, const MouseEvent& mouseEvent, const PlatformMouseEvent& platformEvent, bool& didNotSwallowEvent)
 {
-    if (isDisabledFormControl())
-        return false;
-
-    if (isForceEvent(platformEvent) && !document().hasListenerTypeForEventType(platformEvent.type()))
-        return false;
-
-    Ref<MouseEvent> mouseEvent = MouseEvent::create(eventType, document().windowProxy(), platformEvent, detail, relatedTarget);
-
-    if (mouseEvent->type().isEmpty())
-        return true; // Shouldn't happen.
-
-    bool didNotSwallowEvent = true;
-
 #if ENABLE(POINTER_EVENTS)
     if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled()) {
-        if (auto* page = document().page()) {
+        if (auto* page = element.document().page()) {
             auto& pointerCaptureController = page->pointerCaptureController();
 #if ENABLE(TOUCH_EVENTS)
-            if (mouseEvent->type() != eventNames().clickEvent && pointerCaptureController.preventsCompatibilityMouseEventsForIdentifier(platformEvent.pointerId()))
-                return false;
+            if (platformEvent.pointerId() != mousePointerID && mouseEvent.type() != eventNames().clickEvent && pointerCaptureController.preventsCompatibilityMouseEventsForIdentifier(platformEvent.pointerId()))
+                return true;
 #else
+            UNUSED_PARAM(platformEvent);
+#endif
             if (auto pointerEvent = pointerCaptureController.pointerEventForMouseEvent(mouseEvent)) {
-                pointerCaptureController.dispatchEvent(*pointerEvent, this);
+                pointerCaptureController.dispatchEvent(*pointerEvent, &element);
                 if (isCompatibilityMouseEvent(mouseEvent) && pointerCaptureController.preventsCompatibilityMouseEventsForIdentifier(pointerEvent->pointerId()))
-                    return false;
+                    return true;
                 if (pointerEvent->defaultPrevented() || pointerEvent->defaultHandled()) {
                     didNotSwallowEvent = false;
                     if (pointerEvent->type() == eventNames().pointerdownEvent)
-                        return false;
+                        return true;
                 }
             }
-#endif
         }
     }
 #endif
 
+    return false;
+}
+
+bool Element::dispatchMouseEvent(const PlatformMouseEvent& platformEvent, const AtomString& eventType, int detail, Element* relatedTarget)
+{
+    if (isDisabledFormControl())
+        return false;
+
+    if (isForceEvent(platformEvent) && !document().hasListenerTypeForEventType(platformEvent.type()))
+        return false;
+
+    Ref<MouseEvent> mouseEvent = MouseEvent::create(eventType, document().windowProxy(), platformEvent, detail, relatedTarget);
+
+    if (mouseEvent->type().isEmpty())
+        return true; // Shouldn't happen.
+
+    bool didNotSwallowEvent = true;
+
+    if (shouldIgnoreMouseEvent(*this, mouseEvent.get(), platformEvent, didNotSwallowEvent))
+        return false;
+
     ASSERT(!mouseEvent->target() || mouseEvent->target() != relatedTarget);
     dispatchEvent(mouseEvent);
     if (mouseEvent->defaultPrevented() || mouseEvent->defaultHandled())
index fda80d5..16f432a 100644 (file)
@@ -159,11 +159,10 @@ void PointerCaptureController::elementWasRemoved(Element& element)
 void PointerCaptureController::reset()
 {
     m_activePointerIdsToCapturingData.clear();
-#if !ENABLE(TOUCH_EVENTS)
+
     CapturingData capturingData;
     capturingData.pointerType = PointerEvent::mousePointerType();
     m_activePointerIdsToCapturingData.add(mousePointerID, capturingData);
-#endif
 }
 
 void PointerCaptureController::touchWithIdentifierWasRemoved(PointerID pointerId)
index 707dc4f..a32db8e 100644 (file)
@@ -1,3 +1,69 @@
+2019-10-18  Tim Horton  <timothy_horton@apple.com>
+
+        macCatalyst: Cursor should send mouse events, not touch events
+        https://bugs.webkit.org/show_bug.cgi?id=203175
+        <rdar://problem/56321134>
+
+        Reviewed by Simon Fraser.
+
+        * Platform/spi/ios/UIKitSPI.h:
+        * Shared/NativeWebMouseEvent.h:
+        * Shared/ios/NativeWebMouseEventIOS.mm:
+        (WebKit::NativeWebMouseEvent::NativeWebMouseEvent):
+        Add a NativeWebMouseEvent constructor that doesn't actually wrap a native event,
+        for creating totally-synthetic events.
+
+        * UIProcess/ios/WKMouseGestureRecognizer.h: Added.
+        * UIProcess/ios/WKMouseGestureRecognizer.mm: Added.
+        (webEventModifiersForUIKeyModifierFlags):
+        (-[WKMouseGestureRecognizer initWithTarget:action:]):
+        (-[WKMouseGestureRecognizer setView:]):
+        (-[WKMouseGestureRecognizer lastMouseEvent]):
+        (-[WKMouseGestureRecognizer lastMouseLocation]):
+        (-[WKMouseGestureRecognizer mouseTouch]):
+        (-[WKMouseGestureRecognizer _wantsHoverEvents]):
+        (-[WKMouseGestureRecognizer reset]):
+        (-[WKMouseGestureRecognizer _shouldReceiveTouch:forEvent:recognizerView:]):
+        (-[WKMouseGestureRecognizer _shouldReceivePress:]):
+        (-[WKMouseGestureRecognizer createMouseEventWithType:]):
+        (-[WKMouseGestureRecognizer touchesBegan:withEvent:]):
+        (-[WKMouseGestureRecognizer touchesMoved:withEvent:]):
+        (-[WKMouseGestureRecognizer touchesEnded:withEvent:]):
+        (-[WKMouseGestureRecognizer touchesCancelled:withEvent:]):
+        (-[WKMouseGestureRecognizer _hoverEntered:withEvent:]):
+        (-[WKMouseGestureRecognizer _hoverMoved:withEvent:]):
+        (-[WKMouseGestureRecognizer _hoverExited:withEvent:]):
+        (-[WKMouseGestureRecognizer _hoverCancelled:withEvent:]):
+        (-[WKMouseGestureRecognizer locationInView:]):
+        (-[WKMouseGestureRecognizer canPreventGestureRecognizer:]):
+        (-[WKMouseGestureRecognizer canBePreventedByGestureRecognizer:]):
+        Instead of just using UIHoverGestureRecognizer, introduce a new gesture
+        recognizer that does what it did, but also supports cases where the button
+        is pressed (so, mousedown and mouseup instead of just mousemove),
+        and synthesizes mouse events for all state transitions. These events
+        should look roughly identical to what a non-macCatalyst app would get
+        in AppKit's mouseUp/mouseDown/mouseMoved NSResponder methods.
+
+        * SourcesCocoa.txt:
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView setupInteraction]):
+        (-[WKContentView cleanupInteraction]):
+        (-[WKContentView _removeDefaultGestureRecognizers]):
+        (-[WKContentView _addDefaultGestureRecognizers]):
+        (-[WKContentView gestureRecognizer:shouldReceiveTouch:]):
+        (-[WKContentView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):
+        (-[WKContentView _showShareSheet:inRect:completionHandler:]):
+        (-[WKContentView _mouseGestureRecognizerChanged:]):
+        (webEventFlagsForUIKeyModifierFlags): Deleted.
+        (-[WKContentView _hoverGestureRecognizerChanged:]): Deleted.
+        * WebKit.xcodeproj/project.pbxproj:
+        Make use of WKMouseGestureRecognizer to plumb the synthesized events directly
+        to the macOS-style "handleMouseEvent" codepath, instead of going through
+        the touch events path (and then subsequently generating synthetic clicks).
+        Also, ensure that other gesture recognizers ignore the mouse "touch" entirely
+        by returning NO in shouldReceiveTouch.
+
 2019-10-18  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebAuthn] Warn users when no credentials are found
index 3eaf460..f086d4d 100644 (file)
@@ -1116,6 +1116,20 @@ typedef NS_OPTIONS(NSInteger, UIWKDocumentRequestFlags) {
 - (void)_updateSafeAreaInsets;
 @end
 
+@interface UIGestureRecognizer (IPI)
+- (BOOL)_paused;
+@property (nonatomic) UIView *view;
+@property (nonatomic, assign, getter=_acceptsFailureRequirements, setter=_setAcceptsFailureRequiments:) BOOL _acceptsFailureRequirements;
+@end
+
+@interface UIHoverEvent : UIEvent
+- (void)setNeedsHitTestReset;
+@end
+
+@interface UIApplication (IPI)
+- (UIHoverEvent *)_hoverEventForWindow:(UIWindow *)window;
+@end
+
 @interface UIScrollView (IPI)
 - (CGFloat)_rubberBandOffsetForOffset:(CGFloat)newOffset maxOffset:(CGFloat)maxOffset minOffset:(CGFloat)minOffset range:(CGFloat)range outside:(BOOL *)outside;
 - (void)_adjustForAutomaticKeyboardInfo:(NSDictionary *)info animated:(BOOL)animated lastAdjustment:(CGFloat*)lastAdjustment;
index bbddd94..ba7f93c 100644 (file)
@@ -63,6 +63,7 @@ public:
     NativeWebMouseEvent(GdkEvent*, int);
 #elif PLATFORM(IOS_FAMILY)
     NativeWebMouseEvent(::WebEvent *);
+    NativeWebMouseEvent(Type, Button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet<Modifier>, WallTime timestamp, double force);
 #elif USE(LIBWPE)
     NativeWebMouseEvent(struct wpe_input_pointer_event*, float deviceScaleFactor);
 #elif PLATFORM(WIN)
index b9bcf1b..7db00f1 100644 (file)
@@ -38,6 +38,11 @@ NativeWebMouseEvent::NativeWebMouseEvent(::WebEvent *event)
 {
 }
 
+NativeWebMouseEvent::NativeWebMouseEvent(Type type, Button button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet<Modifier> modifiers, WallTime timestamp, double force)
+    : WebMouseEvent(type, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp, force)
+{
+}
+
 } // namespace WebKit
 
 #endif // PLATFORM(IOS_FAMILY)
index 327ea4e..257e828 100644 (file)
@@ -426,6 +426,7 @@ UIProcess/ios/WKGeolocationProviderIOSObjCSecurityOrigin.mm
 UIProcess/ios/WKHighlightLongPressGestureRecognizer.mm
 UIProcess/ios/WKInspectorNodeSearchGestureRecognizer.mm
 UIProcess/ios/WKKeyboardScrollingAnimator.mm
+UIProcess/ios/WKMouseGestureRecognizer.mm
 UIProcess/ios/WKPasswordView.mm
 UIProcess/ios/WKPDFPageNumberIndicator.mm
 UIProcess/ios/WKPDFView.mm
index 10fe619..1a784a6 100644 (file)
@@ -99,7 +99,6 @@ struct WebAutocorrectionContext;
 
 @class _UILookupGestureRecognizer;
 @class _UIHighlightView;
-@class UIHoverGestureRecognizer;
 @class UITargetedPreview;
 @class WebEvent;
 @class WKActionSheetAssistant;
@@ -109,6 +108,7 @@ struct WebAutocorrectionContext;
 @class WKFormInputControl;
 @class WKFormInputSession;
 @class WKHighlightLongPressGestureRecognizer;
+@class WKMouseGestureRecognizer;
 @class WKInspectorNodeSearchGestureRecognizer;
 
 typedef void (^UIWKAutocorrectionCompletionHandler)(UIWKAutocorrectionRects *rectsForInput);
@@ -236,8 +236,7 @@ struct WKAutoCorrectionData {
 #endif
 
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-    RetainPtr<UIHoverGestureRecognizer> _hoverGestureRecognizer;
-    CGPoint _lastHoverLocation;
+    RetainPtr<WKMouseGestureRecognizer> _mouseGestureRecognizer;
 #endif
 
     RetainPtr<UIWKTextInteractionAssistant> _textSelectionAssistant;
index 76ce342..bda6cca 100644 (file)
@@ -55,6 +55,7 @@
 #import "WKHighlightLongPressGestureRecognizer.h"
 #import "WKImagePreviewViewController.h"
 #import "WKInspectorNodeSearchGestureRecognizer.h"
+#import "WKMouseGestureRecognizer.h"
 #import "WKNSURLExtras.h"
 #import "WKPreviewActionItemIdentifiers.h"
 #import "WKPreviewActionItemInternal.h"
 #import <UIKit/_UILookupGestureRecognizer.h>
 #endif
 
-#if HAVE(HOVER_GESTURE_RECOGNIZER)
-#import "NativeWebMouseEvent.h"
-#import <UIKit/UIHoverGestureRecognizer.h>
-#endif
-
 #if ENABLE(INPUT_TYPE_COLOR)
 #import "WKFormColorControl.h"
 #endif
@@ -745,9 +741,9 @@ static inline bool hasFocusedElement(WebKit::FocusedElementInformation focusedEl
     [self addGestureRecognizer:_touchEventGestureRecognizer.get()];
 
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-    _hoverGestureRecognizer = adoptNS([[UIHoverGestureRecognizer alloc] initWithTarget:self action:@selector(_hoverGestureRecognizerChanged:)]);
-    [_hoverGestureRecognizer setDelegate:self];
-    [self addGestureRecognizer:_hoverGestureRecognizer.get()];
+    _mouseGestureRecognizer = adoptNS([[WKMouseGestureRecognizer alloc] initWithTarget:self action:@selector(_mouseGestureRecognizerChanged:)]);
+    [_mouseGestureRecognizer setDelegate:self];
+    [self addGestureRecognizer:_mouseGestureRecognizer.get()];
 #endif
 
 #if PLATFORM(MACCATALYST)    
@@ -897,8 +893,8 @@ static inline bool hasFocusedElement(WebKit::FocusedElementInformation focusedEl
     [self removeGestureRecognizer:_touchEventGestureRecognizer.get()];
 
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-    [_hoverGestureRecognizer setDelegate:nil];
-    [self removeGestureRecognizer:_hoverGestureRecognizer.get()];
+    [_mouseGestureRecognizer setDelegate:nil];
+    [self removeGestureRecognizer:_mouseGestureRecognizer.get()];
 #endif
 
 #if PLATFORM(MACCATALYST)    
@@ -1014,7 +1010,7 @@ static inline bool hasFocusedElement(WebKit::FocusedElementInformation focusedEl
     [self removeGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
     [self removeGestureRecognizer:_stylusSingleTapGestureRecognizer.get()];
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-    [self removeGestureRecognizer:_hoverGestureRecognizer.get()];
+    [self removeGestureRecognizer:_mouseGestureRecognizer.get()];
 #endif
 #if PLATFORM(MACCATALYST)
     [self removeGestureRecognizer:_lookupGestureRecognizer.get()];
@@ -1040,7 +1036,7 @@ static inline bool hasFocusedElement(WebKit::FocusedElementInformation focusedEl
     [self addGestureRecognizer:_twoFingerSingleTapGestureRecognizer.get()];
     [self addGestureRecognizer:_stylusSingleTapGestureRecognizer.get()];
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-    [self addGestureRecognizer:_hoverGestureRecognizer.get()];
+    [self addGestureRecognizer:_mouseGestureRecognizer.get()];
 #endif
 #if PLATFORM(MACCATALYST)
     [self addGestureRecognizer:_lookupGestureRecognizer.get()];
@@ -1449,17 +1445,24 @@ inline static UIKeyModifierFlags gestureRecognizerModifierFlags(UIGestureRecogni
 
 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
 {
-    if (gestureRecognizer != _touchActionLeftSwipeGestureRecognizer && gestureRecognizer != _touchActionRightSwipeGestureRecognizer && gestureRecognizer != _touchActionUpSwipeGestureRecognizer && gestureRecognizer != _touchActionDownSwipeGestureRecognizer)
-        return true;
+#if HAVE(HOVER_GESTURE_RECOGNIZER)
+    if (gestureRecognizer != _mouseGestureRecognizer && [_mouseGestureRecognizer mouseTouch] == touch)
+        return NO;
+#endif
 
-    // We update the enabled state of the various swipe gesture recognizers such that if we have a unidirectional touch-action
-    // specified (only pan-x or only pan-y) we enable the two recognizers in the opposite axis to prevent scrolling from starting
-    // if the initial gesture is such a swipe. Since the recognizers are specified to use a single finger for recognition, we don't
-    // need to worry about the case where there may be more than a single touch for a given UIScrollView.
-    auto touchActions = WebKit::touchActionsForPoint(self, WebCore::roundedIntPoint([touch locationInView:self]));
-    if (gestureRecognizer == _touchActionLeftSwipeGestureRecognizer || gestureRecognizer == _touchActionRightSwipeGestureRecognizer)
-        return touchActions == WebCore::TouchAction::PanY;
-    return touchActions == WebCore::TouchAction::PanX;
+    if (gestureRecognizer == _touchActionLeftSwipeGestureRecognizer || gestureRecognizer == _touchActionRightSwipeGestureRecognizer || gestureRecognizer == _touchActionUpSwipeGestureRecognizer || gestureRecognizer == _touchActionDownSwipeGestureRecognizer) {
+
+        // We update the enabled state of the various swipe gesture recognizers such that if we have a unidirectional touch-action
+        // specified (only pan-x or only pan-y) we enable the two recognizers in the opposite axis to prevent scrolling from starting
+        // if the initial gesture is such a swipe. Since the recognizers are specified to use a single finger for recognition, we don't
+        // need to worry about the case where there may be more than a single touch for a given UIScrollView.
+        auto touchActions = WebKit::touchActionsForPoint(self, WebCore::roundedIntPoint([touch locationInView:self]));
+        if (gestureRecognizer == _touchActionLeftSwipeGestureRecognizer || gestureRecognizer == _touchActionRightSwipeGestureRecognizer)
+            return touchActions == WebCore::TouchAction::PanY;
+        return touchActions == WebCore::TouchAction::PanX;
+    }
+
+    return YES;
 }
 
 #pragma mark - WKTouchActionGestureRecognizerDelegate implementation
@@ -1956,7 +1959,7 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
         return YES;
 
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-    if ([gestureRecognizer isKindOfClass:[UIHoverGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UIHoverGestureRecognizer class]])
+    if ([gestureRecognizer isKindOfClass:[WKMouseGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[WKMouseGestureRecognizer class]])
         return YES;
 #endif
 
@@ -6352,8 +6355,10 @@ static BOOL allPasteboardItemOriginsMatchOrigin(UIPasteboard *pasteboard, const
 
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
     if (!rect) {
-        auto hoverLocationInWebView = [self convertPoint:_lastHoverLocation toView:_webView];
-        rect = WebCore::FloatRect(hoverLocationInWebView.x, hoverLocationInWebView.y, 1, 1);
+        if (auto lastMouseLocation = [_mouseGestureRecognizer lastMouseLocation]) {
+            auto hoverLocationInWebView = [self convertPoint:*lastMouseLocation toView:_webView];
+            rect = WebCore::FloatRect(hoverLocationInWebView.x, hoverLocationInWebView.y, 1, 1);
+        }
     }
 #endif
     
@@ -7750,46 +7755,13 @@ static Vector<WebCore::IntSize> sizesOfPlaceholderElementsToInsertWhenDroppingIt
 #endif
 
 #if HAVE(HOVER_GESTURE_RECOGNIZER)
-static WebEventFlags webEventFlagsForUIKeyModifierFlags(UIKeyModifierFlags flags)
-{
-    WebEventFlags eventFlags = 0;
-    if (flags & UIKeyModifierShift)
-        eventFlags |= WebEventFlagMaskLeftShiftKey;
-    if (flags & UIKeyModifierControl)
-        eventFlags |= WebEventFlagMaskLeftControlKey;
-    if (flags & UIKeyModifierAlternate)
-        eventFlags |= WebEventFlagMaskLeftOptionKey;
-    if (flags & UIKeyModifierCommand)
-        eventFlags |= WebEventFlagMaskLeftCommandKey;
-    if (flags & UIKeyModifierAlphaShift)
-        eventFlags |= WebEventFlagMaskLeftCapsLockKey;
-    return eventFlags;
-}
-
-- (void)_hoverGestureRecognizerChanged:(UIGestureRecognizer *)gestureRecognizer
+- (void)_mouseGestureRecognizerChanged:(WKMouseGestureRecognizer *)gestureRecognizer
 {
     if (!_page->hasRunningProcess())
         return;
 
-    // Make a timestamp that matches UITouch and UIEvent.
-    CFTimeInterval timestamp = GSCurrentEventTimestamp() / 1000000000.0;
-
-    CGPoint point;
-    switch (gestureRecognizer.state) {
-    case UIGestureRecognizerStateBegan:
-    case UIGestureRecognizerStateChanged:
-        point = [gestureRecognizer locationInView:self];
-        _lastHoverLocation = point;
-        break;
-    case UIGestureRecognizerStateEnded:
-    case UIGestureRecognizerStateCancelled:
-    default:
-        point = CGPointMake(-1, -1);
-        break;
-    }
-
-    auto event = adoptNS([[::WebEvent alloc] initWithMouseEventType:WebEventMouseMoved timeStamp:timestamp location:point modifiers:webEventFlagsForUIKeyModifierFlags(gestureRecognizerModifierFlags(gestureRecognizer))]);
-    _page->handleMouseEvent(WebKit::NativeWebMouseEvent(event.get()));
+    if (auto event = gestureRecognizer.lastMouseEvent)
+        _page->handleMouseEvent(*event);
 }
 #endif
 
diff --git a/Source/WebKit/UIProcess/ios/WKMouseGestureRecognizer.h b/Source/WebKit/UIProcess/ios/WKMouseGestureRecognizer.h
new file mode 100644 (file)
index 0000000..5628cf3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+* 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.
+*/
+
+#if HAVE(HOVER_GESTURE_RECOGNIZER)
+
+#import "NativeWebMouseEvent.h"
+
+@interface WKMouseGestureRecognizer : UIGestureRecognizer
+
+- (WTF::Optional<CGPoint>)lastMouseLocation;
+- (WebKit::NativeWebMouseEvent *)lastMouseEvent;
+
+- (UITouch *)mouseTouch;
+
+@end
+
+#endif
diff --git a/Source/WebKit/UIProcess/ios/WKMouseGestureRecognizer.mm b/Source/WebKit/UIProcess/ios/WKMouseGestureRecognizer.mm
new file mode 100644 (file)
index 0000000..28d8b51
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+* 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.
+*/
+
+#import "config.h"
+#import "WKMouseGestureRecognizer.h"
+
+#if HAVE(HOVER_GESTURE_RECOGNIZER)
+
+#import "NativeWebMouseEvent.h"
+#import "UIKitSPI.h"
+#import <wtf/Optional.h>
+
+static OptionSet<WebKit::WebEvent::Modifier> webEventModifiersForUIKeyModifierFlags(UIKeyModifierFlags flags)
+{
+    OptionSet<WebKit::WebEvent::Modifier> modifiers;
+    if (flags & UIKeyModifierShift)
+        modifiers.add(WebKit::WebEvent::Modifier::ShiftKey);
+    if (flags & UIKeyModifierControl)
+        modifiers.add(WebKit::WebEvent::Modifier::ControlKey);
+    if (flags & UIKeyModifierAlternate)
+        modifiers.add(WebKit::WebEvent::Modifier::AltKey);
+    if (flags & UIKeyModifierCommand)
+        modifiers.add(WebKit::WebEvent::Modifier::MetaKey);
+    if (flags & UIKeyModifierAlphaShift)
+        modifiers.add(WebKit::WebEvent::Modifier::CapsLockKey);
+    return modifiers;
+}
+
+@implementation WKMouseGestureRecognizer {
+    RetainPtr<UIHoverEvent> _currentHoverEvent;
+    RetainPtr<UITouch> _currentTouch;
+
+    BOOL _touching;
+
+    std::unique_ptr<WebKit::NativeWebMouseEvent> _lastEvent;
+    Optional<CGPoint> _lastLocation;
+}
+
+- (instancetype)initWithTarget:(id)target action:(SEL)action
+{
+    self = [super initWithTarget:target action:action];
+    if (!self)
+        return nil;
+
+    [self _setAcceptsFailureRequiments:NO];
+
+    return self;
+}
+
+- (void)setView:(UIView *)view
+{
+    if (view == self.view)
+        return;
+
+    [super setView:view];
+
+    if (view._window) {
+        UIHoverEvent *hoverEvent = [UIApp _hoverEventForWindow:view._window];
+        [hoverEvent setNeedsHitTestReset];
+    }
+}
+
+- (WebKit::NativeWebMouseEvent *)lastMouseEvent
+{
+    return _lastEvent.get();
+}
+
+- (WTF::Optional<CGPoint>)lastMouseLocation
+{
+    return _lastLocation;
+}
+
+- (UITouch *)mouseTouch
+{
+    return _currentTouch.get();
+}
+
+- (BOOL)_wantsHoverEvents
+{
+    return YES;
+}
+
+- (void)reset
+{
+    [super reset];
+    _currentHoverEvent = nil;
+    _currentTouch = nil;
+}
+
+- (BOOL)_shouldReceiveTouch:(UITouch *)touch forEvent:(UIEvent *)event recognizerView:(UIView *)recognizerView
+{
+    return touch == _currentTouch;
+}
+
+- (BOOL)_shouldReceivePress:(UIPress *)press
+{
+    return NO;
+}
+
+- (std::unique_ptr<WebKit::NativeWebMouseEvent>)createMouseEventWithType:(WebKit::WebEvent::Type)type
+{
+    auto modifiers = webEventModifiersForUIKeyModifierFlags(self.modifierFlags);
+    BOOL hasControlModifier = modifiers.contains(WebKit::WebEvent::Modifier::ControlKey);
+
+    auto button = [&] {
+        if (!_touching || type == WebKit::WebEvent::Type::MouseUp)
+            return WebKit::WebMouseEvent::NoButton;
+        if (hasControlModifier)
+            return WebKit::WebMouseEvent::RightButton;
+        return WebKit::WebMouseEvent::LeftButton;
+    }();
+
+    auto buttons = [&] {
+        if (!_touching)
+            return 0;
+        if (hasControlModifier)
+            return 2;
+        return 1;
+    }();
+
+    WebCore::IntPoint point { [self locationInView:self.view] };
+
+    auto timestamp = WallTime::fromRawSeconds(Seconds::fromNanoseconds(GSCurrentEventTimestamp()).seconds());
+
+    return WTF::makeUnique<WebKit::NativeWebMouseEvent>(type, button, buttons, point, point, 0, 0, 0, [_currentTouch tapCount], modifiers, timestamp, 0);
+}
+
+- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    _touching = YES;
+
+    _lastEvent = [self createMouseEventWithType:WebKit::WebEvent::MouseDown];
+    _lastLocation = [self locationInView:self.view];
+
+    self.state = UIGestureRecognizerStateChanged;
+}
+
+- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    _lastEvent = [self createMouseEventWithType:WebKit::WebEvent::MouseMove];
+    _lastLocation = [self locationInView:self.view];
+
+    self.state = UIGestureRecognizerStateChanged;
+}
+
+- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    _touching = NO;
+
+    _lastEvent = [self createMouseEventWithType:WebKit::WebEvent::MouseUp];
+    _lastLocation = [self locationInView:self.view];
+
+    self.state = UIGestureRecognizerStateChanged;
+}
+
+- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    [self touchesEnded:touches withEvent:event];
+}
+
+- (void)_hoverEntered:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    _lastEvent = [self createMouseEventWithType:WebKit::WebEvent::MouseMove];
+
+    if (_currentHoverEvent == nil && touches.count == 1 && [event isKindOfClass:NSClassFromString(@"UIHoverEvent")]) {
+        _currentHoverEvent = (UIHoverEvent *)event;
+        _currentTouch = touches.anyObject;
+        _lastLocation = [self locationInView:self.view];
+        self.state = UIGestureRecognizerStateBegan;
+    }
+
+    [super _hoverEntered:touches withEvent:event];
+}
+
+- (void)_hoverMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    if (_touching) {
+        _lastEvent = nullptr;
+        return;
+    }
+
+    _lastEvent = [self createMouseEventWithType:WebKit::WebEvent::MouseMove];
+    _lastLocation = [self locationInView:self.view];
+
+    if (_currentHoverEvent == event && [touches containsObject:_currentTouch.get()])
+        self.state = UIGestureRecognizerStateChanged;
+
+    [super _hoverMoved:touches withEvent:event];
+}
+
+- (void)_hoverExited:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    _lastEvent = [self createMouseEventWithType:WebKit::WebEvent::MouseMove];
+    _lastLocation = [self locationInView:self.view];
+
+    if (_currentHoverEvent == event) {
+        _currentHoverEvent = nil;
+        _currentTouch = nil;
+        self.state = UIGestureRecognizerStateEnded;
+    }
+
+    [super _hoverExited:touches withEvent:event];
+}
+
+- (void)_hoverCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
+{
+    [self _hoverExited:touches withEvent:event];
+    [super _hoverCancelled:touches withEvent:event];
+}
+
+- (CGPoint)locationInView:(UIView *)view
+{
+    if (!_currentTouch)
+        return CGPointMake(-1, -1);
+    return [_currentTouch locationInView:view];
+}
+
+- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
+{
+    return NO;
+}
+
+- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
+{
+    return NO;
+}
+
+@end
+
+#endif
index ca1bf54..140179e 100644 (file)
                2DACE64E18ADBFF000E4CA76 /* _WKThumbnailViewInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DACE64D18ADBFF000E4CA76 /* _WKThumbnailViewInternal.h */; };
                2DAF06D618BD1A470081CEB1 /* SmartMagnificationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DAF06D418BD1A470081CEB1 /* SmartMagnificationController.h */; };
                2DB7667121B5E48A0045DDB1 /* AccessibilitySupportSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DB7667021B5E48A0045DDB1 /* AccessibilitySupportSPI.h */; };
+               2DB94299234E7A7F00E776AD /* WKMouseGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DB94297234E7A7F00E776AD /* WKMouseGestureRecognizer.h */; };
                2DC18FAD218910490025A88D /* WKDrawingView.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DC18FAB218910480025A88D /* WKDrawingView.h */; };
                2DC18FB0218912640025A88D /* PencilKitSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DC18FAF218912640025A88D /* PencilKitSPI.h */; };
                2DC18FB3218A6E9E0025A88D /* RemoteLayerTreeViews.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DC18FB1218A6E9E0025A88D /* RemoteLayerTreeViews.h */; };
                2DAF06D818BD23BA0081CEB1 /* SmartMagnificationController.messages.in */ = {isa = PBXFileReference; lastKnownFileType = text; name = SmartMagnificationController.messages.in; path = ios/SmartMagnificationController.messages.in; sourceTree = "<group>"; };
                2DAF4FFA1B636181006013D6 /* ViewGestureController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ViewGestureController.cpp; sourceTree = "<group>"; };
                2DB7667021B5E48A0045DDB1 /* AccessibilitySupportSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AccessibilitySupportSPI.h; sourceTree = "<group>"; };
+               2DB94297234E7A7F00E776AD /* WKMouseGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKMouseGestureRecognizer.h; path = ios/WKMouseGestureRecognizer.h; sourceTree = "<group>"; };
+               2DB94298234E7A7F00E776AD /* WKMouseGestureRecognizer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKMouseGestureRecognizer.mm; path = ios/WKMouseGestureRecognizer.mm; sourceTree = "<group>"; };
                2DC18FAB218910480025A88D /* WKDrawingView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WKDrawingView.h; path = ios/WKDrawingView.h; sourceTree = "<group>"; };
                2DC18FAC218910480025A88D /* WKDrawingView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WKDrawingView.mm; path = ios/WKDrawingView.mm; sourceTree = "<group>"; };
                2DC18FAF218912640025A88D /* PencilKitSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PencilKitSPI.h; sourceTree = "<group>"; };
                                A54293A3195A43C6002782C7 /* WKInspectorNodeSearchGestureRecognizer.mm */,
                                2DD5E127210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.h */,
                                2DD5E126210ADC7A00DB6012 /* WKKeyboardScrollingAnimator.mm */,
+                               2DB94297234E7A7F00E776AD /* WKMouseGestureRecognizer.h */,
+                               2DB94298234E7A7F00E776AD /* WKMouseGestureRecognizer.mm */,
                                A15EEDE41E301CEE000069B0 /* WKPasswordView.h */,
                                A15EEDE31E301CEE000069B0 /* WKPasswordView.mm */,
                                2D6AB53F192B1C4A003A9FD1 /* WKPDFPageNumberIndicator.h */,
                                5CABDC8622C40FDE001EDE8E /* WKMessageListener.h in Headers */,
                                C11E1694212B87C500985FF6 /* WKMockDisplay.h in Headers */,
                                411A8DDB20DDD1AC0060D34F /* WKMockMediaDevice.h in Headers */,
+                               2DB94299234E7A7F00E776AD /* WKMouseGestureRecognizer.h in Headers */,
                                BC4075FE124FF0270068F20A /* WKMutableArray.h in Headers */,
                                BC407600124FF0270068F20A /* WKMutableDictionary.h in Headers */,
                                C09AE5E9125257C20025825D /* WKNativeEvent.h in Headers */,