Title: [240554] trunk/Source/WebKit
Revision
240554
Author
bb...@apple.com
Date
2019-01-27 10:36:11 -0800 (Sun, 27 Jan 2019)

Log Message

Web Automation: add support for simulating single touches to Automation.performInteractionSequence
https://bugs.webkit.org/show_bug.cgi?id=193852
<rdar://problem/28360781>

Reviewed by Joseph Pecoraro and Simon Fraser.

This patch makes it possible to simulate touches via the Actions API. The approach is to
use a stripped down version of HIDEventGenerator to send HID events to the UIWindow.
The initial version supports a single touch point; this may be expanded if needed, but
so far it hasn't been an impediment when running desktop-oriented WebDriver test suites.

As part of implementing this support, I went through and added [somewhat obnoxious] ENABLE()
guards so that we don't mistakenly compile mouse support on iOS and touch on Mac,
and vice versa. Each of the interaction methods---touch, mouse, keyboard---can be independently
compiled out. If none is supported (i.e., Windows), then we don't even try to compile
platformSimulate*Interaction methods or SimulatedInputDispatcher. This allows WebAutomationSession
to not include members and code that are never going to be used on a particular platform.

This functionality is covered by existing WebDriver test suites that use Element Click command.
Additional tests that explicitly include 'touch' pointerType will be submitted to WPT later.

* UIProcess/Automation/Automation.json: Update comment.

* UIProcess/Automation/SimulatedInputDispatcher.h:
* UIProcess/Automation/SimulatedInputDispatcher.cpp:
(WebKit::SimulatedInputDispatcher::transitionInputSourceToState):
- Add appropriate guards for code specific to each interaction type.
- Handle SimulatedInputSourceType::Touch and call out to dispatch events.

* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::WebAutomationSession):
(WebKit::WebAutomationSession::terminate):
(WebKit::WebAutomationSession::willShowJavaScriptDialog):
(WebKit::WebAutomationSession::mouseEventsFlushedForPage):
(WebKit::WebAutomationSession::keyboardEventsFlushedForPage):
(WebKit::WebAutomationSession::willClosePage):
Add appropriate guards for code specific to each interaction type.

(WebKit::WebAutomationSession::isSimulatingUserInteraction const):
Add new hook so that we can detect when a touch simulation is in progress.
We don't rely on checking WebKit's event queue, so use a flag.

(WebKit::WebAutomationSession::simulateTouchInteraction):
(WebKit::WebAutomationSession::performMouseInteraction):
(WebKit::WebAutomationSession::performKeyboardInteractions):
(WebKit::WebAutomationSession::cancelInteractionSequence):
(WebKit::WebAutomationSession::performInteractionSequence):
- Add appropriate guards for code specific to each interaction type.
- Bail out immediately if a requested interaction type is not supported.
- Shim Touch input type to Mouse if mouse is not supported but touches are.
Nearly all WebDriver tests in the wild will be requesting a 'mouse' pointerType,
so this is necessary for compatibility. It's easier to shim at this level than try
to implement platformSimulateMouseInteraction for iOS because
platformSimulateMouseinteraction does not use a completion handler but the iOS
implementation would require that.

(WebKit::WebAutomationSession::platformSimulateMouseInteraction): Deleted.
(WebKit::WebAutomationSession::platformSimulateKeyboardInteraction): Deleted.
- Remove these stubs. Platform methods of this class are no longer being filled
with stubs on unsupported platforms because we expect the command to fail earlier.

* UIProcess/Automation/ios/WebAutomationSessionIOS.mm:
(WebKit::WebAutomationSession::platformSimulateTouchInteraction):
- Add appropriate guards for code specific to each interaction type.
- Implement new platform method to simulate touches. This uses _WKTouchEventGenerator.

* UIProcess/Automation/mac/WebAutomationSessionMac.mm:
Add appropriate guards for code specific to each interaction type.

* UIProcess/_WKTouchEventGenerator.h: Added.
* UIProcess/_WKTouchEventGenerator.mm: Added.
(simpleCurveInterpolation):
(calculateNextCurveLocation):
(delayBetweenMove):
(+[_WKTouchEventGenerator sharedTouchEventGenerator]):
(+[_WKTouchEventGenerator nextEventCallbackID]):
(-[_WKTouchEventGenerator init]):
(-[_WKTouchEventGenerator dealloc]):
(-[_WKTouchEventGenerator _createIOHIDEventType:]):
(-[_WKTouchEventGenerator _sendHIDEvent:]):
(-[_WKTouchEventGenerator _sendMarkerHIDEventWithCompletionBlock:]):
(-[_WKTouchEventGenerator _updateTouchPoints:count:]):
(-[_WKTouchEventGenerator touchDownAtPoints:touchCount:]):
(-[_WKTouchEventGenerator touchDown:touchCount:]):
(-[_WKTouchEventGenerator touchDown:]):
(-[_WKTouchEventGenerator liftUpAtPoints:touchCount:]):
(-[_WKTouchEventGenerator liftUp:touchCount:]):
(-[_WKTouchEventGenerator liftUp:]):
(-[_WKTouchEventGenerator moveToPoints:touchCount:duration:]):
(-[_WKTouchEventGenerator touchDown:completionBlock:]):
(-[_WKTouchEventGenerator liftUp:completionBlock:]):
(-[_WKTouchEventGenerator moveToPoint:duration:completionBlock:]):
(-[_WKTouchEventGenerator receivedHIDEvent:]):
Copied and simplified from HIDEventGenerator in WebKitTestRunner.

* WebKit.xcodeproj/project.pbxproj:
Add _WKTouchEventGenerator.{h,mm} and make it a private header. The client needs to
route received HID events to -receivedHIDEvent: in order to detect when the marker
HID event has been processed (and thus the interaction is completed).

* config.h: Add ENABLE(WEBDRIVER_*_INTERACTIONS) macros here.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (240553 => 240554)


