Need to be able to test default behaviors on force click
authorbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Sep 2015 18:45:48 +0000 (18:45 +0000)
committerbdakin@apple.com <bdakin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 4 Sep 2015 18:45:48 +0000 (18:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=148758

Reviewed by Tim Horton.

Source/WebCore:

WKTR needs access to this.
* platform/spi/mac/NSEventSPI.h:

Source/WebKit2:

The hit test seems to return synchronously in WKTR, so we need to do the hit
test last before we clear state otherwise we will trample the hit test
result.
* UIProcess/mac/WKImmediateActionController.mm:
(-[WKImmediateActionController immediateActionRecognizerWillPrepare:]):
(-[WKImmediateActionController immediateActionRecognizerWillBeginAnimation:]):

Tools:

This patch adds a new eventSender method to do a full, completed force click,
and it re-works all of the existing force methods to dispatch their events in
such a way that they will trigger the NSImmediateAction gesture recognizer.
To do this, first we need to send the events to the app rather than straight
to the view, and also needed to tweak some state and send the events in a
delayed fashion.

New public function mouseForceClick() and private helper functions to make
NSEvents.
* WebKitTestRunner/EventSenderProxy.h:

New public function mouseForceClick().
* WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl:
* WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
(WTR::EventSendingController::mouseMoveTo):
(WTR::EventSendingController::mouseForceClick):
(WTR::EventSendingController::mouseForceDown):
* WebKitTestRunner/InjectedBundle/EventSendingController.h:
* WebKitTestRunner/TestController.cpp:
(WTR::TestController::didReceiveSynchronousMessageFromInjectedBundle):

initPressureEventAtLocation needs to take a stageTransition and a window.
* WebKitTestRunner/mac/EventSenderProxy.mm:
(-[EventSenderSyntheticEvent initPressureEventAtLocation:globalLocation:stage:pressure:stageTransition:phase:time:eventNumber:window:]):
(-[EventSenderSyntheticEvent stageTransition]):
(-[EventSenderSyntheticEvent timestamp]):
(-[EventSenderSyntheticEvent _cgsEventRecord]):
(-[EventSenderSyntheticEvent window]):

In order to enter the gesture recognizer, we need to start with a mouse down
that has a NSEventMaskPressure modifier.
(WTR::EventSenderProxy::sendMouseDownToStartPressureEvents):

This ensures that the events queue properly for the force monitor in AppKit.
(WTR::spinRunLoopForForce):

 We need to start the pressure change events with a began.
(WTR::EventSenderProxy::beginPressureEvent):

These functions can be used to create the NSEvent for a pressure change every
time we need one.
(WTR::EventSenderProxy::pressureChangeEvent):

Send the right series of events to emulate a full, completed force click.
(WTR::EventSenderProxy::mouseForceClick):

Use all of the new things for these existing functions.
(WTR::EventSenderProxy::mouseForceDown):
(WTR::EventSenderProxy::mouseForceUp):
(WTR::EventSenderProxy::mouseForceChanged):

Set NSFakeForceTouchDevice to YES.
* WebKitTestRunner/mac/main.mm:
(setDefaultsToConsistentValuesForTesting):

LayoutTests:

One new test that tests a regression found during the work for
http://trac.webkit.org/changeset/181660

* fast/events/force-click-on-link-navigation-expected.txt: Added.
* fast/events/force-click-on-link-navigation.html: Added.
* fast/events/resources/do-not-navigate-here.html: Added.
* platform/efl/TestExpectations:
* platform/gtk/TestExpectations:
* platform/ios-simulator/TestExpectations:
* platform/mac-mavericks/TestExpectations:
* platform/mac-wk1/TestExpectations:
* platform/win/TestExpectations:

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

22 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/force-click-on-link-navigation-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/force-click-on-link-navigation.html [new file with mode: 0644]
LayoutTests/fast/events/resources/do-not-navigate-here.html [new file with mode: 0644]
LayoutTests/platform/efl/TestExpectations
LayoutTests/platform/gtk/TestExpectations
LayoutTests/platform/ios-simulator/TestExpectations
LayoutTests/platform/mac-mavericks/TestExpectations
LayoutTests/platform/mac-wk1/TestExpectations
LayoutTests/platform/win/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/platform/spi/mac/NSEventSPI.h
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/mac/WKImmediateActionController.mm
Tools/ChangeLog
Tools/WebKitTestRunner/EventSenderProxy.h
Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl
Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp
Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h
Tools/WebKitTestRunner/TestController.cpp
Tools/WebKitTestRunner/mac/EventSenderProxy.mm
Tools/WebKitTestRunner/mac/main.mm

index 069d143..4d0874d 100644 (file)
@@ -1,3 +1,23 @@
+2015-09-04  Beth Dakin  <bdakin@apple.com>
+
+        Need to be able to test default behaviors on force click
+        https://bugs.webkit.org/show_bug.cgi?id=148758
+
+        Reviewed by Tim Horton.
+
+        One new test that tests a regression found during the work for 
+        http://trac.webkit.org/changeset/181660
+
+        * fast/events/force-click-on-link-navigation-expected.txt: Added.
+        * fast/events/force-click-on-link-navigation.html: Added.
+        * fast/events/resources/do-not-navigate-here.html: Added.
+        * platform/efl/TestExpectations:
+        * platform/gtk/TestExpectations:
+        * platform/ios-simulator/TestExpectations:
+        * platform/mac-mavericks/TestExpectations:
+        * platform/mac-wk1/TestExpectations:
+        * platform/win/TestExpectations:
+
 2015-09-04  Ryosuke Niwa  <rniwa@webkit.org>
 
         Import new multicolumn layout tests from CSS WG testss
diff --git a/LayoutTests/fast/events/force-click-on-link-navigation-expected.txt b/LayoutTests/fast/events/force-click-on-link-navigation-expected.txt
new file mode 100644 (file)
index 0000000..8e671d7
--- /dev/null
@@ -0,0 +1,2 @@
+Link
+SUCCESS! We did not navigate to the link after force clicking it.
diff --git a/LayoutTests/fast/events/force-click-on-link-navigation.html b/LayoutTests/fast/events/force-click-on-link-navigation.html
new file mode 100644 (file)
index 0000000..968448f
--- /dev/null
@@ -0,0 +1,49 @@
+<html>
+<head>
+<script>
+
+var didNavigate = false;
+
+window.onbeforeunload = function () {
+    didNavigate = true;
+};
+
+function checkForDone()
+{
+    if (!didNavigate) {
+        var console = document.getElementById("console");
+        console.innerHTML = "SUCCESS! We did not navigate to the link after force clicking it.";
+    }
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function spinRunLoop()
+{
+    window.setTimeout(checkForDone, 0);
+}
+
+function startTest()
+{
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    if (window.eventSender) {
+        eventSender.mouseMoveTo(16, 16);
+        eventSender.mouseForceClick();
+        window.setTimeout(spinRunLoop, 0);
+    }
+}
+</script>
+</head>
+
+<body onload="startTest()">
+
+<a href="resources/do-not-navigate-here.html">Link</a>
+<pre id="console">Failed. This test must be run in the test harness. To run the test manually, force click on the link and make sure that the original document does not navigate anywhere.</pre>
+
+</body>
+</html>
diff --git a/LayoutTests/fast/events/resources/do-not-navigate-here.html b/LayoutTests/fast/events/resources/do-not-navigate-here.html
new file mode 100644 (file)
index 0000000..4c9f0f4
--- /dev/null
@@ -0,0 +1,15 @@
+<html>
+<head>
+<script>
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.notifyDone();
+}
+
+</script>
+</head>
+<body>
+Force click tests should not navigate to this page after a successful force click or a started-then-cancelled force click. If navigation occurs, then this test FAILS.
+</body>
+</html>
index 9ffd851..de7865c 100644 (file)
@@ -69,6 +69,7 @@ animations/trigger-container-scroll-simple.html [ Skip ]
 animations/trigger-container-scroll-boundaries.html [ Skip ]
 
 # No support for force events
+fast/events/force-click-on-link-navigation.html [ Skip ]
 fast/events/mouse-force-changed.html [ Skip ]
 fast/events/mouse-force-down.html [ Skip ]
 fast/events/mouse-force-up.html [ Skip ]
index deaa864..84d51ed 100644 (file)
@@ -570,6 +570,7 @@ http/tests/contentfiltering [ Skip ]
 webkit.org/b/143703 fast/forms/listbox-visible-size.html [ Failure ]
 
 # No support for force events
+fast/events/force-click-on-link-navigation.html [ Skip ]
 fast/events/mouse-force-changed.html [ Skip ]
 fast/events/mouse-force-down.html [ Skip ]
 fast/events/mouse-force-up.html [ Skip ]
index 4c74adb..15d48a7 100644 (file)
@@ -178,6 +178,7 @@ http/tests/security/drag-drop-same-unique-origin.html
 http/tests/security/drag-over-remote-content-iframe.html
 
 # No support for force events
+fast/events/force-click-on-link-navigation.html [ Skip ]
 fast/events/mouse-force-changed.html [ Skip ]
 fast/events/mouse-force-down.html [ Skip ]
 fast/events/mouse-force-up.html [ Skip ]
index f0e3ce1..24c0f44 100644 (file)
@@ -2,6 +2,7 @@
 http/tests/cache/disk-cache/disk-cache-validation-back-navigation-policy.html
 
 # No support for force events
+fast/events/force-click-on-link-navigation.html [ Skip ]
 fast/events/mouse-force-changed.html [ Skip ]
 fast/events/mouse-force-down.html [ Skip ]
 fast/events/mouse-force-up.html [ Skip ]
index 43569ae..6ffdb89 100644 (file)
@@ -124,6 +124,7 @@ compositing/iframes/overlapped-nested-iframes.html [ Pass Failure ]
 http/tests/cache/disk-cache
 
 # There is not yet support for force events in WK1.
+fast/events/force-click-on-link-navigation.html [ Skip ]
 fast/events/mouse-force-changed.html [ Skip ]
 fast/events/mouse-force-down.html [ Skip ]
 fast/events/mouse-force-up.html [ Skip ]
index b15cab8..b3c7eba 100644 (file)
@@ -619,6 +619,7 @@ animations/trigger-container-scroll-simple.html [ Skip ]
 animations/trigger-container-scroll-boundaries.html [ Skip ]
 
 # No support for force events
+fast/events/force-click-on-link-navigation.html [ Skip ]
 fast/events/mouse-force-changed.html [ Skip ]
 fast/events/mouse-force-down.html [ Skip ]
 fast/events/mouse-force-up.html [ Skip ]
index 06c6960..87b0f8e 100644 (file)
@@ -1,3 +1,13 @@
+2015-09-04  Beth Dakin  <bdakin@apple.com>
+
+        Need to be able to test default behaviors on force click
+        https://bugs.webkit.org/show_bug.cgi?id=148758
+
+        Reviewed by Tim Horton.
+
+        WKTR needs access to this.
+        * platform/spi/mac/NSEventSPI.h:
+
 2015-09-04  Dean Jackson  <dino@apple.com>
 
         [mediacontrols] Test the ordering of elements in the controls panel
index 8577ce5..6bdb2fb 100644 (file)
@@ -39,4 +39,8 @@ enum {
 
 #endif
 
+@interface NSEvent (ForTestRunner)
+- (void)_postDelayed;
+@end
+
 #endif
index 1bf955f..25ea630 100644 (file)
@@ -1,3 +1,17 @@
+2015-09-04  Beth Dakin  <bdakin@apple.com>
+
+        Need to be able to test default behaviors on force click
+        https://bugs.webkit.org/show_bug.cgi?id=148758
+
+        Reviewed by Tim Horton.
+
+        The hit test seems to return synchronously in WKTR, so we need to do the hit 
+        test last before we clear state otherwise we will trample the hit test 
+        result.
+        * UIProcess/mac/WKImmediateActionController.mm:
+        (-[WKImmediateActionController immediateActionRecognizerWillPrepare:]):
+        (-[WKImmediateActionController immediateActionRecognizerWillBeginAnimation:]):
+
 2015-09-03  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r189338.
index ec60222..6a6c40d 100644 (file)
@@ -173,10 +173,10 @@ using namespace WebKit;
 
     _page->setMaintainsInactiveSelection(true);
 
-    _page->performImmediateActionHitTestAtLocation([immediateActionRecognizer locationInView:immediateActionRecognizer.view]);
-
     _state = ImmediateActionState::Pending;
     immediateActionRecognizer.animationController = nil;
+
+    _page->performImmediateActionHitTestAtLocation([immediateActionRecognizer locationInView:immediateActionRecognizer.view]);
 }
 
 - (void)immediateActionRecognizerWillBeginAnimation:(NSImmediateActionGestureRecognizer *)immediateActionRecognizer
index 2a7821a..956bac4 100644 (file)
@@ -1,3 +1,65 @@
+2015-09-04  Beth Dakin  <bdakin@apple.com>
+
+        Need to be able to test default behaviors on force click
+        https://bugs.webkit.org/show_bug.cgi?id=148758
+
+        Reviewed by Tim Horton.
+
+        This patch adds a new eventSender method to do a full, completed force click, 
+        and it re-works all of the existing force methods to dispatch their events in 
+        such a way that they will trigger the NSImmediateAction gesture recognizer. 
+        To do this, first we need to send the events to the app rather than straight 
+        to the view, and also needed to tweak some state and send the events in a 
+        delayed fashion.
+
+        New public function mouseForceClick() and private helper functions to make 
+        NSEvents.
+        * WebKitTestRunner/EventSenderProxy.h:
+
+        New public function mouseForceClick().
+        * WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl:
+        * WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
+        (WTR::EventSendingController::mouseMoveTo):
+        (WTR::EventSendingController::mouseForceClick):
+        (WTR::EventSendingController::mouseForceDown):
+        * WebKitTestRunner/InjectedBundle/EventSendingController.h:
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::didReceiveSynchronousMessageFromInjectedBundle):
+
+        initPressureEventAtLocation needs to take a stageTransition and a window.
+        * WebKitTestRunner/mac/EventSenderProxy.mm:
+        (-[EventSenderSyntheticEvent initPressureEventAtLocation:globalLocation:stage:pressure:stageTransition:phase:time:eventNumber:window:]):
+        (-[EventSenderSyntheticEvent stageTransition]):
+        (-[EventSenderSyntheticEvent timestamp]):
+        (-[EventSenderSyntheticEvent _cgsEventRecord]):
+        (-[EventSenderSyntheticEvent window]):
+
+        In order to enter the gesture recognizer, we need to start with a mouse down 
+        that has a NSEventMaskPressure modifier.
+        (WTR::EventSenderProxy::sendMouseDownToStartPressureEvents):
+
+        This ensures that the events queue properly for the force monitor in AppKit.
+        (WTR::spinRunLoopForForce):
+
+         We need to start the pressure change events with a began.
+        (WTR::EventSenderProxy::beginPressureEvent):
+
+        These functions can be used to create the NSEvent for a pressure change every 
+        time we need one.
+        (WTR::EventSenderProxy::pressureChangeEvent):
+
+        Send the right series of events to emulate a full, completed force click.
+        (WTR::EventSenderProxy::mouseForceClick):
+
+        Use all of the new things for these existing functions.
+        (WTR::EventSenderProxy::mouseForceDown):
+        (WTR::EventSenderProxy::mouseForceUp):
+        (WTR::EventSenderProxy::mouseForceChanged):
+
+        Set NSFakeForceTouchDevice to YES.
+        * WebKitTestRunner/mac/main.mm:
+        (setDefaultsToConsistentValuesForTesting):
+
 2015-09-04  Jason Marcell  <jmarcell@apple.com>
 
         prepare-ChangeLog needs to know how to parse Swift files.
