WebDriver: implement maximize, minimize and fullscreen window commands
[WebKit-https.git] / Source / WebKit / UIProcess / Automation / WebAutomationSession.h
1 /*
2  * Copyright (C) 2016-2018 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include "APIObject.h"
29 #include "AutomationBackendDispatchers.h"
30 #include "AutomationFrontendDispatchers.h"
31 #include "Connection.h"
32 #include "ShareableBitmap.h"
33 #include "SimulatedInputDispatcher.h"
34 #include "WebEvent.h"
35 #include <wtf/CompletionHandler.h>
36 #include <wtf/Forward.h>
37 #include <wtf/RunLoop.h>
38
39 #if ENABLE(REMOTE_INSPECTOR)
40 #include <JavaScriptCore/RemoteAutomationTarget.h>
41 #endif
42
43 namespace API {
44 class AutomationSessionClient;
45 }
46
47 namespace Inspector {
48 class BackendDispatcher;
49 class FrontendRouter;
50 }
51
52 namespace WebCore {
53 class IntPoint;
54 class IntRect;
55
56 struct Cookie;
57 }
58
59 #if PLATFORM(COCOA)
60 OBJC_CLASS NSArray;
61 typedef unsigned short unichar;
62 #endif
63
64 #if USE(APPKIT)
65 OBJC_CLASS NSEvent;
66 #endif
67
68 namespace API {
69 class OpenPanelParameters;
70 }
71
72 namespace WebKit {
73
74 class WebAutomationSessionClient;
75 class WebFrameProxy;
76 class WebOpenPanelResultListenerProxy;
77 class WebPageProxy;
78 class WebProcessPool;
79
80 class AutomationCommandError {
81 public:
82     Inspector::Protocol::Automation::ErrorMessage type;
83     std::optional<String> message { std::nullopt };
84     
85     AutomationCommandError(Inspector::Protocol::Automation::ErrorMessage type)
86         : type(type) { }
87
88     AutomationCommandError(Inspector::Protocol::Automation::ErrorMessage type, const String& message)
89         : type(type)
90         , message(message) { }
91     
92     String toProtocolString();
93 };
94
95 using AutomationCompletionHandler = WTF::CompletionHandler<void(std::optional<AutomationCommandError>)>;
96
97 class WebAutomationSession final : public API::ObjectImpl<API::Object::Type::AutomationSession>, public IPC::MessageReceiver
98 #if ENABLE(REMOTE_INSPECTOR)
99     , public Inspector::RemoteAutomationTarget
100 #endif
101     , public Inspector::AutomationBackendDispatcherHandler
102     , public SimulatedInputDispatcher::Client
103 {
104 public:
105     WebAutomationSession();
106     ~WebAutomationSession();
107
108     void setClient(std::unique_ptr<API::AutomationSessionClient>&&);
109
110     void setSessionIdentifier(const String& sessionIdentifier) { m_sessionIdentifier = sessionIdentifier; }
111     String sessionIdentifier() const { return m_sessionIdentifier; }
112
113     WebProcessPool* processPool() const { return m_processPool; }
114     void setProcessPool(WebProcessPool*);
115
116     void navigationOccurredForFrame(const WebFrameProxy&);
117     void documentLoadedForFrame(const WebFrameProxy&);
118     void inspectorFrontendLoaded(const WebPageProxy&);
119     void keyboardEventsFlushedForPage(const WebPageProxy&);
120     void mouseEventsFlushedForPage(const WebPageProxy&);
121     void willClosePage(const WebPageProxy&);
122     void handleRunOpenPanel(const WebPageProxy&, const WebFrameProxy&, const API::OpenPanelParameters&, WebOpenPanelResultListenerProxy&);
123     void willShowJavaScriptDialog(WebPageProxy&);
124     void didEnterFullScreenForPage(const WebPageProxy&);
125     void didExitFullScreenForPage(const WebPageProxy&);
126
127     bool shouldAllowGetUserMediaForPage(const WebPageProxy&) const;
128
129 #if ENABLE(REMOTE_INSPECTOR)
130     // Inspector::RemoteAutomationTarget API
131     String name() const override { return m_sessionIdentifier; }
132     void dispatchMessageFromRemote(const String& message) override;
133     void connect(Inspector::FrontendChannel*, bool isAutomaticConnection = false, bool immediatelyPause = false) override;
134     void disconnect(Inspector::FrontendChannel*) override;
135 #endif
136     void terminate();
137
138     // SimulatedInputDispatcher::Client API
139     void simulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, AutomationCompletionHandler&&) final;
140     void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, std::optional<VirtualKey>, std::optional<CharKey>, AutomationCompletionHandler&&) final;
141     void viewportInViewCenterPointOfElement(WebPageProxy&, uint64_t frameID, const String& nodeHandle, Function<void (std::optional<WebCore::IntPoint>, std::optional<AutomationCommandError>)>&&) final;
142
143     // Inspector::AutomationBackendDispatcherHandler API
144     // NOTE: the set of declarations included in this interface depend on the "platform" property in Automation.json
145     // and the --platform argument passed to the protocol bindings generator.
146
147     // Platform: Generic
148     void getBrowsingContexts(Ref<GetBrowsingContextsCallback>&&) final;
149     void getBrowsingContext(const String&, Ref<GetBrowsingContextCallback>&&) final;
150     void createBrowsingContext(const bool* preferNewTab, Ref<CreateBrowsingContextCallback>&&) final;
151     void closeBrowsingContext(Inspector::ErrorString&, const String&) final;
152     void switchToBrowsingContext(const String& browsingContextHandle, const String* optionalFrameHandle, Ref<SwitchToBrowsingContextCallback>&&) final;
153     void setWindowFrameOfBrowsingContext(const String& handle, const JSON::Object* origin, const JSON::Object* size, Ref<SetWindowFrameOfBrowsingContextCallback>&&) final;
154     void maximizeWindowOfBrowsingContext(const String& handle, Ref<MaximizeWindowOfBrowsingContextCallback>&&) final;
155     void hideWindowOfBrowsingContext(const String& handle, Ref<HideWindowOfBrowsingContextCallback>&&) final;
156     void navigateBrowsingContext(const String& handle, const String& url, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<NavigateBrowsingContextCallback>&&) override;
157     void goBackInBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoBackInBrowsingContextCallback>&&) override;
158     void goForwardInBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoForwardInBrowsingContextCallback>&&) override;
159     void reloadBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<ReloadBrowsingContextCallback>&&) override;
160     void waitForNavigationToComplete(const String& browsingContextHandle, const String* optionalFrameHandle, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<WaitForNavigationToCompleteCallback>&&) override;
161     void evaluateJavaScriptFunction(const String& browsingContextHandle, const String* optionalFrameHandle, const String& function, const JSON::Array& arguments, const bool* optionalExpectsImplicitCallbackArgument, const int* optionalCallbackTimeout, Ref<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>&&) override;
162     void performMouseInteraction(const String& handle, const JSON::Object& requestedPosition, const String& mouseButton, const String& mouseInteraction, const JSON::Array& keyModifiers, Ref<PerformMouseInteractionCallback>&&) final;
163     void performKeyboardInteractions(const String& handle, const JSON::Array& interactions, Ref<PerformKeyboardInteractionsCallback>&&) override;
164     void performInteractionSequence(const String& handle, const String* optionalFrameHandle, const JSON::Array& sources, const JSON::Array& steps, Ref<PerformInteractionSequenceCallback>&&) override;
165     void cancelInteractionSequence(const String& handle, const String* optionalFrameHandle, Ref<CancelInteractionSequenceCallback>&&) override;
166     void takeScreenshot(const String& handle, const String* optionalFrameHandle, const String* optionalNodeHandle, const bool* optionalScrollIntoViewIfNeeded, const bool* optionalClipToViewport, Ref<TakeScreenshotCallback>&&) override;
167     void resolveChildFrameHandle(const String& browsingContextHandle, const String* optionalFrameHandle, const int* optionalOrdinal, const String* optionalName, const String* optionalNodeHandle, Ref<ResolveChildFrameHandleCallback>&&) override;
168     void resolveParentFrameHandle(const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&&) override;
169     void computeElementLayout(const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, const bool* optionalScrollIntoViewIfNeeded, const String& coordinateSystem, Ref<Inspector::AutomationBackendDispatcherHandler::ComputeElementLayoutCallback>&&) override;
170     void selectOptionElement(const String& browsingContextHandle, const String& frameHandle, const String& nodeHandle, Ref<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>&&) override;
171     void isShowingJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle, bool* result) override;
172     void dismissCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
173     void acceptCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle) override;
174     void messageOfCurrentJavaScriptDialog(Inspector::ErrorString&, const String& browsingContextHandle, String* text) override;
175     void setUserInputForCurrentJavaScriptPrompt(Inspector::ErrorString&, const String& browsingContextHandle, const String& text) override;
176     void setFilesToSelectForFileUpload(Inspector::ErrorString&, const String& browsingContextHandle, const JSON::Array& filenames) override;
177     void getAllCookies(const String& browsingContextHandle, Ref<GetAllCookiesCallback>&&) override;
178     void deleteSingleCookie(const String& browsingContextHandle, const String& cookieName, Ref<DeleteSingleCookieCallback>&&) override;
179     void addSingleCookie(const String& browsingContextHandle, const JSON::Object& cookie, Ref<AddSingleCookieCallback>&&) override;
180     void deleteAllCookies(Inspector::ErrorString&, const String& browsingContextHandle) override;
181     void getSessionPermissions(Inspector::ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::Automation::SessionPermissionData>>& out_permissions) override;
182     void setSessionPermissions(Inspector::ErrorString&, const JSON::Array& in_permissions) override;
183
184     // Platform: macOS
185 #if PLATFORM(MAC)
186     void inspectBrowsingContext(const String&, const bool* optionalEnableAutoCapturing, Ref<InspectBrowsingContextCallback>&&) override;
187 #endif
188
189     // Event Simulation Support.
190     bool isSimulatingUserInteraction() const;
191     SimulatedInputDispatcher& inputDispatcherForPage(WebPageProxy&);
192     SimulatedInputSource* inputSourceForType(SimulatedInputSourceType) const;
193
194 #if PLATFORM(MAC)
195     bool wasEventSynthesizedForAutomation(NSEvent *);
196     void markEventAsSynthesizedForAutomation(NSEvent *);
197 #endif
198
199 private:
200     WebPageProxy* webPageProxyForHandle(const String&);
201     String handleForWebPageProxy(const WebPageProxy&);
202     Ref<Inspector::Protocol::Automation::BrowsingContext> buildBrowsingContextForPage(WebPageProxy&, WebCore::FloatRect windowFrame);
203     void getNextContext(Ref<WebAutomationSession>&&, Vector<Ref<WebPageProxy>>&&, Ref<JSON::ArrayOf<Inspector::Protocol::Automation::BrowsingContext>>, Ref<WebAutomationSession::GetBrowsingContextsCallback>&&);
204
205     std::optional<uint64_t> webFrameIDForHandle(const String&);
206     String handleForWebFrameID(uint64_t frameID);
207     String handleForWebFrameProxy(const WebFrameProxy&);
208
209     void waitForNavigationToCompleteOnPage(WebPageProxy&, Inspector::Protocol::Automation::PageLoadStrategy, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
210     void waitForNavigationToCompleteOnFrame(WebFrameProxy&, Inspector::Protocol::Automation::PageLoadStrategy, Seconds, Ref<Inspector::BackendDispatcher::CallbackBase>&&);
211     void respondToPendingPageNavigationCallbacksWithTimeout(HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>>&);
212     void respondToPendingFrameNavigationCallbacksWithTimeout(HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>>&);
213     void loadTimerFired();
214
215     void exitFullscreenWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
216     void restoreWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
217     void maximizeWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
218     void hideWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
219
220     // Implemented in generated WebAutomationSessionMessageReceiver.cpp.
221     void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override;
222
223     // Called by WebAutomationSession messages.
224     void didEvaluateJavaScriptFunction(uint64_t callbackID, const String& result, const String& errorType);
225     void didResolveChildFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
226     void didResolveParentFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
227     void didComputeElementLayout(uint64_t callbackID, WebCore::IntRect, std::optional<WebCore::IntPoint>, bool isObscured, const String& errorType);
228     void didSelectOptionElement(uint64_t callbackID, const String& errorType);
229     void didTakeScreenshot(uint64_t callbackID, const ShareableBitmap::Handle&, const String& errorType);
230     void didGetCookiesForFrame(uint64_t callbackID, Vector<WebCore::Cookie>, const String& errorType);
231     void didDeleteCookie(uint64_t callbackID, const String& errorType);
232
233     // Platform-dependent implementations.
234     void platformSimulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, WebEvent::Modifiers keyModifiers);
235     // Simulates a single virtual or char key being pressed/released, such as 'a', Control, F-keys, Numpad keys, etc. as allowed by the protocol.
236     void platformSimulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, std::optional<VirtualKey>, std::optional<CharKey>);
237     // Simulates key presses to produce the codepoints in a string. One or more code points are delivered atomically at grapheme cluster boundaries.
238     void platformSimulateKeySequence(WebPageProxy&, const String&);
239     // Get base64 encoded PNG data from a bitmap.
240     std::optional<String> platformGetBase64EncodedPNGData(const ShareableBitmap::Handle&);
241
242 #if PLATFORM(COCOA)
243     // The type parameter of the NSArray argument is platform-dependent.
244     void sendSynthesizedEventsToPage(WebPageProxy&, NSArray *eventsToSend);
245
246     std::optional<unichar> charCodeForVirtualKey(Inspector::Protocol::Automation::VirtualKey) const;
247     std::optional<unichar> charCodeIgnoringModifiersForVirtualKey(Inspector::Protocol::Automation::VirtualKey) const;
248 #endif
249
250     WebProcessPool* m_processPool { nullptr };
251
252     std::unique_ptr<API::AutomationSessionClient> m_client;
253     String m_sessionIdentifier { ASCIILiteral("Untitled Session") };
254     Ref<Inspector::FrontendRouter> m_frontendRouter;
255     Ref<Inspector::BackendDispatcher> m_backendDispatcher;
256     Ref<Inspector::AutomationBackendDispatcher> m_domainDispatcher;
257     std::unique_ptr<Inspector::AutomationFrontendDispatcher> m_domainNotifier;
258
259     HashMap<uint64_t, String> m_webPageHandleMap;
260     HashMap<String, uint64_t> m_handleWebPageMap;
261
262     HashMap<uint64_t, String> m_webFrameHandleMap;
263     HashMap<String, uint64_t> m_handleWebFrameMap;
264
265     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNormalNavigationInBrowsingContextCallbacksPerPage;
266     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerPage;
267     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingNormalNavigationInBrowsingContextCallbacksPerFrame;
268     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingEagerNavigationInBrowsingContextCallbacksPerFrame;
269     HashMap<uint64_t, RefPtr<Inspector::BackendDispatcher::CallbackBase>> m_pendingInspectorCallbacksPerPage;
270     HashMap<uint64_t, Function<void(std::optional<AutomationCommandError>)>> m_pendingKeyboardEventsFlushedCallbacksPerPage;
271     HashMap<uint64_t, Function<void(std::optional<AutomationCommandError>)>> m_pendingMouseEventsFlushedCallbacksPerPage;
272
273     uint64_t m_nextEvaluateJavaScriptCallbackID { 1 };
274     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>> m_evaluateJavaScriptFunctionCallbacks;
275
276     uint64_t m_nextResolveFrameCallbackID { 1 };
277     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ResolveChildFrameHandleCallback>> m_resolveChildFrameHandleCallbacks;
278
279     uint64_t m_nextResolveParentFrameCallbackID { 1 };
280     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ResolveParentFrameHandleCallback>> m_resolveParentFrameHandleCallbacks;
281
282     // Start at 2 and use only even numbers to not conflict with m_nextViewportInViewCenterPointOfElementCallbackID.
283     uint64_t m_nextComputeElementLayoutCallbackID { 2 };
284     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ComputeElementLayoutCallback>> m_computeElementLayoutCallbacks;
285
286     // Start at 3 and use only odd numbers to not conflict with m_nextComputeElementLayoutCallbackID.
287     uint64_t m_nextViewportInViewCenterPointOfElementCallbackID { 3 };
288     HashMap<uint64_t, Function<void(std::optional<WebCore::IntPoint>, std::optional<AutomationCommandError>)>> m_viewportInViewCenterPointOfElementCallbacks;
289
290     uint64_t m_nextScreenshotCallbackID { 1 };
291     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::TakeScreenshotCallback>> m_screenshotCallbacks;
292
293     uint64_t m_nextGetCookiesCallbackID { 1 };
294     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::GetAllCookiesCallback>> m_getCookieCallbacks;
295
296     uint64_t m_nextDeleteCookieCallbackID { 1 };
297     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::DeleteSingleCookieCallback>> m_deleteCookieCallbacks;
298
299     uint64_t m_nextSelectOptionElementCallbackID { 1 };
300     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::SelectOptionElementCallback>> m_selectOptionElementCallbacks;
301
302     enum class WindowTransitionedToState {
303         Fullscreen,
304         Unfullscreen,
305     };
306     Function<void(WindowTransitionedToState)> m_windowStateTransitionCallback { };
307
308     RunLoop::Timer<WebAutomationSession> m_loadTimer;
309     Vector<String> m_filesToSelectForFileUpload;
310
311     bool m_permissionForGetUserMedia { true };
312
313     // Keep track of currently active modifiers across multiple keystrokes.
314     // Most platforms do not track current modifiers from synthesized events.
315     unsigned m_currentModifiers { 0 };
316
317     // SimulatedInputDispatcher APIs take a set of input sources. We also intern these
318     // so that previous input source state is used as initial state for later commands.
319     HashSet<Ref<SimulatedInputSource>> m_inputSources;
320     HashMap<uint64_t, Ref<SimulatedInputDispatcher>> m_inputDispatchersByPage;
321
322 #if ENABLE(REMOTE_INSPECTOR)
323     Inspector::FrontendChannel* m_remoteChannel { nullptr };
324 #endif
325
326 };
327
328 } // namespace WebKit