--- trunk/Source/WebKit/ChangeLog	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/ChangeLog	2019-01-27 18:36:11 UTC (rev 240554)
@@ -1,3 +1,108 @@
+2019-01-25  Brian Burg  <bb...@apple.com>
+
+        Web Automation: add support for simulating single touches to Automation.performInteractionSequence
+        https://bugs.webkit.org/show_bug.cgi?id=193852
+        <rdar://problem/28360781>
+
+        Reviewed by Joseph Pecoraro and Simon Fraser.
+
+        This patch makes it possible to simulate touches via the Actions API. The approach is to
+        use a stripped down version of HIDEventGenerator to send HID events to the UIWindow.
+        The initial version supports a single touch point; this may be expanded if needed, but
+        so far it hasn't been an impediment when running desktop-oriented WebDriver test suites.
+
+        As part of implementing this support, I went through and added [somewhat obnoxious] ENABLE()
+        guards so that we don't mistakenly compile mouse support on iOS and touch on Mac,
+        and vice versa. Each of the interaction methods---touch, mouse, keyboard---can be independently
+        compiled out. If none is supported (i.e., Windows), then we don't even try to compile
+        platformSimulate*Interaction methods or SimulatedInputDispatcher. This allows WebAutomationSession
+        to not include members and code that are never going to be used on a particular platform.
+
+        This functionality is covered by existing WebDriver test suites that use Element Click command.
+        Additional tests that explicitly include 'touch' pointerType will be submitted to WPT later.
+
+        * UIProcess/Automation/Automation.json: Update comment.
+
+        * UIProcess/Automation/SimulatedInputDispatcher.h:
+        * UIProcess/Automation/SimulatedInputDispatcher.cpp:
+        (WebKit::SimulatedInputDispatcher::transitionInputSourceToState):
+        - Add appropriate guards for code specific to each interaction type.
+        - Handle SimulatedInputSourceType::Touch and call out to dispatch events.
+
+        * UIProcess/Automation/WebAutomationSession.h:
+        * UIProcess/Automation/WebAutomationSession.cpp:
+        (WebKit::WebAutomationSession::WebAutomationSession):
+        (WebKit::WebAutomationSession::terminate):
+        (WebKit::WebAutomationSession::willShowJavaScriptDialog):
+        (WebKit::WebAutomationSession::mouseEventsFlushedForPage):
+        (WebKit::WebAutomationSession::keyboardEventsFlushedForPage):
+        (WebKit::WebAutomationSession::willClosePage):
+        Add appropriate guards for code specific to each interaction type.
+
+        (WebKit::WebAutomationSession::isSimulatingUserInteraction const):
+        Add new hook so that we can detect when a touch simulation is in progress.
+        We don't rely on checking WebKit's event queue, so use a flag.
+
+        (WebKit::WebAutomationSession::simulateTouchInteraction):
+        (WebKit::WebAutomationSession::performMouseInteraction):
+        (WebKit::WebAutomationSession::performKeyboardInteractions):
+        (WebKit::WebAutomationSession::cancelInteractionSequence):
+        (WebKit::WebAutomationSession::performInteractionSequence):
+        - Add appropriate guards for code specific to each interaction type.
+        - Bail out immediately if a requested interaction type is not supported.
+        - Shim Touch input type to Mouse if mouse is not supported but touches are.
+        Nearly all WebDriver tests in the wild will be requesting a 'mouse' pointerType,
+        so this is necessary for compatibility. It's easier to shim at this level than try
+        to implement platformSimulateMouseInteraction for iOS because
+        platformSimulateMouseinteraction does not use a completion handler but the iOS
+        implementation would require that.
+
+        (WebKit::WebAutomationSession::platformSimulateMouseInteraction): Deleted.
+        (WebKit::WebAutomationSession::platformSimulateKeyboardInteraction): Deleted.
+        - Remove these stubs. Platform methods of this class are no longer being filled
+        with stubs on unsupported platforms because we expect the command to fail earlier.
+
+        * UIProcess/Automation/ios/WebAutomationSessionIOS.mm:
+        (WebKit::WebAutomationSession::platformSimulateTouchInteraction):
+        - Add appropriate guards for code specific to each interaction type.
+        - Implement new platform method to simulate touches. This uses _WKTouchEventGenerator.
+
+        * UIProcess/Automation/mac/WebAutomationSessionMac.mm:
+        Add appropriate guards for code specific to each interaction type.
+
+        * UIProcess/_WKTouchEventGenerator.h: Added.
+        * UIProcess/_WKTouchEventGenerator.mm: Added.
+        (simpleCurveInterpolation):
+        (calculateNextCurveLocation):
+        (delayBetweenMove):
+        (+[_WKTouchEventGenerator sharedTouchEventGenerator]):
+        (+[_WKTouchEventGenerator nextEventCallbackID]):
+        (-[_WKTouchEventGenerator init]):
+        (-[_WKTouchEventGenerator dealloc]):
+        (-[_WKTouchEventGenerator _createIOHIDEventType:]):
+        (-[_WKTouchEventGenerator _sendHIDEvent:]):
+        (-[_WKTouchEventGenerator _sendMarkerHIDEventWithCompletionBlock:]):
+        (-[_WKTouchEventGenerator _updateTouchPoints:count:]):
+        (-[_WKTouchEventGenerator touchDownAtPoints:touchCount:]):
+        (-[_WKTouchEventGenerator touchDown:touchCount:]):
+        (-[_WKTouchEventGenerator touchDown:]):
+        (-[_WKTouchEventGenerator liftUpAtPoints:touchCount:]):
+        (-[_WKTouchEventGenerator liftUp:touchCount:]):
+        (-[_WKTouchEventGenerator liftUp:]):
+        (-[_WKTouchEventGenerator moveToPoints:touchCount:duration:]):
+        (-[_WKTouchEventGenerator touchDown:completionBlock:]):
+        (-[_WKTouchEventGenerator liftUp:completionBlock:]):
+        (-[_WKTouchEventGenerator moveToPoint:duration:completionBlock:]):
+        (-[_WKTouchEventGenerator receivedHIDEvent:]):
+        Copied and simplified from HIDEventGenerator in WebKitTestRunner.
+
+        * WebKit.xcodeproj/project.pbxproj:
+        Add _WKTouchEventGenerator.{h,mm} and make it a private header. The client needs to
+        route received HID events to -receivedHIDEvent: in order to detect when the marker
+        HID event has been processed (and thus the interaction is completed).
+
+        * config.h: Add ENABLE(WEBDRIVER_*_INTERACTIONS) macros here.
+
 2019-01-26  Simon Fraser  <simon.fra...@apple.com>
 
         Have composited RenderIFrame layers make FrameHosting scrolling tree nodes to parent the iframe's scrolling node

Modified: trunk/Source/WebKit/UIProcess/Automation/Automation.json (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/Automation.json	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/Automation.json	2019-01-27 18:36:11 UTC (rev 240554)
@@ -299,7 +299,7 @@
                 { "name": "sourceId", "type": "string", "description": "The input source whose state is described by this object." },
                 { "name": "pressedCharKey", "type": "string", "optional": true, "description": "For 'keyboard' input sources, specifies a character key that has 'pressed' state. Unmentioned character keys are assumed to have a 'released' state." },
                 { "name": "pressedVirtualKeys", "type": "array", "items": { "$ref": "VirtualKey" }, "optional": true, "description": "For 'keyboard' input sources, specifies virtual keys that have a 'pressed' state. Unmentioned virtual keys are assumed to have a 'released' state." },
-                { "name": "pressedButton", "$ref": "MouseButton", "optional": true, "description": "For 'mouse' input sources, specifies which mouse button has a 'pressed' state. Unmentioned mouse buttons are assumed to have a 'released' state." },
+                { "name": "pressedButton", "$ref": "MouseButton", "optional": true, "description": "For 'mouse' input sources, specifies which mouse button has a 'pressed' state. Unmentioned mouse buttons are assumed to have a 'released' state. For 'touch' input sources, passing MouseButton::Left denotes a touch-down state." },
                 { "name": "origin", "$ref": "MouseMoveOrigin", "optional": true, "description": "For 'mouse' input sources, specifies the origin type of a mouse move transition. Defaults to 'Viewport' if omitted."},
                 { "name": "nodeHandle", "$ref": "NodeHandle", "optional": true, "description": "The handle of the element to use as origin when origin type is 'Element'."},
                 { "name": "location", "$ref": "Point", "optional": true, "description": "For 'mouse' or 'touch' input sources, specifies a location in view coordinates to which the input source should transition. Transitioning to this state may interpolate intemediate input source states to better simulate real user movements and gestures." },

Modified: trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.cpp (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.cpp	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.cpp	2019-01-27 18:36:11 UTC (rev 240554)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018, 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
@@ -26,6 +26,8 @@
 #include "config.h"
 #include "SimulatedInputDispatcher.h"
 
+#if ENABLE(WEBDRIVER_ACTIONS_API)
+
 #include "AutomationProtocolObjects.h"
 #include "Logging.h"
 #include "WebAutomationSession.h"
@@ -259,6 +261,9 @@
         eventDispatchFinished(WTF::nullopt);
         break;
     case SimulatedInputSourceType::Mouse: {
+#if !ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
+        RELEASE_ASSERT_NOT_REACHED();
+#else
         resolveLocation(a.location.valueOr(WebCore::IntPoint()), b.location, b.origin.valueOr(MouseMoveOrigin::Viewport), b.nodeHandle, [this, &a, &b, eventDispatchFinished = WTFMove(eventDispatchFinished)](Optional<WebCore::IntPoint> location, Optional<AutomationCommandError> error) mutable {
             if (error) {
                 eventDispatchFinished(error);
@@ -270,25 +275,56 @@
             if (!a.pressedMouseButton && b.pressedMouseButton) {
 #if !LOG_DISABLED
                 String mouseButtonName = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(b.pressedMouseButton.value());
-                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MouseDown[button=%s] for transition to %d.%d", this, mouseButtonName.utf8().data(), m_keyframeIndex, m_inputSourceStateIndex);
+                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MouseDown[button=%s] @ (%d, %d) for transition to %d.%d", this, mouseButtonName.utf8().data(), b.location.value().x(), b.location.value().y(), m_keyframeIndex, m_inputSourceStateIndex);
 #endif
                 m_client.simulateMouseInteraction(m_page, MouseInteraction::Down, b.pressedMouseButton.value(), b.location.value(), WTFMove(eventDispatchFinished));
             } else if (a.pressedMouseButton && !b.pressedMouseButton) {
 #if !LOG_DISABLED
                 String mouseButtonName = Inspector::Protocol::AutomationHelpers::getEnumConstantValue(a.pressedMouseButton.value());
-                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MouseUp[button=%s] for transition to %d.%d", this, mouseButtonName.utf8().data(), m_keyframeIndex, m_inputSourceStateIndex);
+                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MouseUp[button=%s] @ (%d, %d) for transition to %d.%d", this, mouseButtonName.utf8().data(), a.location.value().x(), a.location.value().y(), m_keyframeIndex, m_inputSourceStateIndex);
 #endif
                 m_client.simulateMouseInteraction(m_page, MouseInteraction::Up, a.pressedMouseButton.value(), b.location.value(), WTFMove(eventDispatchFinished));
             } else if (a.location != b.location) {
-                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MouseMove for transition to %d.%d", this, m_keyframeIndex, m_inputSourceStateIndex);
+                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MouseMove from (%d, %d) to (%d, %d) for transition to %d.%d", this, a.location.value().x(), a.location.value().y(), b.location.value().x(), b.location.value().y(), m_keyframeIndex, m_inputSourceStateIndex);
                 // FIXME: This does not interpolate mousemoves per the "perform a pointer move" algorithm (§17.4 Dispatching Actions).
                 m_client.simulateMouseInteraction(m_page, MouseInteraction::Move, b.pressedMouseButton.valueOr(MouseButton::NoButton), b.location.value(), WTFMove(eventDispatchFinished));
             } else
                 eventDispatchFinished(WTF::nullopt);
         });
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
         break;
     }
+    case SimulatedInputSourceType::Touch: {
+#if !ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+        RELEASE_ASSERT_NOT_REACHED();
+#else
+        resolveLocation(a.location.valueOr(WebCore::IntPoint()), b.location, b.origin.valueOr(MouseMoveOrigin::Viewport), b.nodeHandle, [this, &a, &b, eventDispatchFinished = WTFMove(eventDispatchFinished)](Optional<WebCore::IntPoint> location, Optional<AutomationCommandError> error) mutable {
+            if (error) {
+                eventDispatchFinished(error);
+                return;
+            }
+            RELEASE_ASSERT(location);
+            b.location = location;
+            // The "dispatch a pointer{Down,Up,Move} action" algorithms (§17.4 Dispatching Actions).
+            if (!a.pressedMouseButton && b.pressedMouseButton) {
+                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating TouchDown @ (%d, %d) for transition to %d.%d", this, b.location.value().x(), b.location.value().y(), m_keyframeIndex, m_inputSourceStateIndex);
+                m_client.simulateTouchInteraction(m_page, TouchInteraction::TouchDown, b.location.value(), WTF::nullopt, WTFMove(eventDispatchFinished));
+            } else if (a.pressedMouseButton && !b.pressedMouseButton) {
+                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating LiftUp @ (%d, %d) for transition to %d.%d", this, a.location.value().x(), a.location.value().y(), m_keyframeIndex, m_inputSourceStateIndex);
+                m_client.simulateTouchInteraction(m_page, TouchInteraction::LiftUp, b.location.value(), WTF::nullopt, WTFMove(eventDispatchFinished));
+            } else if (a.location != b.location) {
+                LOG(Automation, "SimulatedInputDispatcher[%p]: simulating MoveTo from (%d, %d) to (%d, %d) for transition to %d.%d", this, a.location.value().x(), a.location.value().y(), b.location.value().x(), b.location.value().y(), m_keyframeIndex, m_inputSourceStateIndex);
+                m_client.simulateTouchInteraction(m_page, TouchInteraction::MoveTo, b.location.value(), a.duration.valueOr(0_s), WTFMove(eventDispatchFinished));
+            } else
+                eventDispatchFinished(WTF::nullopt);
+        });
+#endif // !ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+        break;
+    }
     case SimulatedInputSourceType::Keyboard:
+#if !ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
+        RELEASE_ASSERT_NOT_REACHED();
+#else
         // The "dispatch a key{Down,Up} action" algorithms (§17.4 Dispatching Actions).
         if (!a.pressedCharKey && b.pressedCharKey) {
             LOG(Automation, "SimulatedInputDispatcher[%p]: simulating KeyPress[key=%c] for transition to %d.%d", this, b.pressedCharKey.value(), m_keyframeIndex, m_inputSourceStateIndex);
@@ -327,12 +363,8 @@
             }
         } else
             eventDispatchFinished(WTF::nullopt);
+#endif // !ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
         break;
-    case SimulatedInputSourceType::Touch:
-        // Not supported yet.
-        ASSERT_NOT_REACHED();
-        eventDispatchFinished(AUTOMATION_COMMAND_ERROR_WITH_NAME(NotImplemented));
-        break;
     }
 }
 