index e1ea670..7b2ecd9 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <wtf/Deque.h>
 #include <wtf/HashMap.h>
+#include <wtf/RetainPtr.h>
 #include <wtf/Vector.h>
 
 #if PLATFORM(GTK)
 #include "EWebKit2.h"
 #endif
 
+#if PLATFORM(COCOA)
+OBJC_CLASS NSEvent;
+#endif
+
 namespace WTR {
 
 class TestController;
@@ -61,6 +66,7 @@ public:
     void mouseForceDown();
     void mouseForceUp();
     void mouseForceChanged(float);
+    void mouseForceClick();
     void mouseMoveTo(double x, double y);
     void mouseScrollBy(int x, int y);
     void mouseScrollByWithWheelAndMomentumPhases(int x, int y, int phase, int momentum);
@@ -96,6 +102,14 @@ private:
     void replaySavedEvents();
 #endif
 
+    void sendMouseDownToStartPressureEvents();
+#if PLATFORM(COCOA)
+    enum class PressureChangeDirection { Increasing, Decreasing };
+    RetainPtr<NSEvent> beginPressureEvent(int stage);
+    RetainPtr<NSEvent> pressureChangeEvent(int stage, PressureChangeDirection);
+    RetainPtr<NSEvent> pressureChangeEvent(int stage, float pressure, PressureChangeDirection);
+#endif
+
 #if PLATFORM(GTK)
     void sendOrQueueEvent(GdkEvent*);
     void dispatchEvent(GdkEvent*);
index 5cbbcdb..c74366e 100644 (file)
@@ -27,6 +27,7 @@ interface EventSendingController {
     void mouseDown(long buttonNumber, object modifierArray);
     void mouseUp(long buttonNumber, object modifierArray);
     void mouseMoveTo(long x, long y);
+    void mouseForceClick();
     void mouseForceDown();
     void mouseForceUp();
     void mouseForceChanged(double force);
index 349163a..2c45589 100644 (file)
@@ -255,6 +255,18 @@ void EventSendingController::mouseMoveTo(int x, int y)
     WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
 }
 
+void EventSendingController::mouseForceClick()
+{
+    WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
+    WKRetainPtr<WKMutableDictionaryRef> EventSenderMessageBody(AdoptWK, WKMutableDictionaryCreate());
+
+    WKRetainPtr<WKStringRef> subMessageKey(AdoptWK, WKStringCreateWithUTF8CString("SubMessage"));
+    WKRetainPtr<WKStringRef> subMessageName(AdoptWK, WKStringCreateWithUTF8CString("MouseForceClick"));
+    WKDictionarySetItem(EventSenderMessageBody.get(), subMessageKey.get(), subMessageName.get());
+
+    WKBundlePagePostSynchronousMessageForTesting(InjectedBundle::singleton().page()->page(), EventSenderMessageName.get(), EventSenderMessageBody.get(), 0);
+}
+
 void EventSendingController::mouseForceDown()
 {
     WKRetainPtr<WKStringRef> EventSenderMessageName(AdoptWK, WKStringCreateWithUTF8CString("EventSender"));
index 5755f19..7b9784a 100644 (file)
@@ -46,6 +46,7 @@ public:
     void mouseDown(int button, JSValueRef modifierArray);
     void mouseUp(int button, JSValueRef modifierArray);
     void mouseMoveTo(int x, int y);
+    void mouseForceClick();
     void mouseForceDown();
     void mouseForceUp();
     void mouseForceChanged(double force);
index 886056a..795f1ee 100644 (file)
@@ -1211,6 +1211,11 @@ WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedB
         }
 
 #if PLATFORM(MAC)
+        if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceClick")) {
+            m_eventSenderProxy->mouseForceClick();
+            return 0;
+        }
+
         if (WKStringIsEqualToUTF8CString(subMessageName, "MouseForceDown")) {
             m_eventSenderProxy->mouseForceDown();
             return 0;
index 7ba1cc8..9cb460c 100644 (file)
@@ -31,6 +31,7 @@
 #import "StringFunctions.h"
 #import "TestController.h"
 #import <Carbon/Carbon.h>
+#import <WebCore/NSEventSPI.h>
 #import <WebKit/WKString.h>
 #import <WebKit/WKPagePrivate.h>
 #import <WebKit/WKWebView.h>
@@ -68,25 +69,28 @@ struct WKTRCGSEventRecord {
     NSPoint _eventSender_location;
     NSInteger _eventSender_stage;
     float _eventSender_pressure;
+    CGFloat _eventSender_stageTransition;
     NSEventPhase _eventSender_phase;
     NSEventPhase _eventSender_momentumPhase;
     NSTimeInterval _eventSender_timestamp;
     NSInteger _eventSender_eventNumber;
     short _eventSender_subtype;
     NSEventType _eventSender_type;
+    NSWindow *_eventSender_window;
+
 
 #if defined(__LP64__)
     WKTRCGSEventRecord _eventSender_cgsEventRecord;
 #endif
 }
 
-- (id)initPressureEventAtLocation:(NSPoint)location globalLocation:(NSPoint)globalLocation stage:(NSInteger)stage pressure:(float)pressure phase:(NSEventPhase)phase time:(NSTimeInterval)time eventNumber:(NSInteger)eventNumber;
+- (id)initPressureEventAtLocation:(NSPoint)location globalLocation:(NSPoint)globalLocation stage:(NSInteger)stage pressure:(float)pressure stageTransition:(float)stageTransition phase:(NSEventPhase)phase time:(NSTimeInterval)time eventNumber:(NSInteger)eventNumber window:(NSWindow *)window;
 - (NSTimeInterval)timestamp;
 @end
 
 @implementation EventSenderSyntheticEvent
 
-- (id)initPressureEventAtLocation:(NSPoint)location globalLocation:(NSPoint)globalLocation stage:(NSInteger)stage pressure:(float)pressure phase:(NSEventPhase)phase time:(NSTimeInterval)time eventNumber:(NSInteger)eventNumber
+- (id)initPressureEventAtLocation:(NSPoint)location globalLocation:(NSPoint)globalLocation stage:(NSInteger)stage pressure:(float)pressure stageTransition:(float)stageTransition phase:(NSEventPhase)phase time:(NSTimeInterval)time eventNumber:(NSInteger)eventNumber window:(NSWindow *)window
 {
     self = [super init];
 
@@ -97,9 +101,11 @@ struct WKTRCGSEventRecord {
     _eventSender_locationInWindow = globalLocation;
     _eventSender_stage = stage;
     _eventSender_pressure = pressure;
+    _eventSender_stageTransition = stageTransition;
     _eventSender_phase = phase;
     _eventSender_timestamp = time;
     _eventSender_eventNumber = eventNumber;
+    _eventSender_window = window;
 #if defined(__LP64__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101003
     _eventSender_type = NSEventTypePressure;
 #endif
@@ -107,6 +113,11 @@ struct WKTRCGSEventRecord {
     return self;
 }
 
+- (CGFloat)stageTransition
+{
+    return _eventSender_stageTransition;
+}
+
 - (NSTimeInterval)timestamp
 {
     return _eventSender_timestamp;
@@ -176,6 +187,11 @@ struct WKTRCGSEventRecord {
 }
 #endif
 
+- (NSWindow *)window
+{
+    return _eventSender_window;
+}
+
 @end
 
 namespace WTR {
@@ -350,33 +366,95 @@ void EventSenderProxy::mouseUp(unsigned buttonNumber, WKEventModifiers modifiers
 }
 
 #if defined(__LP64__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101003
-void EventSenderProxy::mouseForceDown()
+void EventSenderProxy::sendMouseDownToStartPressureEvents()
 {
-    EventSenderSyntheticEvent *firstEvent = [[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
+    updateClickCountForButton(0);
+
+    NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown
+        location:NSMakePoint(m_position.x, m_position.y)
+        modifierFlags:NSEventMaskPressure
+        timestamp:absoluteTimeForEventTime(currentEventTime())
+        windowNumber:[m_testController->mainWebView()->platformWindow() windowNumber]
+        context:[NSGraphicsContext currentContext]
+        eventNumber:++eventNumber
+        clickCount:m_clickCount
+        pressure:0.0];
+
+    [NSApp sendEvent:event];
+}
+
+static void handleForceEventSynchronously(NSEvent *event)
+{
+    // Force events have to be pushed onto the queue, then popped off right away and handled synchronously in order
+    // to get the NSImmediateActionGestureRecognizer to do the right thing.
+    [event _postDelayed];
+    [NSApp sendEvent:[NSApp nextEventMatchingMask:NSEventMaskPressure untilDate:[NSDate dateWithTimeIntervalSinceNow:0.05] inMode:NSDefaultRunLoopMode dequeue:YES]];
+}
+
+RetainPtr<NSEvent> EventSenderProxy::beginPressureEvent(int stage)
+{
+    RetainPtr<EventSenderSyntheticEvent> event = adoptNS([[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
         globalLocation:([m_testController->mainWebView()->platformWindow() convertRectToScreen:NSMakeRect(m_position.x, m_position.y, 1, 1)].origin)
-        stage:1
-        pressure:0.9
-        phase:NSEventPhaseChanged
+        stage:stage
+        pressure:0.5
+        stageTransition:0
+        phase:NSEventPhaseBegan
         time:absoluteTimeForEventTime(currentEventTime())
-        eventNumber:++eventNumber];
-    EventSenderSyntheticEvent *secondEvent = [[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
+        eventNumber:++eventNumber
+        window:[m_testController->mainWebView()->platformView() window]]);
+
+    return event;
+}
+
+RetainPtr<NSEvent> EventSenderProxy::pressureChangeEvent(int stage, float pressure, EventSenderProxy::PressureChangeDirection direction)
+{
+    RetainPtr<EventSenderSyntheticEvent> event = adoptNS([[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
         globalLocation:([m_testController->mainWebView()->platformWindow() convertRectToScreen:NSMakeRect(m_position.x, m_position.y, 1, 1)].origin)
-        stage:2
-        pressure:0.1
+        stage:stage
+        pressure:pressure
+        stageTransition:direction == PressureChangeDirection::Increasing ? 0.5 : -0.5
         phase:NSEventPhaseChanged
         time:absoluteTimeForEventTime(currentEventTime())
-        eventNumber:++eventNumber];
+        eventNumber:++eventNumber
+        window:[m_testController->mainWebView()->platformView() window]]);
+
+    return event;
+}
+
+RetainPtr<NSEvent> EventSenderProxy::pressureChangeEvent(int stage, EventSenderProxy::PressureChangeDirection direction)
+{
+    return pressureChangeEvent(stage, 0.5, direction);
+}
+
+void EventSenderProxy::mouseForceClick()
+{
+    sendMouseDownToStartPressureEvents();
 
-    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[firstEvent locationInWindow]];
+    RetainPtr<NSEvent> beginPressure = beginPressureEvent(1);
+    RetainPtr<NSEvent> preForceClick = pressureChangeEvent(1, PressureChangeDirection::Increasing);
+    RetainPtr<NSEvent> forceClick = pressureChangeEvent(2, PressureChangeDirection::Increasing);
+    RetainPtr<NSEvent> releasingPressure = pressureChangeEvent(1, PressureChangeDirection::Decreasing);
+    NSEvent *mouseUp = [NSEvent mouseEventWithType:NSLeftMouseUp
+        location:NSMakePoint(m_position.x, m_position.y)
+        modifierFlags:0
+        timestamp:absoluteTimeForEventTime(currentEventTime())
+        windowNumber:[m_testController->mainWebView()->platformWindow() windowNumber]
+        context:[NSGraphicsContext currentContext]
+        eventNumber:++eventNumber
+        clickCount:m_clickCount
+        pressure:0.0];
+
+    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[preForceClick.get() locationInWindow]];
     targetView = targetView ? targetView : m_testController->mainWebView()->platformView();
     ASSERT(targetView);
 
     // Since AppKit does not implement forceup/down as mouse events, we need to send two pressure events to detect
     // the change in stage that marks those moments.
-    [NSApp _setCurrentEvent:firstEvent];
-    [targetView pressureChangeWithEvent:firstEvent];
-    [NSApp _setCurrentEvent:secondEvent];
-    [targetView pressureChangeWithEvent:secondEvent];
+    handleForceEventSynchronously(beginPressure.get());
+    handleForceEventSynchronously(preForceClick.get());
+    handleForceEventSynchronously(forceClick.get());
+    handleForceEventSynchronously(releasingPressure.get());
+    [NSApp sendEvent:mouseUp];
 
     [NSApp _setCurrentEvent:nil];
 #pragma clang diagnostic push
@@ -384,38 +462,49 @@ void EventSenderProxy::mouseForceDown()
     // WKView caches the most recent pressure event, so send it a nil event to clear the cache.
     [targetView pressureChangeWithEvent:nil];
 #pragma clang diagnostic pop
-
-    [firstEvent release];
-    [secondEvent release];
 }
 
-void EventSenderProxy::mouseForceUp()
+void EventSenderProxy::mouseForceDown()
 {
-    EventSenderSyntheticEvent *firstEvent = [[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
-        globalLocation:([m_testController->mainWebView()->platformWindow() convertRectToScreen:NSMakeRect(m_position.x, m_position.y, 1, 1)].origin)
-        stage:2
-        pressure:0.1
-        phase:NSEventPhaseChanged
-        time:absoluteTimeForEventTime(currentEventTime())
-        eventNumber:++eventNumber];
-    EventSenderSyntheticEvent *secondEvent = [[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
-        globalLocation:([m_testController->mainWebView()->platformWindow() convertRectToScreen:NSMakeRect(m_position.x, m_position.y, 1, 1)].origin)
-        stage:1
-        pressure:0.9
-        phase:NSEventPhaseChanged
-        time:absoluteTimeForEventTime(currentEventTime())
-        eventNumber:++eventNumber];
+    sendMouseDownToStartPressureEvents();
 
-    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[firstEvent locationInWindow]];
+    RetainPtr<NSEvent> beginPressure = beginPressureEvent(1);
+    RetainPtr<NSEvent> preForceClick = pressureChangeEvent(1, PressureChangeDirection::Increasing);
+    RetainPtr<NSEvent> forceMouseDown = pressureChangeEvent(2, PressureChangeDirection::Increasing);
+
+    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[beginPressure locationInWindow]];
     targetView = targetView ? targetView : m_testController->mainWebView()->platformView();
     ASSERT(targetView);
 
     // Since AppKit does not implement forceup/down as mouse events, we need to send two pressure events to detect
     // the change in stage that marks those moments.
-    [NSApp _setCurrentEvent:firstEvent];
-    [targetView pressureChangeWithEvent:firstEvent];
-    [NSApp _setCurrentEvent:secondEvent];
-    [targetView pressureChangeWithEvent:secondEvent];
+    handleForceEventSynchronously(beginPressure.get());
+    handleForceEventSynchronously(preForceClick.get());
+    [forceMouseDown _postDelayed];
+
+    [NSApp _setCurrentEvent:nil];
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnonnull"
+    // WKView caches the most recent pressure event, so send it a nil event to clear the cache.
+    [targetView pressureChangeWithEvent:nil];
+#pragma clang diagnostic pop
+}
+
+void EventSenderProxy::mouseForceUp()
+{
+    RetainPtr<NSEvent> beginPressure = beginPressureEvent(2);
+    RetainPtr<NSEvent> stageTwoEvent = pressureChangeEvent(2, PressureChangeDirection::Decreasing);
+    RetainPtr<NSEvent> stageOneEvent = pressureChangeEvent(1, PressureChangeDirection::Decreasing);
+
+    // Since AppKit does not implement forceup/down as mouse events, we need to send two pressure events to detect
+    // the change in stage that marks those moments.
+    [NSApp sendEvent:beginPressure.get()];
+    [NSApp sendEvent:stageTwoEvent.get()];
+    [NSApp sendEvent:stageOneEvent.get()];
+
+    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[beginPressure locationInWindow]];
+    targetView = targetView ? targetView : m_testController->mainWebView()->platformView();
+    ASSERT(targetView);
 
     [NSApp _setCurrentEvent:nil];
 
@@ -424,37 +513,51 @@ void EventSenderProxy::mouseForceUp()
 // WKView caches the most recent pressure event, so send it a nil event to clear the cache.
     [targetView pressureChangeWithEvent:nil];
 #pragma clang diagnostic pop
-
-    [firstEvent release];
-    [secondEvent release];
 }
 
 void EventSenderProxy::mouseForceChanged(float force)
 {
-    EventSenderSyntheticEvent *event = [[EventSenderSyntheticEvent alloc] initPressureEventAtLocation:NSMakePoint(m_position.x, m_position.y)
-        globalLocation:([m_testController->mainWebView()->platformWindow() convertRectToScreen:NSMakeRect(m_position.x, m_position.y, 1, 1)].origin)
-        stage:force < 1 ? 1 : 2
-        pressure:force
-        phase:NSEventPhaseChanged
-        time:absoluteTimeForEventTime(currentEventTime())
-        eventNumber:++eventNumber];
+    int stage = force < 1 ? 1 : 2;
+    float pressure = force < 1 ? force : force - 1;
+    RetainPtr<NSEvent> beginPressure = beginPressureEvent(stage);
+    RetainPtr<NSEvent> pressureChangedEvent = pressureChangeEvent(stage, pressure, PressureChangeDirection::Increasing);
 
-    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[event locationInWindow]];
+    NSView *targetView = [m_testController->mainWebView()->platformView() hitTest:[beginPressure locationInWindow]];
     targetView = targetView ? targetView : m_testController->mainWebView()->platformView();
     ASSERT(targetView);
-    [NSApp _setCurrentEvent:event];
-    [targetView pressureChangeWithEvent:event];
-    [NSApp _setCurrentEvent:nil];
+
+    [NSApp sendEvent:beginPressure.get()];
+    [NSApp sendEvent:pressureChangedEvent.get()];
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wnonnull"
     // WKView caches the most recent pressure event, so send it a nil event to clear the cache.
     [targetView pressureChangeWithEvent:nil];
 #pragma clang diagnostic pop
-
-    [event release];
 }
 #else
+
+#if PLATFORM(COCOA)
+RetainPtr<NSEvent> EventSenderProxy::beginPressureEvent(int)
+{
+    return nil;
+}
+
+RetainPtr<NSEvent> EventSenderProxy::pressureChangeEvent(int, PressureChangeDirection)
+{
+    return nil;
+}
+
+RetainPtr<NSEvent> EventSenderProxy::pressureChangeEvent(int, float, PressureChangeDirection)
+{
+    return nil;
+}
+#endif // PLATFORM(COCOA)
+
+void EventSenderProxy::sendMouseDownToStartPressureEvents()
+{
+}
+
 void EventSenderProxy::mouseForceDown()
 {
 }
@@ -466,6 +569,10 @@ void EventSenderProxy::mouseForceUp()
 void EventSenderProxy::mouseForceChanged(float)
 {
 }
+
+void EventSenderProxy::mouseForceClick()
+{
+}
 #endif // defined(__LP64__) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101003
 
 void EventSenderProxy::mouseMoveTo(double x, double y)
index a5efd57..b26b897 100644 (file)
@@ -33,7 +33,8 @@ static void setDefaultsToConsistentValuesForTesting()
         @"AppleKeyboardUIMode": @1,
         // FIXME: This is likely insufficient, as tests change (and don't reset) these settings via Internals.
         @"WebAutomaticQuoteSubstitutionEnabled": @NO,
-        @"WebAutomaticDashSubstitutionEnabled": @NO
+        @"WebAutomaticDashSubstitutionEnabled": @NO,
+        @"NSFakeForceTouchDevice" : @YES
     };
 
     [[NSUserDefaults standardUserDefaults] setValuesForKeysWithDictionary:dict];