@@ -387,3 +419,5 @@
 }
 
 } // namespace Webkit
+
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)

Modified: trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.h (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.h	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/SimulatedInputDispatcher.h	2019-01-27 18:36:11 UTC (rev 240554)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 Apple Inc. All rights reserved.
+ * Copyright (C) 2018, 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
@@ -25,6 +25,8 @@
 
 #pragma once
 
+#if ENABLE(WEBDRIVER_ACTIONS_API)
+
 #include "WebEvent.h"
 #include <wtf/CompletionHandler.h>
 #include <wtf/HashSet.h>
@@ -65,6 +67,12 @@
     Touch,
 };
 
+enum class TouchInteraction {
+    TouchDown,
+    MoveTo,
+    LiftUp,
+};
+
 struct SimulatedInputSourceState {
     Optional<CharKey> pressedCharKey;
     VirtualKeySet pressedVirtualKeys;
@@ -115,8 +123,15 @@
     class Client {
     public:
         virtual ~Client() { }
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
         virtual void simulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, AutomationCompletionHandler&&) = 0;
+#endif
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+        virtual void simulateTouchInteraction(WebPageProxy&, TouchInteraction, const WebCore::IntPoint& locationInView, Optional<Seconds> duration, AutomationCompletionHandler&&) = 0;
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
         virtual void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&, AutomationCompletionHandler&&) = 0;
+#endif
         virtual void viewportInViewCenterPointOfElement(WebPageProxy&, uint64_t frameID, const String& nodeHandle, Function<void (Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&&) = 0;
     };
 
@@ -167,3 +182,5 @@
 };
 
 } // namespace WebKit
+
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)

Modified: trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp	2019-01-27 18:36:11 UTC (rev 240554)
@@ -78,10 +78,19 @@
     , m_domainNotifier(std::make_unique<AutomationFrontendDispatcher>(m_frontendRouter))
     , m_loadTimer(RunLoop::main(), this, &WebAutomationSession::loadTimerFired)
 {
+#if ENABLE(WEBDRIVER_ACTIONS_API)
     // Set up canonical input sources to be used for 'performInteractionSequence' and 'cancelInteractionSequence'.
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+    m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Touch));
+#endif
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Mouse));
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Keyboard));
+#endif
     m_inputSources.add(SimulatedInputSource::create(SimulatedInputSourceType::Null));
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
 }
 
 WebAutomationSession::~WebAutomationSession()
@@ -139,15 +148,19 @@
 
 void WebAutomationSession::terminate()
 {
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     for (auto& identifier : copyToVector(m_pendingKeyboardEventsFlushedCallbacksPerPage.keys())) {
         auto callback = m_pendingKeyboardEventsFlushedCallbacksPerPage.take(identifier);
         callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(InternalError));
     }
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     for (auto& identifier : copyToVector(m_pendingMouseEventsFlushedCallbacksPerPage.keys())) {
         auto callback = m_pendingMouseEventsFlushedCallbacksPerPage.take(identifier);
         callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(InternalError));
     }
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 
 #if ENABLE(REMOTE_INSPECTOR)
     if (Inspector::FrontendChannel* channel = m_remoteChannel) {
@@ -645,7 +658,8 @@
                 callback->sendFailure(unexpectedAlertOpenError);
             }
         }
-        
+
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
         if (!m_pendingMouseEventsFlushedCallbacksPerPage.isEmpty()) {
             for (auto key : copyToVector(m_pendingMouseEventsFlushedCallbacksPerPage.keys())) {
                 auto callback = m_pendingMouseEventsFlushedCallbacksPerPage.take(key);
@@ -652,7 +666,9 @@
                 callback(WTF::nullopt);
             }
         }
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
         if (!m_pendingKeyboardEventsFlushedCallbacksPerPage.isEmpty()) {
             for (auto key : copyToVector(m_pendingKeyboardEventsFlushedCallbacksPerPage.keys())) {
                 auto callback = m_pendingKeyboardEventsFlushedCallbacksPerPage.take(key);
@@ -659,6 +675,7 @@
                 callback(WTF::nullopt);
             }
         }
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     });
 }
     
@@ -776,14 +793,22 @@
 
 void WebAutomationSession::mouseEventsFlushedForPage(const WebPageProxy& page)
 {
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     if (auto callback = m_pendingMouseEventsFlushedCallbacksPerPage.take(page.pageID()))
         callback(WTF::nullopt);
+#else
+    UNUSED_PARAM(page);
+#endif
 }
 
 void WebAutomationSession::keyboardEventsFlushedForPage(const WebPageProxy& page)
 {
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     if (auto callback = m_pendingKeyboardEventsFlushedCallbacksPerPage.take(page.pageID()))
         callback(WTF::nullopt);
+#else
+    UNUSED_PARAM(page);
+#endif
 }
 
 void WebAutomationSession::willClosePage(const WebPageProxy& page)
@@ -793,15 +818,21 @@
 
     // Cancel pending interactions on this page. By providing an error, this will cause subsequent
     // actions to be aborted and the SimulatedInputDispatcher::run() call will unwind and fail.
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     if (auto callback = m_pendingMouseEventsFlushedCallbacksPerPage.take(page.pageID()))
         callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(WindowNotFound));
-    if (auto callback = m_pendingMouseEventsFlushedCallbacksPerPage.take(page.pageID()))
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
+    if (auto callback = m_pendingKeyboardEventsFlushedCallbacksPerPage.take(page.pageID()))
         callback(AUTOMATION_COMMAND_ERROR_WITH_NAME(WindowNotFound));
+#endif
 
+#if ENABLE(WEBDRIVER_ACTIONS_API)
     // Then tell the input dispatcher to cancel so timers are stopped, and let it go out of scope.
     Optional<Ref<SimulatedInputDispatcher>> inputDispatcher = m_inputDispatchersByPage.take(page.pageID());
     if (inputDispatcher.hasValue())
         inputDispatcher.value()->cancel();
+#endif
 }
 
 static bool fileCanBeAcceptedForUpload(const String& filename, const HashSet<String>& allowedMIMETypes, const HashSet<String>& allowedFileExtensions)
@@ -1434,14 +1465,22 @@
 
 bool WebAutomationSession::isSimulatingUserInteraction() const
 {
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     if (!m_pendingMouseEventsFlushedCallbacksPerPage.isEmpty())
         return true;
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     if (!m_pendingKeyboardEventsFlushedCallbacksPerPage.isEmpty())
         return true;
-
+#endif
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+    if (m_simulatingTouchInteraction)
+        return true;
+#endif
     return false;
 }
 
+#if ENABLE(WEBDRIVER_ACTIONS_API)
 SimulatedInputDispatcher& WebAutomationSession::inputDispatcherForPage(WebPageProxy& page)
 {
     return m_inputDispatchersByPage.ensure(page.pageID(), [&] {
@@ -1460,7 +1499,7 @@
     return nullptr;
 }
 
-// SimulatedInputDispatcher::Client API
+// MARK: SimulatedInputDispatcher::Client API
 void WebAutomationSession::viewportInViewCenterPointOfElement(WebPageProxy& page, uint64_t frameID, const String& nodeHandle, Function<void (Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&& completionHandler)
 {
     // Start at 3 and use only odd numbers to not conflict with m_nextComputeElementLayoutCallbackID.
@@ -1470,6 +1509,7 @@
     page.process().send(Messages::WebAutomationSessionProxy::ComputeElementLayout(page.pageID(), frameID, nodeHandle, false, CoordinateSystem::LayoutViewport, callbackID), 0);
 }
 
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 void WebAutomationSession::simulateMouseInteraction(WebPageProxy& page, MouseInteraction interaction, WebMouseEvent::Button mouseButton, const WebCore::IntPoint& locationInViewport, CompletionHandler<void(Optional<AutomationCommandError>)>&& completionHandler)
 {
     WebCore::IntPoint locationInView = WebCore::IntPoint(locationInViewport.x(), locationInViewport.y() + page.topContentInset());
@@ -1502,7 +1542,27 @@
         // Otherwise, wait for mouseEventsFlushedCallback to run when all events are handled.
     });
 }
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+void WebAutomationSession::simulateTouchInteraction(WebPageProxy& page, TouchInteraction interaction, const WebCore::IntPoint& locationInViewport, Optional<Seconds> duration, CompletionHandler<void(Optional<AutomationCommandError>)>&& completionHandler)
+{
+#if PLATFORM(IOS_FAMILY)
+    if (!page.unobscuredContentRect().contains(locationInViewport)) {
+        completionHandler(AUTOMATION_COMMAND_ERROR_WITH_NAME(TargetOutOfBounds));
+        return;
+    }
+#endif
+
+    m_simulatingTouchInteraction = true;
+    platformSimulateTouchInteraction(page, interaction, locationInViewport, duration, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](Optional<AutomationCommandError> error) mutable {
+        m_simulatingTouchInteraction = false;
+        completionHandler(error);
+    });
+}
+#endif // ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 void WebAutomationSession::simulateKeyboardInteraction(WebPageProxy& page, KeyboardInteraction interaction, WTF::Variant<VirtualKey, CharKey>&& key, CompletionHandler<void(Optional<AutomationCommandError>)>&& completionHandler)
 {
     // Bridge the flushed callback to our command's completion handler.
@@ -1526,8 +1586,10 @@
 
     // Otherwise, wait for keyboardEventsFlushedCallback to run when all events are handled.
 }
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
 
-#if USE(APPKIT) || PLATFORM(GTK) || PLATFORM(WPE)
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 static WebEvent::Modifiers protocolModifierToWebEventModifier(Inspector::Protocol::Automation::KeyModifier modifier)
 {
     switch (modifier) {
@@ -1545,7 +1607,9 @@
 
     RELEASE_ASSERT_NOT_REACHED();
 }
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 
+#if ENABLE(WEBDRIVER_ACTIONS_API)
 static WebMouseEvent::Button protocolMouseButtonToWebMouseEventButton(Inspector::Protocol::Automation::MouseButton button)
 {
     switch (button) {
@@ -1561,11 +1625,11 @@
 
     RELEASE_ASSERT_NOT_REACHED();
 }
-#endif // USE(APPKIT) || PLATFORM(GTK) || PLATFORM(WPE)
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
 
 void WebAutomationSession::performMouseInteraction(const String& handle, const JSON::Object& requestedPositionObject, const String& mouseButtonString, const String& mouseInteractionString, const JSON::Array& keyModifierStrings, Ref<PerformMouseInteractionCallback>&& callback)
 {
-#if !USE(APPKIT) && !PLATFORM(GTK) && !PLATFORM(WPE)
+#if !ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     ASYNC_FAIL_WITH_PREDEFINED_ERROR(NotImplemented);
 #else
     WebPageProxy* page = webPageProxyForHandle(handle);
@@ -1634,12 +1698,12 @@
             callbackToCancel(WTF::nullopt);
         }
     });
-#endif // USE(APPKIT) || PLATFORM(GTK) || PLATFORM(WPE)
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 }
 
 void WebAutomationSession::performKeyboardInteractions(const String& handle, const JSON::Array& interactions, Ref<PerformKeyboardInteractionsCallback>&& callback)
 {
-#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE)
+#if !ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     ASYNC_FAIL_WITH_PREDEFINED_ERROR(NotImplemented);
 #else
     WebPageProxy* page = webPageProxyForHandle(handle);
@@ -1716,10 +1780,10 @@
 
     for (auto& action : actionsToPerform)
         action();
-#endif // PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 }
 
-#if USE(APPKIT) || PLATFORM(GTK) || PLATFORM(WPE)
+#if ENABLE(WEBDRIVER_ACTIONS_API)
 static SimulatedInputSourceType simulatedInputSourceTypeFromProtocolSourceType(Inspector::Protocol::Automation::InputSourceType protocolType)
 {
     switch (protocolType) {
@@ -1735,13 +1799,13 @@
 
     RELEASE_ASSERT_NOT_REACHED();
 }
-#endif // USE(APPKIT) || PLATFORM(GTK) || PLATFORM(WPE)
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
 
 void WebAutomationSession::performInteractionSequence(const String& handle, const String* optionalFrameHandle, const JSON::Array& inputSources, const JSON::Array& steps, Ref<WebAutomationSession::PerformInteractionSequenceCallback>&& callback)
 {
     // This command implements WebKit support for §17.5 Perform Actions.
 
-#if !USE(APPKIT) && !PLATFORM(GTK) && !PLATFORM(WPE)
+#if !ENABLE(WEBDRIVER_ACTIONS_API)
     ASYNC_FAIL_WITH_PREDEFINED_ERROR(NotImplemented);
 #else
     WebPageProxy* page = webPageProxyForHandle(handle);
@@ -1778,9 +1842,26 @@
             ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "An input source in the 'inputSources' parameter has an invalid 'sourceType'.");
 
         SimulatedInputSourceType inputSourceType = simulatedInputSourceTypeFromProtocolSourceType(*parsedInputSourceType);
+
+        // Note: iOS does not support mouse input sources, and other platforms do not support touch input sources.
+        // If a mismatch happens, alias to the supported input source. This works because both Mouse and Touch input sources
+        // use a MouseButton to indicate the result of interacting (down/up/move), which can be interpreted for touch or mouse.
+#if !ENABLE(WEBDRIVER_MOUSE_INTERACTIONS) && ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+        if (inputSourceType == SimulatedInputSourceType::Mouse)
+            inputSourceType = SimulatedInputSourceType::Touch;
+#endif
+#if !ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
+        if (inputSourceType == SimulatedInputSourceType::Mouse)
+            ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(NotImplemented, "Mouse input sources are not yet supported.");
+#endif
+#if !ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
         if (inputSourceType == SimulatedInputSourceType::Touch)
             ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(NotImplemented, "Touch input sources are not yet supported.");
-
+#endif
+#if !ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
+        if (inputSourceType == SimulatedInputSourceType::Keyboard)
+            ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(NotImplemented, "Keyboard input sources are not yet supported.");
+#endif
         if (typeToSourceIdMap.contains(inputSourceType))
             ASYNC_FAIL_WITH_PREDEFINED_ERROR_AND_DETAILS(InvalidParameter, "Two input sources with the same type were specified.");
         if (sourceIdToInputSourceMap.contains(sourceId))
@@ -1892,7 +1973,7 @@
         else
             callback->sendSuccess();
     });
-#endif // PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
 }
 
 void WebAutomationSession::cancelInteractionSequence(const String& handle, const String* optionalFrameHandle, Ref<CancelInteractionSequenceCallback>&& callback)
@@ -1899,7 +1980,7 @@
 {
     // This command implements WebKit support for §17.6 Release Actions.
 
-#if !USE(APPKIT) && !PLATFORM(GTK) && !PLATFORM(WPE)
+#if !ENABLE(WEBDRIVER_ACTIONS_API)
     ASYNC_FAIL_WITH_PREDEFINED_ERROR(NotImplemented);
 #else
     WebPageProxy* page = webPageProxyForHandle(handle);
@@ -1920,7 +2001,7 @@
         else
             callback->sendSuccess();
     });
-#endif // PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
 }
 
 void WebAutomationSession::takeScreenshot(const String& handle, const String* optionalFrameHandle, const String* optionalNodeHandle, const bool* optionalScrollIntoViewIfNeeded, const bool* optionalClipToViewport, Ref<TakeScreenshotCallback>&& callback)
@@ -1961,22 +2042,6 @@
     callback->sendSuccess(base64EncodedData.value());
 }
 
-// Platform-dependent Implementation Stubs.
-
-#if !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(WPE)
-void WebAutomationSession::platformSimulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint&, WebEvent::Modifiers)
-{
-}
-#endif // !PLATFORM(MAC) && !PLATFORM(GTK) && !PLATFORM(WPE)
-
-#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE)
-
-
-void WebAutomationSession::platformSimulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&)
-{
-}
-#endif // !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE)
-
 #if !PLATFORM(COCOA) && !USE(CAIRO)
 Optional<String> WebAutomationSession::platformGetBase64EncodedPNGData(const ShareableBitmap::Handle&)
 {

Modified: trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/WebAutomationSession.h	2019-01-27 18:36:11 UTC (rev 240554)
@@ -99,7 +99,9 @@
     , public Inspector::RemoteAutomationTarget
 #endif
     , public Inspector::AutomationBackendDispatcherHandler
+#if ENABLE(WEBDRIVER_ACTIONS_API)
     , public SimulatedInputDispatcher::Client
+#endif
 {
 public:
     WebAutomationSession();
@@ -135,11 +137,22 @@
 #endif
     void terminate();
 
+#if ENABLE(WEBDRIVER_ACTIONS_API)
+
     // SimulatedInputDispatcher::Client API
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     void simulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, AutomationCompletionHandler&&) final;
+#endif
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+    void simulateTouchInteraction(WebPageProxy&, TouchInteraction, const WebCore::IntPoint& locationInView, Optional<Seconds> duration, AutomationCompletionHandler&&) final;
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&, AutomationCompletionHandler&&) final;
+#endif
     void viewportInViewCenterPointOfElement(WebPageProxy&, uint64_t frameID, const String& nodeHandle, Function<void (Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&&) final;
 
+#endif // ENABLE(WEBDRIVER_ACTIONS_API)
+
     // Inspector::AutomationBackendDispatcherHandler API
     // NOTE: the set of declarations included in this interface depend on the "platform" property in Automation.json
     // and the --platform argument passed to the protocol bindings generator.
@@ -188,8 +201,10 @@
 
     // Event Simulation Support.
     bool isSimulatingUserInteraction() const;
+#if ENABLE(WEBDRIVER_ACTIONS_API)
     SimulatedInputDispatcher& inputDispatcherForPage(WebPageProxy&);
     SimulatedInputSource* inputSourceForType(SimulatedInputSourceType) const;
+#endif
 
 #if PLATFORM(MAC)
     bool wasEventSynthesizedForAutomation(NSEvent *);
@@ -231,11 +246,20 @@
     void didDeleteCookie(uint64_t callbackID, const String& errorType);
 
     // Platform-dependent implementations.
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     void platformSimulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, WebEvent::Modifiers keyModifiers);
+#endif
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+    // Simulates a single touch point being pressed, moved, and released.
+    void platformSimulateTouchInteraction(WebPageProxy&, TouchInteraction, const WebCore::IntPoint& locationInViewport, Optional<Seconds> duration, AutomationCompletionHandler&&);
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     // Simulates a single virtual or char key being pressed/released, such as 'a', Control, F-keys, Numpad keys, etc. as allowed by the protocol.
     void platformSimulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&);
     // Simulates key presses to produce the codepoints in a string. One or more code points are delivered atomically at grapheme cluster boundaries.
     void platformSimulateKeySequence(WebPageProxy&, const String&);
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
+
     // Get base64 encoded PNG data from a bitmap.
     Optional<String> platformGetBase64EncodedPNGData(const ShareableBitmap::Handle&);
 
@@ -267,8 +291,12 @@
     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame;
     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame;
     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingInspectorCallbacksPerPage;
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
     HashMap<uint64_t, Function<void(Optional<AutomationCommandError>)>> m_pendingKeyboardEventsFlushedCallbacksPerPage;
+#endif
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
     HashMap<uint64_t, Function<void(Optional<AutomationCommandError>)>> m_pendingMouseEventsFlushedCallbacksPerPage;
+#endif
 
     uint64_t m_nextEvaluateJavaScriptCallbackID { 1 };
     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>> m_evaluateJavaScriptFunctionCallbacks;
@@ -310,14 +338,20 @@
 
     bool m_permissionForGetUserMedia { true };
 
-    // Keep track of currently active modifiers across multiple keystrokes.
-    // Most platforms do not track current modifiers from synthesized events.
-    unsigned m_currentModifiers { 0 };
-
+#if ENABLE(WEBDRIVER_ACTIONS_API)
     // SimulatedInputDispatcher APIs take a set of input sources. We also intern these
     // so that previous input source state is used as initial state for later commands.
     HashSet<Ref<SimulatedInputSource>> m_inputSources;
     HashMap<uint64_t, Ref<SimulatedInputDispatcher>> m_inputDispatchersByPage;
+#endif
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
+    // Keep track of currently active modifiers across multiple keystrokes.
+    // Most platforms do not track current modifiers from synthesized events.
+    unsigned m_currentModifiers { 0 };
+#endif
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+    bool m_simulatingTouchInteraction { false };
+#endif
 
 #if ENABLE(REMOTE_INSPECTOR)
     Inspector::FrontendChannel* m_remoteChannel { nullptr };

Modified: trunk/Source/WebKit/UIProcess/Automation/ios/WebAutomationSessionIOS.mm (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/ios/WebAutomationSessionIOS.mm	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/ios/WebAutomationSessionIOS.mm	2019-01-27 18:36:11 UTC (rev 240554)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2017, 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
@@ -31,9 +31,11 @@
 #import "NativeWebKeyboardEvent.h"
 #import "WebAutomationSessionMacros.h"
 #import "WebPageProxy.h"
+#import "_WKTouchEventGenerator.h"
 #import <WebCore/KeyEventCodesIOS.h>
 #import <WebCore/NotImplemented.h>
 #import <WebCore/WebEvent.h>
+#import <wtf/BlockPtr.h>
 
 namespace WebKit {
 using namespace WebCore;
@@ -64,6 +66,7 @@
 
 #pragma mark Commands for Platform: 'iOS'
 
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 void WebAutomationSession::platformSimulateKeyboardInteraction(WebPageProxy& page, KeyboardInteraction interaction, WTF::Variant<VirtualKey, CharKey>&& key)
 {
     // The modifiers changed by the virtual key when it is pressed or released.
@@ -169,7 +172,32 @@
 
     sendSynthesizedEventsToPage(page, eventsToBeSent.get());
 }
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 
+#if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+void WebAutomationSession::platformSimulateTouchInteraction(WebPageProxy& page, TouchInteraction interaction, const WebCore::IntPoint& locationInViewport, Optional<Seconds> duration, AutomationCompletionHandler&& completionHandler)
+{
+    WebCore::IntPoint locationOnScreen = page.syncRootViewToScreen(IntRect(locationInViewport, IntSize())).location();
+    _WKTouchEventGenerator *generator = [_WKTouchEventGenerator sharedTouchEventGenerator];
+
+    auto interactionFinished = makeBlockPtr([completionHandler = WTFMove(completionHandler)] () mutable {
+        completionHandler(WTF::nullopt);
+    });
+    
+    switch (interaction) {
+    case TouchInteraction::TouchDown:
+        [generator touchDown:locationOnScreen completionBlock:interactionFinished.get()];
+        break;
+    case TouchInteraction::LiftUp:
+        [generator liftUp:locationOnScreen completionBlock:interactionFinished.get()];
+        break;
+    case TouchInteraction::MoveTo:
+        [generator moveToPoint:locationOnScreen duration:duration.valueOr(0_s).seconds() completionBlock:interactionFinished.get()];
+        break;
+    }
+}
+#endif // ENABLE(WEBDRIVER_TOUCH_INTERACTIONS)
+
 } // namespace WebKit
 
 #endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Source/WebKit/UIProcess/Automation/mac/WebAutomationSessionMac.mm (240553 => 240554)


--- trunk/Source/WebKit/UIProcess/Automation/mac/WebAutomationSessionMac.mm	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/UIProcess/Automation/mac/WebAutomationSessionMac.mm	2019-01-27 18:36:11 UTC (rev 240554)
@@ -120,6 +120,7 @@
 
 #pragma mark Platform-dependent Implementations
 
+#if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 void WebAutomationSession::platformSimulateMouseInteraction(WebPageProxy& page, MouseInteraction interaction, WebMouseEvent::Button button, const WebCore::IntPoint& locationInView, WebEvent::Modifiers keyModifiers)
 {
     IntRect windowRect;
@@ -210,7 +211,9 @@
 
     sendSynthesizedEventsToPage(page, eventsToBeSent.get());
 }
+#endif // ENABLE(WEBDRIVER_MOUSE_INTERACTIONS)
 
+#if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 static bool virtualKeyHasStickyModifier(VirtualKey key)
 {
     // Returns whether the key's modifier flags should affect other events while pressed down.
@@ -718,6 +721,7 @@
 
     sendSynthesizedEventsToPage(page, eventsToBeSent.get());
 }
+#endif // ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS)
 
 } // namespace WebKit
 

Added: trunk/Source/WebKit/UIProcess/_WKTouchEventGenerator.h (0 => 240554)


--- trunk/Source/WebKit/UIProcess/_WKTouchEventGenerator.h	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/_WKTouchEventGenerator.h	2019-01-27 18:36:11 UTC (rev 240554)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015, 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 TARGET_OS_IPHONE
+
+#import <CoreGraphics/CGGeometry.h>
+#import <WebKit/WKFoundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef struct __IOHIDEvent * IOHIDEventRef;
+
+WK_CLASS_AVAILABLE(ios(WK_IOS_TBA))
+@interface _WKTouchEventGenerator : NSObject
++ (_WKTouchEventGenerator *)sharedTouchEventGenerator;
+
+// The 'location' parameter is in screen coordinates, as used by IOHIDEvent.
+- (void)touchDown:(CGPoint)location completionBlock:(void (^)(void))completionBlock;
+- (void)liftUp:(CGPoint)location completionBlock:(void (^)(void))completionBlock;
+- (void)moveToPoint:(CGPoint)location duration:(NSTimeInterval)seconds completionBlock:(void (^)(void))completionBlock;
+
+// Clients must call this method whenever a HID event is delivered to the UIApplication.
+// It is used to detect when all synthesized touch events have been successfully delivered.
+- (void)receivedHIDEvent:(IOHIDEventRef)event;
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // TARGET_OS_IPHONE

Added: trunk/Source/WebKit/UIProcess/_WKTouchEventGenerator.mm (0 => 240554)


--- trunk/Source/WebKit/UIProcess/_WKTouchEventGenerator.mm	                        (rev 0)
+++ trunk/Source/WebKit/UIProcess/_WKTouchEventGenerator.mm	2019-01-27 18:36:11 UTC (rev 240554)
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2015, 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 "_WKTouchEventGenerator.h"
+
+#if PLATFORM(IOS_FAMILY)
+
+#import "UIKitSPI.h"
+#import <mach/mach_time.h>
+#import <pal/spi/cocoa/IOKitSPI.h>
+#import <wtf/Assertions.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/SoftLinking.h>
+
+SOFT_LINK_PRIVATE_FRAMEWORK(BackBoardServices)
+SOFT_LINK(BackBoardServices, BKSHIDEventSetDigitizerInfo, void, (IOHIDEventRef digitizerEvent, uint32_t contextID, uint8_t systemGestureisPossible, uint8_t isSystemGestureStateChangeEvent, CFStringRef displayUUID, CFTimeInterval initialTouchTimestamp, float maxForce), (digitizerEvent, contextID, systemGestureisPossible, isSystemGestureStateChangeEvent, displayUUID, initialTouchTimestamp, maxForce));
+
+static const NSTimeInterval fingerMoveInterval = 0.016;
+static const IOHIDFloat defaultMajorRadius = 5;
+static const IOHIDFloat defaultPathPressure = 0;
+static const long nanosecondsPerSecond = 1e9;
+
+NSUInteger const HIDMaxTouchCount = 5;
+
+static int fingerIdentifiers[HIDMaxTouchCount] = { 2, 3, 4, 5, 1 };
+
+typedef enum {
+    HandEventNull,
+    HandEventTouched,
+    HandEventMoved,
+    HandEventChordChanged,
+    HandEventLifted,
+    HandEventCanceled,
+} HandEventType;
+
+typedef struct {
+    int identifier;
+    CGPoint point;
+    IOHIDFloat pathMajorRadius;
+    IOHIDFloat pathPressure;
+    UInt8 pathProximity;
+} SyntheticEventDigitizerInfo;
+
+static CFTimeInterval secondsSinceAbsoluteTime(CFAbsoluteTime startTime)
+{
+    return CFAbsoluteTimeGetCurrent() - startTime;
+}
+
+static double simpleCurveInterpolation(double a, double b, double t)
+{
+    return a + (b - a) * sin(sin(t * M_PI / 2) * t * M_PI / 2);
+}
+
+static CGPoint calculateNextCurveLocation(CGPoint a, CGPoint b, CFTimeInterval t)
+{
+    return CGPointMake(simpleCurveInterpolation(a.x, b.x, t), simpleCurveInterpolation(a.y, b.y, t));
+}
+
+static void delayBetweenMove(int eventIndex, double elapsed)
+{
+    // Delay next event until expected elapsed time.
+    double delay = (eventIndex * fingerMoveInterval) - elapsed;
+    if (delay > 0) {
+        struct timespec moveDelay = { 0, static_cast<long>(delay * nanosecondsPerSecond) };
+        nanosleep(&moveDelay, NULL);
+    }   
+}
+
+// NOTE: this event synthesizer is derived from WebKitTestRunner code.
+// Compared to that version, this lacks support for stylus event simulation,
+// event stream, and only single touches are exposed via the touch/lift/move method calls.
+@interface _WKTouchEventGenerator ()
+@property (nonatomic, strong) NSMutableDictionary *eventCallbacks;
+@end
+
+@implementation _WKTouchEventGenerator {
+    IOHIDEventSystemClientRef _ioSystemClient;
+    SyntheticEventDigitizerInfo _activePoints[HIDMaxTouchCount];
+    NSUInteger _activePointCount;
+}
+
++ (_WKTouchEventGenerator *)sharedTouchEventGenerator
+{
+    static _WKTouchEventGenerator *eventGenerator = [[_WKTouchEventGenerator alloc] init];
+    return eventGenerator;
+}
+
++ (CFIndex)nextEventCallbackID
+{
+    static CFIndex callbackID = 0;
+    return ++callbackID;
+}
+
+- (instancetype)init
+{
+    self = [super init];
+    if (!self)
+        return nil;
+
+    for (NSUInteger i = 0; i < HIDMaxTouchCount; ++i)
+        _activePoints[i].identifier = fingerIdentifiers[i];
+
+    _eventCallbacks = [[NSMutableDictionary alloc] init];
+
+    return self;
+}
+
+- (void)dealloc
+{
+  if (_ioSystemClient)
+        CFRelease(_ioSystemClient);
+
+    [_eventCallbacks release];
+    [super dealloc];
+}
+
+- (IOHIDEventRef)_createIOHIDEventType:(HandEventType)eventType
+{
+    BOOL isTouching = (eventType == HandEventTouched || eventType == HandEventMoved || eventType == HandEventChordChanged);
+
+    IOHIDDigitizerEventMask eventMask = kIOHIDDigitizerEventTouch;
+    if (eventType == HandEventMoved) {
+        eventMask &= ~kIOHIDDigitizerEventTouch;
+        eventMask |= kIOHIDDigitizerEventPosition;
+        eventMask |= kIOHIDDigitizerEventAttribute;
+    } else if (eventType == HandEventChordChanged) {
+        eventMask |= kIOHIDDigitizerEventPosition;
+        eventMask |= kIOHIDDigitizerEventAttribute;
+    } else if (eventType == HandEventTouched || eventType == HandEventCanceled || eventType == HandEventLifted)
+        eventMask |= kIOHIDDigitizerEventIdentity;
+
+    uint64_t machTime = mach_absolute_time();
+    RetainPtr<IOHIDEventRef> eventRef = adoptCF(IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, machTime,
+        kIOHIDDigitizerTransducerTypeHand,
+        0,
+        0,
+        eventMask,
+        0,
+        0, 0, 0,
+        0,
+        0,
+        0,
+        isTouching,
+        kIOHIDEventOptionNone));
+
+    IOHIDEventSetIntegerValue(eventRef.get(), kIOHIDEventFieldDigitizerIsDisplayIntegrated, 1);
+
+    for (NSUInteger i = 0; i < _activePointCount; ++i) {
+        SyntheticEventDigitizerInfo* pointInfo = &_activePoints[i];
+        if (eventType == HandEventTouched) {
+            if (!pointInfo->pathMajorRadius)
+                pointInfo->pathMajorRadius = defaultMajorRadius;
+            if (!pointInfo->pathPressure)
+                pointInfo->pathPressure = defaultPathPressure;
+            if (!pointInfo->pathProximity)
+                pointInfo->pathProximity = kGSEventPathInfoInTouch | kGSEventPathInfoInRange;
+        } else if (eventType == HandEventLifted || eventType == HandEventCanceled) {
+            pointInfo->pathMajorRadius = 0;
+            pointInfo->pathPressure = 0;
+            pointInfo->pathProximity = 0;
+        }
+
+        CGPoint point = pointInfo->point;
+        point = CGPointMake(roundf(point.x), roundf(point.y));
+        
+        RetainPtr<IOHIDEventRef> subEvent = adoptCF(IOHIDEventCreateDigitizerFingerEvent(kCFAllocatorDefault, machTime,
+            pointInfo->identifier,
+            pointInfo->identifier,
+            eventMask,
+            point.x, point.y, 0,
+            pointInfo->pathPressure,
+            0,
+            pointInfo->pathProximity & kGSEventPathInfoInRange,
+            pointInfo->pathProximity & kGSEventPathInfoInTouch,
+            kIOHIDEventOptionNone));
+
+        IOHIDEventSetFloatValue(subEvent.get(), kIOHIDEventFieldDigitizerMajorRadius, pointInfo->pathMajorRadius);
+        IOHIDEventSetFloatValue(subEvent.get(), kIOHIDEventFieldDigitizerMinorRadius, pointInfo->pathMajorRadius);
+
+        IOHIDEventAppendEvent(eventRef.get(), subEvent.get(), 0);
+    }
+
+    return eventRef.leakRef();
+}
+
+- (BOOL)_sendHIDEvent:(IOHIDEventRef)eventRef
+{
+    if (!_ioSystemClient)
+        _ioSystemClient = IOHIDEventSystemClientCreate(kCFAllocatorDefault);
+
+    if (eventRef) {
+        RetainPtr<IOHIDEventRef> strongEvent = eventRef;
+        dispatch_async(dispatch_get_main_queue(), ^{
+            uint32_t contextID = [UIApplication sharedApplication].keyWindow._contextId;
+            ASSERT(contextID);
+            BKSHIDEventSetDigitizerInfo(strongEvent.get(), contextID, false, false, NULL, 0, 0);
+            [[UIApplication sharedApplication] _enqueueHIDEvent:strongEvent.get()];
+        });
+    }
+    return YES;
+}
+
+- (BOOL)_sendMarkerHIDEventWithCompletionBlock:(void (^)(void))completionBlock
+{
+    auto callbackID = [_WKTouchEventGenerator nextEventCallbackID];
+    [_eventCallbacks setObject:Block_copy(completionBlock) forKey:@(callbackID)];
+
+    auto markerEvent = adoptCF(IOHIDEventCreateVendorDefinedEvent(kCFAllocatorDefault,
+        mach_absolute_time(),
+        kHIDPage_VendorDefinedStart + 100,
+        0,
+        1,
+        (uint8_t*)&callbackID,
+        sizeof(CFIndex),
+        kIOHIDEventOptionNone));
+    
+    if (markerEvent) {
+        dispatch_async(dispatch_get_main_queue(), [markerEvent = WTFMove(markerEvent)] {
+            auto contextID = [UIApplication sharedApplication].keyWindow._contextId;
+            ASSERT(contextID);
+            BKSHIDEventSetDigitizerInfo(markerEvent.get(), contextID, false, false, NULL, 0, 0);
+            [[UIApplication sharedApplication] _enqueueHIDEvent:markerEvent.get()];
+        });
+    }
+    return YES;
+}
+
+- (void)_updateTouchPoints:(CGPoint*)points count:(NSUInteger)count
+{
+    HandEventType handEventType;
+    
+    // The hand event type is based on previous state.
+    if (!_activePointCount)
+        handEventType = HandEventTouched;
+    else if (!count)
+        handEventType = HandEventLifted;
+    else if (count == _activePointCount)
+        handEventType = HandEventMoved;
+    else
+        handEventType = HandEventChordChanged;
+    
+    // Update previous count for next event.
+    _activePointCount = count;
+
+    // Update point locations.
+    for (NSUInteger i = 0; i < count; ++i)
+        _activePoints[i].point = points[i];
+    
+    RetainPtr<IOHIDEventRef> eventRef = adoptCF([self _createIOHIDEventType:handEventType]);
+    [self _sendHIDEvent:eventRef.get()];
+}
+
+- (void)touchDownAtPoints:(CGPoint*)locations touchCount:(NSUInteger)touchCount
+{
+    touchCount = std::min(touchCount, HIDMaxTouchCount);
+
+    _activePointCount = touchCount;
+
+    for (NSUInteger index = 0; index < touchCount; ++index)
+        _activePoints[index].point = locations[index];
+
+    RetainPtr<IOHIDEventRef> eventRef = adoptCF([self _createIOHIDEventType:HandEventTouched]);
+    [self _sendHIDEvent:eventRef.get()];
+}
+
+- (void)touchDown:(CGPoint)location touchCount:(NSUInteger)touchCount
+{
+    touchCount = std::min(touchCount, HIDMaxTouchCount);
+
+    CGPoint locations[touchCount];
+
+    for (NSUInteger index = 0; index < touchCount; ++index)
+        locations[index] = location;
+    
+    [self touchDownAtPoints:locations touchCount:touchCount];
+}
+
+- (void)touchDown:(CGPoint)location
+{
+    [self touchDownAtPoints:&location touchCount:1];
+}
+
+- (void)liftUpAtPoints:(CGPoint*)locations touchCount:(NSUInteger)touchCount
+{
+    touchCount = std::min(touchCount, HIDMaxTouchCount);
+    touchCount = std::min(touchCount, _activePointCount);
+
+    NSUInteger newPointCount = _activePointCount - touchCount;
+
+    for (NSUInteger index = 0; index < touchCount; ++index)
+        _activePoints[newPointCount + index].point = locations[index];
+    
+    RetainPtr<IOHIDEventRef> eventRef = adoptCF([self _createIOHIDEventType:HandEventLifted]);
+    [self _sendHIDEvent:eventRef.get()];
+    
+    _activePointCount = newPointCount;
+}
+
+- (void)liftUp:(CGPoint)location touchCount:(NSUInteger)touchCount
+{
+    touchCount = std::min(touchCount, HIDMaxTouchCount);
+
+    CGPoint locations[touchCount];
+
+    for (NSUInteger index = 0; index < touchCount; ++index)
+        locations[index] = location;
+    
+    [self liftUpAtPoints:locations touchCount:touchCount];
+}
+
+- (void)liftUp:(CGPoint)location
+{
+    [self liftUp:location touchCount:1];
+}
+
+- (void)moveToPoints:(CGPoint*)newLocations touchCount:(NSUInteger)touchCount duration:(NSTimeInterval)seconds
+{
+    touchCount = std::min(touchCount, HIDMaxTouchCount);
+
+    CGPoint startLocations[touchCount];
+    CGPoint nextLocations[touchCount];
+
+    CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
+    CFTimeInterval elapsed = 0;
+
+    int eventIndex = 0;
+    while (elapsed < (seconds - fingerMoveInterval)) {
+        elapsed = secondsSinceAbsoluteTime(startTime);
+        CFTimeInterval interval = elapsed / seconds;
+        
+        for (NSUInteger i = 0; i < touchCount; ++i) {
+            if (!eventIndex)
+                startLocations[i] = _activePoints[i].point;
+
+            nextLocations[i] = calculateNextCurveLocation(startLocations[i], newLocations[i], interval);
+        }
+        [self _updateTouchPoints:nextLocations count:touchCount];
+
+        delayBetweenMove(eventIndex++, elapsed);
+    }
+
+    [self _updateTouchPoints:newLocations count:touchCount];
+}
+
+- (void)touchDown:(CGPoint)location completionBlock:(void (^)(void))completionBlock
+{
+    [self touchDown:location touchCount:1];
+    [self _sendMarkerHIDEventWithCompletionBlock:completionBlock];
+}
+
+- (void)liftUp:(CGPoint)location completionBlock:(void (^)(void))completionBlock
+{
+    [self liftUp:location touchCount:1];
+    [self _sendMarkerHIDEventWithCompletionBlock:completionBlock];
+}
+
+- (void)moveToPoint:(CGPoint)location duration:(NSTimeInterval)seconds completionBlock:(void (^)(void))completionBlock
+{
+    CGPoint locations[1];
+    locations[0] = location;
+    [self moveToPoints:locations touchCount:1 duration:seconds];
+    [self _sendMarkerHIDEventWithCompletionBlock:completionBlock];
+}
+
+- (void)receivedHIDEvent:(IOHIDEventRef)event
+{
+    if (IOHIDEventGetType(event) != kIOHIDEventTypeVendorDefined)
+        return;
+
+    CFIndex callbackID = IOHIDEventGetIntegerValue(event, kIOHIDEventFieldVendorDefinedData);
+    NSNumber *key = @(callbackID);
+    void (^completionBlock)() = [_eventCallbacks objectForKey:key];
+    if (completionBlock) {
+        [_eventCallbacks removeObjectForKey:key];
+        completionBlock();
+        Block_release(completionBlock);
+    }
+}
+
+@end
+
+#endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (240553 => 240554)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2019-01-27 18:36:11 UTC (rev 240554)
@@ -1261,6 +1261,8 @@
 		99C81D5A1C20E7E2005C4C82 /* AutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D551C20DFBE005C4C82 /* AutomationClient.h */; };
 		99C81D5D1C21F38B005C4C82 /* APIAutomationClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 99C81D5B1C20E817005C4C82 /* APIAutomationClient.h */; };
 		99E714C51C124A0400665B3A /* _WKAutomationDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E714C11C1249E600665B3A /* _WKAutomationDelegate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		99E7189A21F79D9E0055E975 /* _WKTouchEventGenerator.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99E7189621F79D9D0055E975 /* _WKTouchEventGenerator.mm */; };
+		99E7189C21F79D9E0055E975 /* _WKTouchEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 99E7189821F79D9E0055E975 /* _WKTouchEventGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9FB5F395169E6A80002C25BF /* WKContextPrivateMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 9FB5F393169E6A80002C25BF /* WKContextPrivateMac.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		A102A7081EC0EEE900D81D82 /* com.macromedia.Flash Player ESR.plugin.sb in Copy Plug-in Sandbox Profiles */ = {isa = PBXBuildFile; fileRef = 7A5E39491D5BD8A700B4B7CE /* com.macromedia.Flash Player ESR.plugin.sb */; };
 		A1046EA12079263100F0C5D8 /* WKPDFView.h in Headers */ = {isa = PBXBuildFile; fileRef = A1046E9F2079263100F0C5D8 /* WKPDFView.h */; };
@@ -3803,6 +3805,8 @@
 		99C81D5B1C20E817005C4C82 /* APIAutomationClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APIAutomationClient.h; sourceTree = "<group>"; };
 		99CA66C8203668220074F35E /* EnterFullscreen.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = EnterFullscreen.js; sourceTree = "<group>"; };
 		99E714C11C1249E600665B3A /* _WKAutomationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKAutomationDelegate.h; sourceTree = "<group>"; };
+		99E7189621F79D9D0055E975 /* _WKTouchEventGenerator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _WKTouchEventGenerator.mm; sourceTree = "<group>"; };
+		99E7189821F79D9E0055E975 /* _WKTouchEventGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKTouchEventGenerator.h; sourceTree = "<group>"; };
 		99F642D21FABE378009621E9 /* CoordinateSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CoordinateSystem.h; sourceTree = "<group>"; };
 		9BC59D6C1EFCCCB6001E8D09 /* CallbackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallbackID.h; sourceTree = "<group>"; };
 		9BC59D6D1EFCDC6D001E8D09 /* OptionalCallbackID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OptionalCallbackID.h; sourceTree = "<group>"; };
@@ -5803,6 +5807,8 @@
 			children = (
 				C54256AE18BEC16100DE4179 /* forms */,
 				CDC2831A201BD75600E6E745 /* fullscreen */,
+				99E7189821F79D9E0055E975 /* _WKTouchEventGenerator.h */,
+				99E7189621F79D9D0055E975 /* _WKTouchEventGenerator.mm */,
 				A115DC6E191D82AB00DA8072 /* _WKWebViewPrintFormatter.h */,
 				A115DC6D191D82AB00DA8072 /* _WKWebViewPrintFormatter.mm */,
 				A19DD3BF1D07D16800AC823B /* _WKWebViewPrintFormatterInternal.h */,
@@ -8871,6 +8877,7 @@
 				1A002D43196B337000B9AD44 /* _WKSessionStateInternal.h in Headers */,
 				2D6B371B18A967AD0042AE80 /* _WKThumbnailView.h in Headers */,
 				2DACE64E18ADBFF000E4CA76 /* _WKThumbnailViewInternal.h in Headers */,
+				99E7189C21F79D9E0055E975 /* _WKTouchEventGenerator.h in Headers */,
 				7C2413031AACFA7500A58C15 /* _WKUserContentExtensionStore.h in Headers */,
 				7C2413051AACFA9C00A58C15 /* _WKUserContentExtensionStoreInternal.h in Headers */,
 				7CA3793E1AC378B30079DC37 /* _WKUserContentExtensionStorePrivate.h in Headers */,
@@ -10755,6 +10762,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				99E7189A21F79D9E0055E975 /* _WKTouchEventGenerator.mm in Sources */,
 				2D92A784212B6AB100F493FD /* ActivityAssertion.cpp in Sources */,
 				2D92A77B212B6A7100F493FD /* ArgumentCoders.cpp in Sources */,
 				2DEB1D2E2127473600933906 /* ArgumentCodersCF.cpp in Sources */,

Modified: trunk/Source/WebKit/config.h (240553 => 240554)


--- trunk/Source/WebKit/config.h	2019-01-27 16:58:48 UTC (rev 240553)
+++ trunk/Source/WebKit/config.h	2019-01-27 18:36:11 UTC (rev 240554)
@@ -79,3 +79,7 @@
 #endif
 #endif
 
+#define ENABLE_WEBDRIVER_TOUCH_INTERACTIONS PLATFORM(IOS_FAMILY)
+#define ENABLE_WEBDRIVER_MOUSE_INTERACTIONS PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WPE)
+#define ENABLE_WEBDRIVER_KEYBOARD_INTERACTIONS PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)
+#define ENABLE_WEBDRIVER_ACTIONS_API ENABLE_WEBDRIVER_TOUCH_INTERACTIONS || ENABLE_WEBDRIVER_MOUSE_INTERACTIONS || ENABLE_WEBDRIVER_KEYBOARD_INTERACTIONS
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to