From 75af8eb6e1f3c2a4021f60efcfc8f3a9970d8eae Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Wed, 4 Dec 2019 17:53:49 -0800 Subject: [PATCH] chore: bootstrap --- Source/JavaScriptCore/CMakeLists.txt | 4 + Source/JavaScriptCore/DerivedSources.make | 4 + .../inspector/InspectorBackendDispatcher.cpp | 21 +- .../inspector/InspectorBackendDispatcher.h | 5 +- .../inspector/InspectorTarget.h | 3 + .../inspector/agents/InspectorTargetAgent.cpp | 46 +- .../inspector/agents/InspectorTargetAgent.h | 6 +- .../inspector/protocol/Browser.json | 106 ++++ .../inspector/protocol/DOM.json | 39 ++ .../inspector/protocol/Dialog.json | 36 ++ .../inspector/protocol/Emulation.json | 21 + .../inspector/protocol/Input.json | 160 ++++++ .../inspector/protocol/Page.json | 82 ++- .../inspector/protocol/Target.json | 18 +- Source/WebCore/html/FileInputType.cpp | 6 + .../inspector/InspectorInstrumentation.cpp | 14 +- .../inspector/InspectorInstrumentation.h | 21 + .../inspector/agents/InspectorDOMAgent.cpp | 103 ++++ .../inspector/agents/InspectorDOMAgent.h | 2 + .../inspector/agents/InspectorPageAgent.cpp | 496 +++++++++++++++++- .../inspector/agents/InspectorPageAgent.h | 16 +- .../agents/page/PageRuntimeAgent.cpp | 14 +- Source/WebCore/loader/FrameLoader.cpp | 1 + Source/WebCore/page/History.cpp | 1 + .../WebCore/platform/PlatformKeyboardEvent.h | 2 + .../platform/gtk/PlatformKeyboardEventGtk.cpp | 242 +++++++++ .../libwpe/PlatformKeyboardEventLibWPE.cpp | 240 +++++++++ .../soup/NetworkStorageSessionSoup.cpp | 9 +- .../WebKit/NetworkProcess/NetworkProcess.cpp | 30 +- Source/WebKit/NetworkProcess/NetworkProcess.h | 5 + .../NetworkProcess/NetworkProcess.messages.in | 4 + Source/WebKit/Shared/API/c/wpe/WebKit.h | 1 + Source/WebKit/Shared/NativeWebKeyboardEvent.h | 5 + Source/WebKit/Shared/NativeWebMouseEvent.h | 4 + Source/WebKit/Shared/WebEvent.h | 6 +- Source/WebKit/Shared/WebKeyboardEvent.cpp | 22 + .../Shared/gtk/NativeWebKeyboardEventGtk.cpp | 2 +- .../Shared/gtk/NativeWebMouseEventGtk.cpp | 4 +- Source/WebKit/Sources.txt | 9 + Source/WebKit/SourcesCocoa.txt | 1 + Source/WebKit/SourcesGTK.txt | 5 + Source/WebKit/SourcesWPE.txt | 6 +- Source/WebKit/UIProcess/API/APIUIClient.h | 1 + Source/WebKit/UIProcess/API/C/WKPage.cpp | 4 + .../WebKit/UIProcess/API/Cocoa/WKUIDelegate.h | 7 + .../UIProcess/API/Cocoa/WKWebsiteDataStore.h | 3 +- .../UIProcess/API/Cocoa/WKWebsiteDataStore.mm | 6 + .../UIProcess/API/Cocoa/_WKBrowserInspector.h | 33 ++ .../API/Cocoa/_WKBrowserInspector.mm | 28 + .../API/glib/WebKitBrowserInspector.cpp | 114 ++++ .../API/glib/WebKitBrowserInspectorPrivate.h | 9 + .../UIProcess/API/glib/WebKitUIClient.cpp | 4 + .../UIProcess/API/glib/WebKitWebContext.cpp | 5 + .../UIProcess/API/glib/WebKitWebView.cpp | 9 + .../UIProcess/API/glib/WebKitWebViewPrivate.h | 1 + .../UIProcess/API/gtk/PageClientImpl.cpp | 2 + .../API/gtk/WebKitBrowserInspector.h | 57 ++ Source/WebKit/UIProcess/API/gtk/webkit2.h | 1 + .../API/wpe/WebKitBrowserInspector.h | 54 ++ Source/WebKit/UIProcess/API/wpe/webkit.h | 1 + .../UIProcess/BrowserInspectorController.cpp | 101 ++++ .../UIProcess/BrowserInspectorController.h | 47 ++ .../WebKit/UIProcess/BrowserInspectorPipe.cpp | 35 ++ .../WebKit/UIProcess/BrowserInspectorPipe.h | 16 + .../UIProcess/BrowserInspectorTargetAgent.cpp | 83 +++ .../UIProcess/BrowserInspectorTargetAgent.h | 35 ++ .../PopUpSOAuthorizationSession.h | 4 + .../PopUpSOAuthorizationSession.mm | 1 + Source/WebKit/UIProcess/Cocoa/UIDelegate.h | 2 + Source/WebKit/UIProcess/Cocoa/UIDelegate.mm | 10 + .../UIProcess/InspectorBrowserAgent.cpp | 255 +++++++++ .../WebKit/UIProcess/InspectorBrowserAgent.h | 63 +++ .../UIProcess/InspectorBrowserAgentClient.h | 33 ++ .../WebKit/UIProcess/InspectorDialogAgent.cpp | 64 +++ .../WebKit/UIProcess/InspectorDialogAgent.h | 48 ++ .../WebKit/UIProcess/InspectorTargetProxy.cpp | 18 +- .../WebKit/UIProcess/InspectorTargetProxy.h | 11 +- .../WebKit/UIProcess/RemoteInspectorPipe.cpp | 132 +++++ Source/WebKit/UIProcess/RemoteInspectorPipe.h | 43 ++ .../AuthenticatorManager.cpp | 1 + .../UIProcess/WebPageInspectorController.cpp | 56 +- .../UIProcess/WebPageInspectorController.h | 8 + .../WebPageInspectorEmulationAgent.cpp | 47 ++ .../WebPageInspectorEmulationAgent.h | 42 ++ .../UIProcess/WebPageInspectorInputAgent.cpp | 235 +++++++++ .../UIProcess/WebPageInspectorInputAgent.h | 54 ++ .../UIProcess/WebPageInspectorTargetProxy.cpp | 109 ++++ .../UIProcess/WebPageInspectorTargetProxy.h | 45 ++ Source/WebKit/UIProcess/WebPageProxy.cpp | 20 +- Source/WebKit/UIProcess/WebPageProxy.h | 13 + .../glib/InspectorBrowserAgentClientGLib.cpp | 103 ++++ .../glib/InspectorBrowserAgentClientGLib.h | 36 ++ .../gtk/WebPageInspectorEmulationAgentGtk.cpp | 35 ++ .../gtk/WebPageInspectorInputAgentGtk.cpp | 85 +++ .../gtk/WebPageInspectorTargetProxyGtk.cpp | 22 + .../WebKit/UIProcess/ios/PageClientImplIOS.mm | 2 + .../mac/InspectorBrowserAgentClientMac.h | 29 + .../mac/InspectorBrowserAgentClientMac.mm | 54 ++ .../WebKit/UIProcess/mac/PageClientImplMac.mm | 5 + .../mac/WebPageInspectorEmulationAgentMac.mm | 21 + .../mac/WebPageInspectorInputAgentMac.mm | 14 + .../mac/WebPageInspectorTargetProxyMac.mm | 18 + .../wpe/WebPageInspectorEmulationAgentWPE.cpp | 18 + .../wpe/WebPageInspectorInputAgentWPE.cpp | 76 +++ .../wpe/WebPageInspectorTargetProxyWPE.cpp | 18 + .../WebKit/WebKit.xcodeproj/project.pbxproj | 59 ++- .../WebPage/WebPageInspectorTarget.cpp | 7 + .../WebPage/WebPageInspectorTarget.h | 1 + Source/WebKit/WebProcess/WebProcess.cpp | 3 +- Tools/MiniBrowser/gtk/BrowserWindow.h | 2 +- Tools/MiniBrowser/gtk/main.c | 28 + Tools/MiniBrowser/mac/AppDelegate.h | 14 +- Tools/MiniBrowser/mac/AppDelegate.m | 187 ++++++- Tools/MiniBrowser/mac/SettingsController.m | 2 +- .../mac/WK2BrowserWindowController.h | 3 + .../mac/WK2BrowserWindowController.m | 35 +- Tools/MiniBrowser/wpe/main.cpp | 37 ++ 117 files changed, 4632 insertions(+), 74 deletions(-) create mode 100644 Source/JavaScriptCore/inspector/protocol/Browser.json create mode 100644 Source/JavaScriptCore/inspector/protocol/Dialog.json create mode 100644 Source/JavaScriptCore/inspector/protocol/Emulation.json create mode 100644 Source/JavaScriptCore/inspector/protocol/Input.json create mode 100644 Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h create mode 100644 Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm create mode 100644 Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp create mode 100644 Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h create mode 100644 Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h create mode 100644 Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h create mode 100644 Source/WebKit/UIProcess/BrowserInspectorController.cpp create mode 100644 Source/WebKit/UIProcess/BrowserInspectorController.h create mode 100644 Source/WebKit/UIProcess/BrowserInspectorPipe.cpp create mode 100644 Source/WebKit/UIProcess/BrowserInspectorPipe.h create mode 100644 Source/WebKit/UIProcess/BrowserInspectorTargetAgent.cpp create mode 100644 Source/WebKit/UIProcess/BrowserInspectorTargetAgent.h create mode 100644 Source/WebKit/UIProcess/InspectorBrowserAgent.cpp create mode 100644 Source/WebKit/UIProcess/InspectorBrowserAgent.h create mode 100644 Source/WebKit/UIProcess/InspectorBrowserAgentClient.h create mode 100644 Source/WebKit/UIProcess/InspectorDialogAgent.cpp create mode 100644 Source/WebKit/UIProcess/InspectorDialogAgent.h create mode 100644 Source/WebKit/UIProcess/RemoteInspectorPipe.cpp create mode 100644 Source/WebKit/UIProcess/RemoteInspectorPipe.h create mode 100644 Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp create mode 100644 Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h create mode 100644 Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp create mode 100644 Source/WebKit/UIProcess/WebPageInspectorInputAgent.h create mode 100644 Source/WebKit/UIProcess/WebPageInspectorTargetProxy.cpp create mode 100644 Source/WebKit/UIProcess/WebPageInspectorTargetProxy.h create mode 100644 Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.cpp create mode 100644 Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.h create mode 100644 Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp create mode 100644 Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp create mode 100644 Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp create mode 100644 Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.h create mode 100644 Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.mm create mode 100644 Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm create mode 100644 Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm create mode 100644 Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm create mode 100644 Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp create mode 100644 Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp create mode 100644 Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 0f8c4194064..a28f84c44ba 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -1143,16 +1143,20 @@ set(JavaScriptCore_INSPECTOR_DOMAINS ${JAVASCRIPTCORE_DIR}/inspector/protocol/Animation.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/ApplicationCache.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Audit.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Browser.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/CSS.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Canvas.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Console.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Dialog.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOM.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOMDebugger.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/DOMStorage.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Database.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Debugger.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Emulation.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/GenericTypes.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Heap.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Input.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Inspector.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/LayerTree.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Network.json diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make index f59212ff01c..ca6ef5f8d07 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make @@ -238,16 +238,20 @@ INSPECTOR_DOMAINS := \ $(JavaScriptCore)/inspector/protocol/Animation.json \ $(JavaScriptCore)/inspector/protocol/ApplicationCache.json \ $(JavaScriptCore)/inspector/protocol/Audit.json \ + $(JavaScriptCore)/inspector/protocol/Browser.json \ $(JavaScriptCore)/inspector/protocol/CSS.json \ $(JavaScriptCore)/inspector/protocol/Canvas.json \ $(JavaScriptCore)/inspector/protocol/Console.json \ + $(JavaScriptCore)/inspector/protocol/Dialog.json \ $(JavaScriptCore)/inspector/protocol/DOM.json \ $(JavaScriptCore)/inspector/protocol/DOMDebugger.json \ $(JavaScriptCore)/inspector/protocol/DOMStorage.json \ $(JavaScriptCore)/inspector/protocol/Database.json \ $(JavaScriptCore)/inspector/protocol/Debugger.json \ + $(JavaScriptCore)/inspector/protocol/Emulation.json \ $(JavaScriptCore)/inspector/protocol/GenericTypes.json \ $(JavaScriptCore)/inspector/protocol/Heap.json \ + $(JavaScriptCore)/inspector/protocol/Input.json \ $(JavaScriptCore)/inspector/protocol/Inspector.json \ $(JavaScriptCore)/inspector/protocol/LayerTree.json \ $(JavaScriptCore)/inspector/protocol/Network.json \ diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp index 038cb646d31..8a01d7679bf 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp @@ -102,7 +102,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple m_dispatchers.set(domain, dispatcher); } -void BackendDispatcher::dispatch(const String& message) +BackendDispatcher::DispatchResult BackendDispatcher::dispatch(const String& message, Mode mode) { Ref protect(*this); @@ -120,26 +120,26 @@ void BackendDispatcher::dispatch(const String& message) if (!JSON::Value::parseJSON(message, parsedMessage)) { reportProtocolError(ParseError, "Message must be in JSON format"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } if (!parsedMessage->asObject(messageObject)) { reportProtocolError(InvalidRequest, "Message must be a JSONified object"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } RefPtr requestIdValue; if (!messageObject->getValue("id"_s, requestIdValue)) { reportProtocolError(InvalidRequest, "'id' property was not found"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } if (!requestIdValue->asInteger(requestId)) { reportProtocolError(InvalidRequest, "The type of 'id' property must be integer"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } } @@ -151,29 +151,31 @@ void BackendDispatcher::dispatch(const String& message) if (!messageObject->getValue("method"_s, methodValue)) { reportProtocolError(InvalidRequest, "'method' property wasn't found"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } String methodString; if (!methodValue->asString(methodString)) { reportProtocolError(InvalidRequest, "The type of 'method' property must be string"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } Vector domainAndMethod = methodString.splitAllowingEmptyEntries('.'); if (domainAndMethod.size() != 2 || !domainAndMethod[0].length() || !domainAndMethod[1].length()) { reportProtocolError(InvalidRequest, "The 'method' property was formatted incorrectly. It should be 'Domain.method'"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } String domain = domainAndMethod[0]; SupplementalBackendDispatcher* domainDispatcher = m_dispatchers.get(domain); if (!domainDispatcher) { + if (mode == Mode::ContinueIfDomainIsMissing) + return DispatchResult::Continue; reportProtocolError(MethodNotFound, "'" + domain + "' domain was not found"); sendPendingErrors(); - return; + return DispatchResult::Finished; } String method = domainAndMethod[1]; @@ -182,6 +184,7 @@ void BackendDispatcher::dispatch(const String& message) if (m_protocolErrors.size()) sendPendingErrors(); } + return DispatchResult::Finished; } // FIXME: remove this function when legacy InspectorObject symbols are no longer needed . diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h index 95d9d81188e..6f96f174dff 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h @@ -82,7 +82,10 @@ public: }; void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); - void dispatch(const String& message); + + enum class DispatchResult { Finished, Continue }; + enum class Mode { FailIfDomainIsMissing, ContinueIfDomainIsMissing }; + DispatchResult dispatch(const String& message, Mode mode = Mode::FailIfDomainIsMissing); // Note that 'unused' is a workaround so the compiler can pick the right sendResponse based on arity. // When is fixed or this class is renamed for the JSON::Object case, diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h index a9f04b8a0c9..045b9ecd39a 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.h +++ b/Source/JavaScriptCore/inspector/InspectorTarget.h @@ -45,6 +45,7 @@ public: // State. virtual String identifier() const = 0; virtual InspectorTargetType type() const = 0; + virtual String url() const = 0; virtual bool isProvisional() const { return false; } @@ -52,6 +53,8 @@ public: virtual void connect(FrontendChannel::ConnectionType) = 0; virtual void disconnect() = 0; virtual void sendMessageToTargetBackend(const String&) = 0; + virtual void activate(String& error) { error = "Target cannot be activated"; } + virtual void close(String& error) { error = "Target cannot be closed"; } }; } // namespace Inspector diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp index 1177090fc18..764b62c727c 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp @@ -30,11 +30,12 @@ namespace Inspector { -InspectorTargetAgent::InspectorTargetAgent(FrontendRouter& frontendRouter, BackendDispatcher& backendDispatcher) +InspectorTargetAgent::InspectorTargetAgent(FrontendRouter& frontendRouter, BackendDispatcher& backendDispatcher, const String& browserContextID) : InspectorAgentBase("Target"_s) , m_router(frontendRouter) , m_frontendDispatcher(makeUnique(frontendRouter)) , m_backendDispatcher(TargetBackendDispatcher::create(backendDispatcher, this)) + , m_browserContextID(browserContextID) { } @@ -65,6 +66,28 @@ void InspectorTargetAgent::sendMessageToTarget(ErrorString& errorString, const S target->sendMessageToTargetBackend(message); } +void InspectorTargetAgent::activate(ErrorString& errorString, const String& targetId) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) { + errorString = "Missing target for given targetId"_s; + return; + } + + target->activate(errorString); +} + +void InspectorTargetAgent::close(ErrorString& errorString, const String& targetId) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) { + errorString = "Missing target for given targetId"_s; + return; + } + + target->close(errorString); +} + void InspectorTargetAgent::sendMessageFromTargetToFrontend(const String& targetId, const String& message) { ASSERT_WITH_MESSAGE(m_targets.get(targetId), "Sending a message from an untracked target to the frontend."); @@ -87,14 +110,17 @@ static Protocol::Target::TargetInfo::Type targetTypeToProtocolType(InspectorTarg return Protocol::Target::TargetInfo::Type::Page; } -static Ref buildTargetInfoObject(const InspectorTarget& target) +static Ref buildTargetInfoObject(const InspectorTarget& target, const String& browserContextID) { auto result = Protocol::Target::TargetInfo::create() .setTargetId(target.identifier()) .setType(targetTypeToProtocolType(target.type())) + .setUrl(target.url()) .release(); if (target.isProvisional()) result->setIsProvisional(true); + if (!browserContextID.isEmpty()) + result->setBrowserContextId(browserContextID); return result; } @@ -108,7 +134,7 @@ void InspectorTargetAgent::targetCreated(InspectorTarget& target) target.connect(connectionType()); - m_frontendDispatcher->targetCreated(buildTargetInfoObject(target)); + m_frontendDispatcher->targetCreated(buildTargetInfoObject(target, m_browserContextID)); } void InspectorTargetAgent::targetDestroyed(InspectorTarget& target) @@ -135,6 +161,18 @@ void InspectorTargetAgent::didCommitProvisionalTarget(const String& oldTargetID, m_frontendDispatcher->didCommitProvisionalTarget(oldTargetID, committedTargetID); } +void InspectorTargetAgent::ensureConnected(const String& targetID) +{ + if (!m_isConnected) + return; + + auto* target = m_targets.get(targetID); + if (!target) + return; + + target->connect(connectionType()); +} + FrontendChannel::ConnectionType InspectorTargetAgent::connectionType() const { return m_router.hasLocalFrontend() ? Inspector::FrontendChannel::ConnectionType::Local : Inspector::FrontendChannel::ConnectionType::Remote; @@ -144,7 +182,7 @@ void InspectorTargetAgent::connectToTargets() { for (InspectorTarget* target : m_targets.values()) { target->connect(connectionType()); - m_frontendDispatcher->targetCreated(buildTargetInfoObject(*target)); + m_frontendDispatcher->targetCreated(buildTargetInfoObject(*target, m_browserContextID)); } } diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h index 38cb318986b..4287e05e559 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h @@ -41,7 +41,7 @@ class JS_EXPORT_PRIVATE InspectorTargetAgent : public InspectorAgentBase, public WTF_MAKE_NONCOPYABLE(InspectorTargetAgent); WTF_MAKE_FAST_ALLOCATED; public: - InspectorTargetAgent(FrontendRouter&, BackendDispatcher&); + InspectorTargetAgent(FrontendRouter&, BackendDispatcher&, const String& browserContextID); ~InspectorTargetAgent() override; // InspectorAgentBase @@ -50,11 +50,14 @@ public: // TargetBackendDispatcherHandler void sendMessageToTarget(ErrorString&, const String& targetId, const String& message) final; + void activate(ErrorString&, const String& targetId) override; + void close(ErrorString&, const String& targetId) override; // Target lifecycle. void targetCreated(InspectorTarget&); void targetDestroyed(InspectorTarget&); void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID); + void ensureConnected(const String& targetID); // Target messages. void sendMessageFromTargetToFrontend(const String& targetId, const String& message); @@ -68,6 +71,7 @@ private: Inspector::FrontendRouter& m_router; std::unique_ptr m_frontendDispatcher; Ref m_backendDispatcher; + const String m_browserContextID; HashMap m_targets; bool m_isConnected { false }; }; diff --git a/Source/JavaScriptCore/inspector/protocol/Browser.json b/Source/JavaScriptCore/inspector/protocol/Browser.json new file mode 100644 index 00000000000..063e5e1346a --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Browser.json @@ -0,0 +1,106 @@ +{ + "domain": "Browser", + "availability": ["web"], + "types": [ + { + "id": "ContextID", + "type": "string", + "description": "Id of Browser context." + }, + { + "id": "CookieSameSitePolicy", + "type": "string", + "enum": ["None", "Lax", "Strict"], + "description": "Same-Site policy of a cookie." + }, + { + "id": "Cookie", + "type": "object", + "description": "Cookie object", + "properties": [ + { "name": "name", "type": "string", "description": "Cookie name." }, + { "name": "value", "type": "string", "description": "Cookie value." }, + { "name": "domain", "type": "string", "description": "Cookie domain." }, + { "name": "path", "type": "string", "description": "Cookie path." }, + { "name": "expires", "type": "number", "description": "Cookie expires." }, + { "name": "httpOnly", "type": "boolean", "description": "True if cookie is http-only." }, + { "name": "secure", "type": "boolean", "description": "True if cookie is secure." }, + { "name": "session", "type": "boolean", "description": "True if cookie is session cookie." }, + { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." } + ] + }, + { + "id": "SetCookieParam", + "type": "object", + "description": "Cookie object", + "properties": [ + { "name": "name", "type": "string", "description": "Cookie name." }, + { "name": "value", "type": "string", "description": "Cookie value." }, + { "name": "domain", "type": "string", "description": "Cookie domain." }, + { "name": "path", "type": "string", "description": "Cookie path." }, + { "name": "expires", "type": "number", "optional": true, "description": "Cookie expires." }, + { "name": "httpOnly", "type": "boolean", "optional": true, "description": "True if cookie is http-only." }, + { "name": "secure", "type": "boolean", "optional": true, "description": "True if cookie is secure." }, + { "name": "session", "type": "boolean", "optional": true, "description": "True if cookie is session cookie." }, + { "name": "sameSite", "$ref": "CookieSameSitePolicy", "optional": true, "description": "Cookie Same-Site policy." } + ] + } + ], + "commands": [ + { + "name": "close", + "description": "Close browser." + }, + { + "name": "createContext", + "description": "Creates new ephemeral browser context.", + "returns": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." } + ] + }, + { + "name": "deleteContext", + "description": "Deletes browser context previously created with createContect. The command will automatically close all pages that use the context.", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Identifier of the context to delete." } + ] + }, + { + "name": "createPage", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." } + ], + "returns": [ + { "name": "targetId", "type": "string", "description": "Unique identifier for the page target." } + ] + }, + { + "name": "getAllCookies", + "description": "Returns all cookies in the given browser context.", + "async": true, + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ], + "returns": [ + { "name": "cookies", "type": "array", "items": { "$ref": "Cookie" }, "description": "Cookies." } + ] + }, + { + "name": "setCookies", + "description": "Sets cookies in the given browser context.", + "async": true, + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }, + { "name": "cookies", "type": "array", "items": { "$ref": "SetCookieParam" }, "description": "Cookies." } + ] + }, + { + "name": "deleteAllCookies", + "description": "Deletes cookies in the given browser context.", + "async": true, + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/DOM.json b/Source/JavaScriptCore/inspector/protocol/DOM.json index 38cb48bedf2..c8da2a4f10f 100644 --- a/Source/JavaScriptCore/inspector/protocol/DOM.json +++ b/Source/JavaScriptCore/inspector/protocol/DOM.json @@ -167,6 +167,16 @@ { "name": "borderColor", "$ref": "RGBAColor", "optional": true, "description": "The border highlight fill color (default: transparent)." }, { "name": "marginColor", "$ref": "RGBAColor", "optional": true, "description": "The margin highlight fill color (default: transparent)." } ] + }, + { + "id": "FilePayload", + "type": "object", + "description": "Data to construct File object.", + "properties": [ + { "name": "name", "type": "string", "description": "File name." }, + { "name": "type", "type": "string", "description": "File type." }, + { "name": "data", "type": "string", "description": "Base64-encoded file data." } + ] } ], "commands": [ @@ -542,6 +552,35 @@ "parameters": [ { "name": "allow", "type": "boolean" } ] + }, + { + "name": "getContentQuads", + "description": "Returns quads that describe node position on the page. This method\nmight return multiple quads for inline nodes.", + "parameters": [ + { + "name": "objectId", + "description": "JavaScript object id of the node wrapper.", + "$ref": "Runtime.RemoteObjectId" + } + ], + "returns": [ + { + "name": "quads", + "description": "Quads that describe node layout relative to viewport.", + "type": "array", + "items": { + "$ref": "Quad" + } + } + ] + }, + { + "name": "setInputFiles", + "description": "Sets input files for given ", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Input element handle." }, + { "name": "files", "type": "array", "items": { "$ref": "FilePayload" }, "description": "Files to set" } + ] } ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Dialog.json b/Source/JavaScriptCore/inspector/protocol/Dialog.json new file mode 100644 index 00000000000..79edea03fed --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Dialog.json @@ -0,0 +1,36 @@ +{ + "domain": "Dialog", + "description": "Actions and events related to alert boxes.", + "availability": ["web"], + "types": [ + ], + "commands": [ + { + "name": "enable", + "description": "Enables dialog domain notifications." + }, + { + "name": "disable", + "description": "Disables dialog domain notifications." + }, + { + "name": "handleJavaScriptDialog", + "description": "Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload).", + "parameters": [ + { "name": "accept", "type": "boolean", "description": "Whether to accept or dismiss the dialog."}, + { "name": "promptText", "optional": true, "type": "string", "description": "The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog."} + ] + } + ], + "events": [ + { + "name": "javascriptDialogOpening", + "description": "Fired when a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload) is about to open.", + "parameters": [ + { "name": "type", "type": "string", "description": "Dialog type."}, + { "name": "message", "type": "string", "description": "Message that will be displayed by the dialog."}, + { "name": "defaultPrompt", "optional": true, "type": "string", "description": "Default dialog prompt."} + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Emulation.json b/Source/JavaScriptCore/inspector/protocol/Emulation.json new file mode 100644 index 00000000000..af0f39e5249 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Emulation.json @@ -0,0 +1,21 @@ +{ + "domain": "Emulation", + "availability": ["web"], + "commands": [ + { + "name": "setDeviceMetricsOverride", + "description": "Overrides device metrics with provided values.", + "parameters": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" } + ] + }, + { + "name": "setJavaScriptEnabled", + "description": "Allows to disable script execution for the page.", + "parameters": [ + { "name": "enabled", "type": "boolean" } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Input.json b/Source/JavaScriptCore/inspector/protocol/Input.json new file mode 100644 index 00000000000..79bbe73b0df --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Input.json @@ -0,0 +1,160 @@ +{ + "domain": "Input", + "availability": ["web"], + "types": [ + { + "id": "TimeSinceEpoch", + "description": "UTC time in seconds, counted from January 1, 1970.", + "type": "number" + } + ], + "commands": [ + { + "name": "goBack", + "description": "FIXME: move this to Page domain." + }, + { + "name": "dispatchKeyEvent", + "description": "Dispatches a key event to the page.", + "async": true, + "parameters": [ + { + "name": "type", + "description": "Type of the key event.", + "type": "string", + "enum": [ + "keyDown", + "keyUp" + ] + }, + { + "name": "modifiers", + "description": "Bit field representing pressed modifier keys. (default: 0).", + "optional": true, + "type": "integer" + }, + { + "name": "text", + "description": "Text as generated by processing a virtual key code with a keyboard layout. Not needed for\nfor `keyUp` and `rawKeyDown` events (default: \"\")", + "optional": true, + "type": "string" + }, + { + "name": "unmodifiedText", + "description": "Text that would have been generated by the keyboard if no modifiers were pressed (except for\nshift). Useful for shortcut (accelerator) key handling (default: \"\").", + "optional": true, + "type": "string" + }, + { + "name": "code", + "description": "Unique DOM defined string value for each physical key (e.g., 'KeyA') (default: \"\").", + "optional": true, + "type": "string" + }, + { + "name": "key", + "description": "Unique DOM defined string value describing the meaning of the key in the context of active\nmodifiers, keyboard layout, etc (e.g., 'AltGr') (default: \"\").", + "optional": true, + "type": "string" + }, + { + "name": "windowsVirtualKeyCode", + "description": "Windows virtual key code (default: 0).", + "optional": true, + "type": "integer" + }, + { + "name": "nativeVirtualKeyCode", + "description": "Native virtual key code (default: 0).", + "optional": true, + "type": "integer" + }, + { + "name": "autoRepeat", + "description": "Whether the event was generated from auto repeat (default: false).", + "optional": true, + "type": "boolean" + }, + { + "name": "isKeypad", + "description": "Whether the event was generated from the keypad (default: false).", + "optional": true, + "type": "boolean" + }, + { + "name": "isSystemKey", + "description": "Whether the event was a system key event (default: false).", + "optional": true, + "type": "boolean" + } + ] + }, + { + "name": "dispatchMouseEvent", + "description": "Dispatches a mouse event to the page.", + "async": true, + "parameters": [ + { + "name": "type", + "description": "Type of the mouse event.", + "type": "string", + "enum": [ "move", "down", "up", "wheel"] + }, + { + "name": "x", + "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels.", + "type": "integer" + }, + { + "name": "y", + "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to\nthe top of the viewport and Y increases as it proceeds towards the bottom of the viewport.", + "type": "integer" + }, + { + "name": "modifiers", + "description": "Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8\n(default: 0).", + "optional": true, + "type": "integer" + }, + { + "name": "button", + "description": "Mouse button (default: \"none\").", + "optional": true, + "type": "string", + "enum": [ + "none", + "left", + "middle", + "right", + "back", + "forward" + ] + }, + { + "name": "buttons", + "description": "A number indicating which buttons are pressed on the mouse when a mouse event is triggered.\nLeft=1, Right=2, Middle=4, Back=8, Forward=16, None=0.", + "optional": true, + "type": "integer" + }, + { + "name": "clickCount", + "description": "Number of times the mouse button was clicked (default: 0).", + "optional": true, + "type": "integer" + }, + { + "name": "deltaX", + "description": "X delta in CSS pixels for mouse wheel event (default: 0).", + "optional": true, + "type": "integer" + }, + { + "name": "deltaY", + "description": "Y delta in CSS pixels for mouse wheel event (default: 0).", + "optional": true, + "type": "integer" + } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json index 367d1f235a8..b01d36e5e86 100644 --- a/Source/JavaScriptCore/inspector/protocol/Page.json +++ b/Source/JavaScriptCore/inspector/protocol/Page.json @@ -108,6 +108,40 @@ { "name": "session", "type": "boolean", "description": "True in case of session cookie." }, { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." } ] + }, + { + "id": "AXNode", + "type": "object", + "description": "Accessibility Node", + "properties": [ + { "name": "role", "type": "string", "description": "The role."}, + { "name": "name", "type": "string","optional": true, "description": "A human readable name for the node."}, + { "name": "value", "type": "any", "optional": true, "description": "The current value of the node."}, + { "name": "description", "type": "string", "optional": true, "description": "An additional human readable description of the node."}, + { "name": "keyshortcuts", "type": "string", "optional": true, "description": "Keyboard shortcuts associated with this node."}, + { "name": "roledescription", "type": "string", "optional": true, "description": "A human readable alternative to the role."}, + { "name": "valuetext", "type": "string", "optional": true, "description": "A description of the current value."}, + { "name": "disabled", "type": "boolean", "optional": true, "description": "Whether the node is disabled."}, + { "name": "expanded", "type": "boolean", "optional": true, "description": "Whether the node is expanded or collapsed."}, + { "name": "focused", "type": "boolean", "optional": true, "description": "Whether the node is focused."}, + { "name": "modal", "type": "boolean", "optional": true, "description": "Whether the node is modal."}, + { "name": "multiline", "type": "boolean", "optional": true, "description": "Whether the node text input supports multiline."}, + { "name": "multiselectable", "type": "boolean", "optional": true, "description": "Whether more than one child can be selected."}, + { "name": "readonly", "type": "boolean", "optional": true, "description": "Whether the node is read only."}, + { "name": "required", "type": "boolean", "optional": true, "description": "Whether the node is required."}, + { "name": "selected", "type": "boolean", "optional": true, "description": "Whether the node is selected in its parent node."}, + { "name": "checked", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Whether the checkbox is checked, or \"mixed\"."}, + { "name": "pressed", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Whether the toggle button is checked, or \"mixed\"."}, + { "name": "level", "type": "integer", "optional": true, "description": "The level of a heading."}, + { "name": "valuemin", "type": "number", "optional": true, "description": "The minimum value in a node."}, + { "name": "valuemax", "type": "number", "optional": true, "description": "The maximum value in a node."}, + { "name": "autocomplete", "type": "string", "optional": true, "description": "What kind of autocomplete is supported by a control."}, + { "name": "haspopup", "type": "string", "optional": true, "description": "What kind of popup is currently being shown for a node."}, + { "name": "invalid", "type": "string", "optional": true, "enum": ["true", "false", "grammar", "spelling"], "description": "Whether and in what way this node's value is invalid."}, + { "name": "orientation", "type": "string", "optional": true, "description": "Whether the node is oriented horizontally or vertically."}, + { "name": "focusable", "type": "boolean", "optional": true, "description": "Whether the node is focusable."}, + { "name": "children", "type": "array", "optional": true, "items": { "$ref": "AXNode"}, "description": "Child AXNodes of this node, if any."} + ] } ], "commands": [ @@ -131,7 +165,8 @@ "name": "navigate", "description": "Navigates current page to the given URL.", "parameters": [ - { "name": "url", "type": "string", "description": "URL to navigate the page to." } + { "name": "url", "type": "string", "description": "URL to navigate the page to." }, + { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to navigate."} ] }, { @@ -288,6 +323,27 @@ "returns": [ { "name": "data", "type": "string", "description": "Base64-encoded web archive." } ] + }, + { + "name": "insertText", + "description": "Insert text into the current selection of the page.", + "parameters": [ + { "name": "text", "type": "string", "description": "Text to insert." } + ] + }, + { + "name": "accessibilitySnapshot", + "description": "Serializes and returns all of the accessibility nodes of the page.", + "returns": [ + { "name": "axNode", "$ref": "AXNode", "description": "The root AXNode."} + ] + }, + { + "name": "setInterceptFileChooserDialog", + "description": "Intercepts file chooser dialog", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "True to enable." } + ] } ], "events": [ @@ -346,12 +402,36 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ] }, + { + "name": "navigatedWithinDocument", + "description": "Fired when same-document navigation happens, e.g. due to history API usage or anchor navigation.", + "parameters": [ + { + "name": "frameId", + "description": "Id of the frame.", + "$ref": "Network.FrameId" + }, + { + "name": "url", + "description": "Frame's new url.", + "type": "string" + } + ] + }, { "name": "defaultAppearanceDidChange", "description": "Fired when page's default appearance changes, even if there is a forced appearance.", "parameters": [ { "name": "appearance", "$ref": "Appearance", "description": "Name of the appearance that is active (not considering any forced appearance.)" } ] + }, + { + "name": "fileChooserOpened", + "description": "Fired when the page shows file chooser for it's .", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Frame where file chooser is opened." }, + { "name": "element", "$ref": "Runtime.RemoteObject", "description": "Input element." } + ] } ] } diff --git a/Source/JavaScriptCore/inspector/protocol/Target.json b/Source/JavaScriptCore/inspector/protocol/Target.json index 240cd42e67e..f635c67ef3f 100644 --- a/Source/JavaScriptCore/inspector/protocol/Target.json +++ b/Source/JavaScriptCore/inspector/protocol/Target.json @@ -10,7 +10,9 @@ "properties": [ { "name": "targetId", "type": "string", "description": "Unique identifier for the target." }, { "name": "type", "type": "string", "enum": ["page", "service-worker", "worker"] }, - { "name": "isProvisional", "type": "boolean", "optional": true, "description": "True value indicates that this is a provisional page target i.e. Such target may be created when current page starts cross-origin navigation. Eventually each provisional target is either committed and swaps with the current target or gets destroyed, e.g. in case of load request failure." } + { "name": "url", "type": "string" }, + { "name": "isProvisional", "type": "boolean", "optional": true, "description": "True value indicates that this is a provisional page target i.e. Such target may be created when current page starts cross-origin navigation. Eventually each provisional target is either committed and swaps with the current target or gets destroyed, e.g. in case of load request failure." }, + { "name": "browserContextId", "$ref": "Browser.ContextID", "optional": true } ] } ], @@ -22,6 +24,20 @@ { "name": "targetId", "type": "string" }, { "name": "message", "type": "string", "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." } ] + }, + { + "name": "activate", + "description": "Reveals the target on screen.", + "parameters": [ + { "name": "targetId", "type": "string" } + ] + }, + { + "name": "close", + "description": "Closes the target.", + "parameters": [ + { "name": "targetId", "type": "string" } + ] } ], "events": [ diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp index 4e41fd3f807..1f7be602cb2 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp @@ -36,6 +36,7 @@ #include "HTMLNames.h" #include "Icon.h" #include "InputTypeNames.h" +#include "InspectorInstrumentation.h" #include "LocalizedStrings.h" #include "RenderFileUploadControl.h" #include "RuntimeEnabledFeatures.h" @@ -205,6 +206,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) if (input.isDisabledFormControl()) return; + bool intercept = false; + InspectorInstrumentation::runOpenPanel(input.document().frame(), element(), &intercept); + if (intercept) + return; + if (!UserGestureIndicator::processingUserGesture()) return; diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp index cb6ed9f6c84..458def75277 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -121,7 +121,7 @@ static Frame* frameForScriptExecutionContext(ScriptExecutionContext& context) void InspectorInstrumentation::didClearWindowObjectInWorldImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, DOMWrapperWorld& world) { - if (&world != &mainThreadNormalWorld()) + if (!world.isNormal()) return; if (auto* pageDebuggerAgent = instrumentingAgents.pageDebuggerAgent()) @@ -783,6 +783,12 @@ void InspectorInstrumentation::frameClearedScheduledNavigationImpl(Instrumenting inspectorPageAgent->frameClearedScheduledNavigation(frame); } +void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) +{ + if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.inspectorPageAgent()) + inspectorPageAgent->didNavigateWithinPage(frame); +} + void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents, bool useDarkAppearance) { if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.inspectorPageAgent()) @@ -1251,6 +1257,12 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins layerTreeAgent->renderLayerDestroyed(renderLayer); } +void InspectorInstrumentation::runOpenPanelImpl(InstrumentingAgents& instrumentingAgents, HTMLInputElement* element, bool* intercept) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent()) + pageAgent->runOpenPanel(element, intercept); +} + InstrumentingAgents& InspectorInstrumentation::instrumentingAgentsForWorkerGlobalScope(WorkerGlobalScope& workerGlobalScope) { return workerGlobalScope.inspectorController().m_instrumentingAgents; diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index 6698431f316..486a6781d81 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -77,6 +77,7 @@ class DOMWrapperWorld; class Document; class DocumentLoader; class EventListener; +class HTMLInputElement; class HTTPHeaderMap; class InspectorTimelineAgent; class InstrumentingAgents; @@ -228,6 +229,7 @@ public: static void frameStoppedLoading(Frame&); static void frameScheduledNavigation(Frame&, Seconds delay); static void frameClearedScheduledNavigation(Frame&); + static void didNavigateWithinPage(Frame&); static void defaultAppearanceDidChange(Page&, bool useDarkAppearance); static void willDestroyCachedResource(CachedResource&); @@ -313,6 +315,8 @@ public: static void layerTreeDidChange(Page*); static void renderLayerDestroyed(Page*, const RenderLayer&); + static void runOpenPanel(Frame*, HTMLInputElement*, bool*); + static void frontendCreated(); static void frontendDeleted(); static bool hasFrontends() { return InspectorInstrumentationPublic::hasFrontends(); } @@ -428,6 +432,7 @@ private: static void frameStoppedLoadingImpl(InstrumentingAgents&, Frame&); static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay); static void frameClearedScheduledNavigationImpl(InstrumentingAgents&, Frame&); + static void didNavigateWithinPageImpl(InstrumentingAgents&, Frame&); static void defaultAppearanceDidChangeImpl(InstrumentingAgents&, bool useDarkAppearance); static void willDestroyCachedResourceImpl(CachedResource&); @@ -509,6 +514,8 @@ private: static void layerTreeDidChangeImpl(InstrumentingAgents&); static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&); + static void runOpenPanelImpl(InstrumentingAgents&, HTMLInputElement*, bool*); + static InstrumentingAgents& instrumentingAgentsForPage(Page&); static InstrumentingAgents& instrumentingAgentsForWorkerGlobalScope(WorkerGlobalScope&); @@ -1219,6 +1226,13 @@ inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& fra frameClearedScheduledNavigationImpl(*instrumentingAgents, frame); } +inline void InspectorInstrumentation::didNavigateWithinPage(Frame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame)) + didNavigateWithinPageImpl(*instrumentingAgents, frame); +} + inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page, bool useDarkAppearance) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1643,6 +1657,13 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren renderLayerDestroyedImpl(*instrumentingAgents, renderLayer); } +inline void InspectorInstrumentation::runOpenPanel(Frame* frame, HTMLInputElement* element, bool* intercept) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(*frame)) + runOpenPanelImpl(*instrumentingAgents, element, intercept); +} + inline InstrumentingAgents* InspectorInstrumentation::instrumentingAgentsForContext(ScriptExecutionContext* context) { return context ? instrumentingAgentsForContext(*context) : nullptr; diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp index aecc79bc0ca..57ce50c1f94 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -61,12 +61,16 @@ #include "Event.h" #include "EventListener.h" #include "EventNames.h" +#include "File.h" +#include "FileList.h" #include "Frame.h" #include "FrameTree.h" #include "FrameView.h" #include "FullscreenManager.h" +#include "FloatQuad.h" #include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "HTMLParserIdioms.h" @@ -93,11 +97,13 @@ #include "Page.h" #include "Pasteboard.h" #include "PseudoElement.h" +#include "RenderObject.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" #include "ScriptState.h" #include "SelectorChecker.h" #include "ShadowRoot.h" +#include "SharedBuffer.h" #include "StaticNodeList.h" #include "StyleProperties.h" #include "StyleResolver.h" @@ -1475,6 +1481,61 @@ void InspectorDOMAgent::setInspectedNode(ErrorString& errorString, int nodeId) m_suppressEventListenerChangedEvent = false; } +static void frameQuadToViewport(const FrameView* containingView, FloatQuad& quad) +{ + quad.setP1(containingView->contentsToRootView(quad.p1())); + quad.setP2(containingView->contentsToRootView(quad.p2())); + quad.setP3(containingView->contentsToRootView(quad.p3())); + quad.setP4(containingView->contentsToRootView(quad.p4())); +} + +static RefPtr buildObjectForQuad(const FloatQuad& quad) +{ + auto result = Inspector::Protocol::DOM::Quad::create(); + result->addItem(quad.p1().x()); + result->addItem(quad.p1().y()); + result->addItem(quad.p2().x()); + result->addItem(quad.p2().y()); + result->addItem(quad.p3().x()); + result->addItem(quad.p3().y()); + result->addItem(quad.p4().x()); + result->addItem(quad.p4().y()); + return result; +} + +static RefPtr> buildArrayOfQuads(const Vector& quads) +{ + auto result = JSON::ArrayOf::create(); + for (const auto& quad : quads) + result->addItem(buildObjectForQuad(quad)); + return result; +} + +void InspectorDOMAgent::getContentQuads(ErrorString& error, const String& objectId, RefPtr>& out_quads) +{ + Node* node = nodeForObjectId(objectId); + if (!node) { + error = "Node not found"; + return; + } + RenderObject* renderer = node->renderer(); + if (!renderer) { + error = "Node doesn't have renderer"; + return; + } + Frame* containingFrame = renderer->document().frame(); + if (!containingFrame) { + error = "No containing frame"; + return; + } + FrameView* containingView = containingFrame->view(); + Vector quads; + renderer->absoluteQuads(quads); + for (auto& quad : quads) + frameQuadToViewport(containingView, quad); + out_quads = buildArrayOfQuads(quads); +} + void InspectorDOMAgent::resolveNode(ErrorString& errorString, int nodeId, const String* objectGroup, RefPtr& result) { String objectGroupName = objectGroup ? *objectGroup : emptyString(); @@ -2686,4 +2747,46 @@ void InspectorDOMAgent::setAllowEditingUserAgentShadowTrees(ErrorString&, bool a m_allowEditingUserAgentShadowTrees = allow; } +void InspectorDOMAgent::setInputFiles(ErrorString& errorString, const String& objectId, const JSON::Array& in_files) { + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) { + errorString = "Can not find element's context for given id"_s; + return; + } + Node* node = scriptValueAsNode(injectedScript.findObjectById(objectId)); + if (!node) { + errorString = "Can not find element for given id"_s; + return; + } + if (node->nodeType() != Node::ELEMENT_NODE || node->nodeName() != "INPUT") { + errorString = "Not an input node"_s; + return; + } + HTMLInputElement* element = static_cast(node); + Vector> fileObjects; + for (unsigned i = 0; i < in_files.length(); ++i) { + RefPtr item = in_files.get(i); + RefPtr obj; + if (!item->asObject(obj)) { + errorString = "Invalid file payload format"_s; + return; + } + String name; + String type; + String data; + if (!obj->getString("name", name) || !obj->getString("type", type) || !obj->getString("data", data)) { + errorString = "Invalid file payload format"_s; + return; + } + Vector buffer; + if (!base64Decode(data, buffer)) { + errorString = "Unable to decode given content"_s; + return; + } + fileObjects.append(File::create(Blob::create(SharedBuffer::create(WTFMove(buffer)), type), name)); + } + RefPtr fileList = FileList::create(WTFMove(fileObjects)); + element->setFiles(WTFMove(fileList)); +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h index 51639abeb84..16080f2c017 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -148,6 +148,8 @@ public: void focus(ErrorString&, int nodeId) override; void setInspectedNode(ErrorString&, int nodeId) override; void setAllowEditingUserAgentShadowTrees(ErrorString&, bool allow) final; + void getContentQuads(ErrorString&, const String& objectId, RefPtr>& out_quads) override; + void setInputFiles(ErrorString&, const String& objectId, const JSON::Array& in_files) override; // InspectorInstrumentation int identifierForNode(Node&); diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp index f2e228b7f74..d6d0c38f6b7 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp @@ -32,6 +32,7 @@ #include "config.h" #include "InspectorPageAgent.h" +#include "AXObjectCache.h" #include "CachedResource.h" #include "CachedResourceLoader.h" #include "Cookie.h" @@ -39,12 +40,14 @@ #include "CustomHeaderFields.h" #include "Document.h" #include "DocumentLoader.h" +#include "FocusController.h" #include "Frame.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" #include "FrameSnapshotting.h" #include "FrameView.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" #include "InspectorClient.h" @@ -59,13 +62,16 @@ #include "RenderTheme.h" #include "ScriptController.h" #include "ScriptSourceCode.h" +#include "ScriptState.h" #include "SecurityOrigin.h" #include "Settings.h" #include "StyleScope.h" #include "TextEncoding.h" +#include "TypingCommand.h" #include "UserGestureIndicator.h" #include #include +#include #include #include #include @@ -337,6 +343,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien , m_frontendDispatcher(makeUnique(context.frontendRouter)) , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this)) , m_inspectedPage(context.inspectedPage) + , m_injectedScriptManager(context.injectedScriptManager) , m_client(client) , m_overlay(overlay) { @@ -412,14 +419,16 @@ void InspectorPageAgent::reload(ErrorString&, const bool* optionalReloadFromOrig m_inspectedPage.mainFrame().loader().reload(reloadOptions); } -void InspectorPageAgent::navigate(ErrorString&, const String& url) +void InspectorPageAgent::navigate(ErrorString& errorString, const String& url, const String* frameId) { UserGestureIndicator indicator { ProcessingUserGesture }; - Frame& frame = m_inspectedPage.mainFrame(); + Frame* frame = frameId ? assertFrame(errorString, *frameId) : &m_inspectedPage.mainFrame(); + if (!frame) + return; - ResourceRequest resourceRequest { frame.document()->completeURL(url) }; - FrameLoadRequest frameLoadRequest { *frame.document(), frame.document()->securityOrigin(), resourceRequest, "_self"_s, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown }; - frame.loader().changeLocation(WTFMove(frameLoadRequest)); + ResourceRequest resourceRequest { frame->document()->completeURL(url) }; + FrameLoadRequest frameLoadRequest { *frame->document(), frame->document()->securityOrigin(), resourceRequest, "_self"_s, LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown }; + frame->loader().changeLocation(WTFMove(frameLoadRequest)); } void InspectorPageAgent::overrideUserAgent(ErrorString&, const String* value) @@ -691,6 +700,7 @@ void InspectorPageAgent::loadEventFired() void InspectorPageAgent::frameNavigated(Frame& frame) { + mainWorldExecState(&frame); m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } @@ -761,6 +771,12 @@ void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame) m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame)); } +void InspectorPageAgent::didNavigateWithinPage(Frame& frame) +{ + String url = frame.document()->url().string(); + m_frontendDispatcher->navigatedWithinDocument(frameId(&frame), url); +} + void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance) { m_frontendDispatcher->defaultAppearanceDidChange(useDarkAppearance ? Inspector::Protocol::Page::Appearance::Dark : Inspector::Protocol::Page::Appearance::Light); @@ -815,6 +831,25 @@ void InspectorPageAgent::didRecalculateStyle() m_overlay->update(); } +void InspectorPageAgent::runOpenPanel(HTMLInputElement* element, bool* intercept) { + if (m_interceptFileChooserDialog) { + *intercept = true; + } else { + return; + } + Document& document = element->document(); + auto* frame = document.frame(); + if (!frame) + return; + + auto& state = *mainWorldExecState(frame); + auto injectedScript = m_injectedScriptManager.injectedScriptFor(&state); + if (injectedScript.hasNoValue()) + return; + + m_frontendDispatcher->fileChooserOpened(frameId(frame), injectedScript.wrapObject(InspectorDOMAgent::nodeAsScriptValue(state, element), WTF::String())); +} + Ref InspectorPageAgent::buildObjectForFrame(Frame* frame) { ASSERT_ARG(frame, frame); @@ -986,4 +1021,455 @@ void InspectorPageAgent::archive(ErrorString& errorString, String* data) #endif } +void InspectorPageAgent::insertText(ErrorString&, const String& text) { + UserGestureIndicator indicator { ProcessingUserGesture }; + Document* focusedDocument = m_inspectedPage.focusController().focusedOrMainFrame().document(); + TypingCommand::insertText(*focusedDocument, text, 0); +} + +static String roleFromObject(RefPtr axObject) { + String computedRoleString = axObject->computedRoleString(); + if (!computedRoleString.isEmpty()) + return computedRoleString; + AccessibilityRole role = axObject->roleValue(); + switch(role) { + case AccessibilityRole::Annotation: + return "Annotation"; + case AccessibilityRole::Application: + return "Application"; + case AccessibilityRole::ApplicationAlert: + return "ApplicationAlert"; + case AccessibilityRole::ApplicationAlertDialog: + return "ApplicationAlertDialog"; + case AccessibilityRole::ApplicationDialog: + return "ApplicationDialog"; + case AccessibilityRole::ApplicationGroup: + return "ApplicationGroup"; + case AccessibilityRole::ApplicationLog: + return "ApplicationLog"; + case AccessibilityRole::ApplicationMarquee: + return "ApplicationMarquee"; + case AccessibilityRole::ApplicationStatus: + return "ApplicationStatus"; + case AccessibilityRole::ApplicationTextGroup: + return "ApplicationTextGroup"; + case AccessibilityRole::ApplicationTimer: + return "ApplicationTimer"; + case AccessibilityRole::Audio: + return "Audio"; + case AccessibilityRole::Blockquote: + return "Blockquote"; + case AccessibilityRole::Browser: + return "Browser"; + case AccessibilityRole::BusyIndicator: + return "BusyIndicator"; + case AccessibilityRole::Button: + return "Button"; + case AccessibilityRole::Canvas: + return "Canvas"; + case AccessibilityRole::Caption: + return "Caption"; + case AccessibilityRole::Cell: + return "Cell"; + case AccessibilityRole::CheckBox: + return "CheckBox"; + case AccessibilityRole::ColorWell: + return "ColorWell"; + case AccessibilityRole::Column: + return "Column"; + case AccessibilityRole::ColumnHeader: + return "ColumnHeader"; + case AccessibilityRole::ComboBox: + return "ComboBox"; + case AccessibilityRole::Definition: + return "Definition"; + case AccessibilityRole::Deletion: + return "Deletion"; + case AccessibilityRole::DescriptionList: + return "DescriptionList"; + case AccessibilityRole::DescriptionListTerm: + return "DescriptionListTerm"; + case AccessibilityRole::DescriptionListDetail: + return "DescriptionListDetail"; + case AccessibilityRole::Details: + return "Details"; + case AccessibilityRole::Directory: + return "Directory"; + case AccessibilityRole::DisclosureTriangle: + return "DisclosureTriangle"; + case AccessibilityRole::Div: + return "Div"; + case AccessibilityRole::Document: + return "Document"; + case AccessibilityRole::DocumentArticle: + return "DocumentArticle"; + case AccessibilityRole::DocumentMath: + return "DocumentMath"; + case AccessibilityRole::DocumentNote: + return "DocumentNote"; + case AccessibilityRole::Drawer: + return "Drawer"; + case AccessibilityRole::EditableText: + return "EditableText"; + case AccessibilityRole::Feed: + return "Feed"; + case AccessibilityRole::Figure: + return "Figure"; + case AccessibilityRole::Footer: + return "Footer"; + case AccessibilityRole::Footnote: + return "Footnote"; + case AccessibilityRole::Form: + return "Form"; + case AccessibilityRole::GraphicsDocument: + return "GraphicsDocument"; + case AccessibilityRole::GraphicsObject: + return "GraphicsObject"; + case AccessibilityRole::GraphicsSymbol: + return "GraphicsSymbol"; + case AccessibilityRole::Grid: + return "Grid"; + case AccessibilityRole::GridCell: + return "GridCell"; + case AccessibilityRole::Group: + return "Group"; + case AccessibilityRole::GrowArea: + return "GrowArea"; + case AccessibilityRole::Heading: + return "Heading"; + case AccessibilityRole::HelpTag: + return "HelpTag"; + case AccessibilityRole::HorizontalRule: + return "HorizontalRule"; + case AccessibilityRole::Ignored: + return "Ignored"; + case AccessibilityRole::Inline: + return "Inline"; + case AccessibilityRole::Image: + return "Image"; + case AccessibilityRole::ImageMap: + return "ImageMap"; + case AccessibilityRole::ImageMapLink: + return "ImageMapLink"; + case AccessibilityRole::Incrementor: + return "Incrementor"; + case AccessibilityRole::Insertion: + return "Insertion"; + case AccessibilityRole::Label: + return "Label"; + case AccessibilityRole::LandmarkBanner: + return "LandmarkBanner"; + case AccessibilityRole::LandmarkComplementary: + return "LandmarkComplementary"; + case AccessibilityRole::LandmarkContentInfo: + return "LandmarkContentInfo"; + case AccessibilityRole::LandmarkDocRegion: + return "LandmarkDocRegion"; + case AccessibilityRole::LandmarkMain: + return "LandmarkMain"; + case AccessibilityRole::LandmarkNavigation: + return "LandmarkNavigation"; + case AccessibilityRole::LandmarkRegion: + return "LandmarkRegion"; + case AccessibilityRole::LandmarkSearch: + return "LandmarkSearch"; + case AccessibilityRole::Legend: + return "Legend"; + case AccessibilityRole::Link: + return "Link"; + case AccessibilityRole::List: + return "List"; + case AccessibilityRole::ListBox: + return "ListBox"; + case AccessibilityRole::ListBoxOption: + return "ListBoxOption"; + case AccessibilityRole::ListItem: + return "ListItem"; + case AccessibilityRole::ListMarker: + return "ListMarker"; + case AccessibilityRole::Mark: + return "Mark"; + case AccessibilityRole::MathElement: + return "MathElement"; + case AccessibilityRole::Matte: + return "Matte"; + case AccessibilityRole::Menu: + return "Menu"; + case AccessibilityRole::MenuBar: + return "MenuBar"; + case AccessibilityRole::MenuButton: + return "MenuButton"; + case AccessibilityRole::MenuItem: + return "MenuItem"; + case AccessibilityRole::MenuItemCheckbox: + return "MenuItemCheckbox"; + case AccessibilityRole::MenuItemRadio: + return "MenuItemRadio"; + case AccessibilityRole::MenuListPopup: + return "MenuListPopup"; + case AccessibilityRole::MenuListOption: + return "MenuListOption"; + case AccessibilityRole::Meter: + return "Meter"; + case AccessibilityRole::Outline: + return "Outline"; + case AccessibilityRole::Paragraph: + return "Paragraph"; + case AccessibilityRole::PopUpButton: + return "PopUpButton"; + case AccessibilityRole::Pre: + return "Pre"; + case AccessibilityRole::Presentational: + return "Presentational"; + case AccessibilityRole::ProgressIndicator: + return "ProgressIndicator"; + case AccessibilityRole::RadioButton: + return "RadioButton"; + case AccessibilityRole::RadioGroup: + return "RadioGroup"; + case AccessibilityRole::RowHeader: + return "RowHeader"; + case AccessibilityRole::Row: + return "Row"; + case AccessibilityRole::RowGroup: + return "RowGroup"; + case AccessibilityRole::RubyBase: + return "RubyBase"; + case AccessibilityRole::RubyBlock: + return "RubyBlock"; + case AccessibilityRole::RubyInline: + return "RubyInline"; + case AccessibilityRole::RubyRun: + return "RubyRun"; + case AccessibilityRole::RubyText: + return "RubyText"; + case AccessibilityRole::Ruler: + return "Ruler"; + case AccessibilityRole::RulerMarker: + return "RulerMarker"; + case AccessibilityRole::ScrollArea: + return "ScrollArea"; + case AccessibilityRole::ScrollBar: + return "ScrollBar"; + case AccessibilityRole::SearchField: + return "SearchField"; + case AccessibilityRole::Sheet: + return "Sheet"; + case AccessibilityRole::Slider: + return "Slider"; + case AccessibilityRole::SliderThumb: + return "SliderThumb"; + case AccessibilityRole::SpinButton: + return "SpinButton"; + case AccessibilityRole::SpinButtonPart: + return "SpinButtonPart"; + case AccessibilityRole::SplitGroup: + return "SplitGroup"; + case AccessibilityRole::Splitter: + return "Splitter"; + case AccessibilityRole::StaticText: + return "StaticText"; + case AccessibilityRole::Subscript: + return "Subscript"; + case AccessibilityRole::Summary: + return "Summary"; + case AccessibilityRole::Superscript: + return "Superscript"; + case AccessibilityRole::Switch: + return "Switch"; + case AccessibilityRole::SystemWide: + return "SystemWide"; + case AccessibilityRole::SVGRoot: + return "SVGRoot"; + case AccessibilityRole::SVGText: + return "SVGText"; + case AccessibilityRole::SVGTSpan: + return "SVGTSpan"; + case AccessibilityRole::SVGTextPath: + return "SVGTextPath"; + case AccessibilityRole::TabGroup: + return "TabGroup"; + case AccessibilityRole::TabList: + return "TabList"; + case AccessibilityRole::TabPanel: + return "TabPanel"; + case AccessibilityRole::Tab: + return "Tab"; + case AccessibilityRole::Table: + return "Table"; + case AccessibilityRole::TableHeaderContainer: + return "TableHeaderContainer"; + case AccessibilityRole::TextArea: + return "TextArea"; + case AccessibilityRole::TextGroup: + return "TextGroup"; + case AccessibilityRole::Term: + return "Term"; + case AccessibilityRole::Time: + return "Time"; + case AccessibilityRole::Tree: + return "Tree"; + case AccessibilityRole::TreeGrid: + return "TreeGrid"; + case AccessibilityRole::TreeItem: + return "TreeItem"; + case AccessibilityRole::TextField: + return "TextField"; + case AccessibilityRole::ToggleButton: + return "ToggleButton"; + case AccessibilityRole::Toolbar: + return "Toolbar"; + case AccessibilityRole::Unknown: + return "Unknown"; + case AccessibilityRole::UserInterfaceTooltip: + return "UserInterfaceTooltip"; + case AccessibilityRole::ValueIndicator: + return "ValueIndicator"; + case AccessibilityRole::Video: + return "Video"; + case AccessibilityRole::WebApplication: + return "WebApplication"; + case AccessibilityRole::WebArea: + return "WebArea"; + case AccessibilityRole::WebCoreLink: + return "WebCoreLink"; + case AccessibilityRole::Window: + return "Window"; + }; + return "Unknown"; +} + +static RefPtr snapshotForAXObject(RefPtr axObject) { + auto axNode = Inspector::Protocol::Page::AXNode::create() + .setRole(roleFromObject(axObject)) + .release(); + + if (!axObject->computedLabel().isEmpty()) + axNode->setName(axObject->computedLabel()); + if (!axObject->stringValue().isEmpty()) + axNode->setValue(JSON::Value::create(axObject->stringValue())); + if (!axObject->accessibilityDescription().isEmpty()) + axNode->setDescription(axObject->accessibilityDescription()); + if (!axObject->keyShortcutsValue().isEmpty()) + axNode->setKeyshortcuts(axObject->keyShortcutsValue()); + if (!axObject->valueDescription().isEmpty()) + axNode->setValuetext(axObject->valueDescription()); + if (!axObject->isEnabled()) + axNode->setDisabled(!axObject->isEnabled()); + if (axObject->supportsExpanded()) + axNode->setExpanded(axObject->isExpanded()); + if (axObject->isFocused()) + axNode->setFocused(axObject->isFocused()); + if (axObject->isModalNode()) + axNode->setModal(axObject->isModalNode()); + bool multiline = axObject->ariaIsMultiline() || axObject->roleValue() == AccessibilityRole::TextArea; + if (multiline) + axNode->setMultiline(multiline); + if (axObject->isMultiSelectable()) + axNode->setMultiselectable(axObject->isMultiSelectable()); + if (axObject->supportsReadOnly()) + axNode->setReadonly(axObject->readOnlyValue() != "false"); + if (axObject->supportsRequiredAttribute()) + axNode->setRequired(axObject->isRequired()); + if (axObject->isSelected()) + axNode->setSelected(axObject->isSelected()); + if (axObject->supportsChecked()) { + AccessibilityButtonState checkedState = axObject->checkboxOrRadioValue(); + switch (checkedState) { + case AccessibilityButtonState::On: + axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::True); + break; + case AccessibilityButtonState::Off: + axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::False); + break; + case AccessibilityButtonState::Mixed: + axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::Mixed); + break; + } + } + if (axObject->supportsPressed()) { + AccessibilityButtonState checkedState = axObject->checkboxOrRadioValue(); + switch (checkedState) { + case AccessibilityButtonState::On: + axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::True); + break; + case AccessibilityButtonState::Off: + axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::False); + break; + case AccessibilityButtonState::Mixed: + axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::Mixed); + break; + } + } + unsigned level = axObject->hierarchicalLevel() ? axObject->hierarchicalLevel() : axObject->headingLevel(); + if (level) + axNode->setLevel(level); + if (axObject->minValueForRange() != 0) + axNode->setValuemin(axObject->minValueForRange()); + if (axObject->maxValueForRange() != 0) + axNode->setValuemax(axObject->maxValueForRange()); + if (axObject->supportsAutoComplete()) + axNode->setAutocomplete(axObject->autoCompleteValue()); + if (axObject->hasPopup()) + axNode->setHaspopup(axObject->popupValue()); + + String invalidValue = axObject->invalidStatus(); + if (invalidValue != "false") { + if (invalidValue == "grammar") + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Grammar); + else if (invalidValue == "spelling") + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Spelling); + else // Future versions of ARIA may allow additional truthy values. Ex. format, order, or size. + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::True); + } + switch (axObject->orientation()) { + case AccessibilityOrientation::Undefined: + break; + case AccessibilityOrientation::Vertical: + axNode->setOrientation("vertical"_s); + break; + case AccessibilityOrientation::Horizontal: + axNode->setOrientation("horizontal"_s); + break; + } + + if (axObject->isKeyboardFocusable()) + axNode->setFocusable(axObject->isKeyboardFocusable()); + + if (axObject->hasChildren()) { + RefPtr> children = JSON::ArrayOf::create(); + for (auto& childObject : axObject->children()) + children->addItem(snapshotForAXObject(childObject)); + axNode->setChildren(children); + } + return axNode; +} + + +void InspectorPageAgent::accessibilitySnapshot(ErrorString& errorString, RefPtr& out_axNode) { + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); + auto document = makeRefPtr(m_inspectedPage.mainFrame().document()); + if (!document) { + errorString = "No document for main frame"_s; + return; + } + AXObjectCache* axObjectCache = document->axObjectCache(); + if (!axObjectCache) { + errorString = "No AXObjectCache for main document"_s; + return; + } + AXCoreObject* axObject = axObjectCache->rootObject(); + if (!axObject) { + errorString = "No AXObject for main document"_s; + return; + } + + out_axNode = snapshotForAXObject(makeRefPtr(axObject)); +} + +void InspectorPageAgent::setInterceptFileChooserDialog(ErrorString&, bool enabled) { + m_interceptFileChooserDialog = enabled; +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h index 4fd8c0b1016..50712625607 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h @@ -40,10 +40,15 @@ #include #include +namespace Inspector { +class InjectedScriptManager; +} + namespace WebCore { class DocumentLoader; class Frame; +class HTMLInputElement; class InspectorClient; class InspectorOverlay; class Page; @@ -96,7 +101,7 @@ public: void enable(ErrorString&) override; void disable(ErrorString&) override; void reload(ErrorString&, const bool* optionalReloadFromOrigin, const bool* optionalRevalidateAllResources) override; - void navigate(ErrorString&, const String& url) override; + void navigate(ErrorString&, const String& url, const String* frameId) override; void overrideUserAgent(ErrorString&, const String* value) override; void overrideSetting(ErrorString&, const String& setting, const bool* value) override; void getCookies(ErrorString&, RefPtr>& cookies) override; @@ -113,8 +118,11 @@ public: void getCompositingBordersVisible(ErrorString&, bool* out_param) override; void setCompositingBordersVisible(ErrorString&, bool) override; void snapshotNode(ErrorString&, int nodeId, String* outDataURL) override; - void snapshotRect(ErrorString&, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL) override; + void snapshotRect(ErrorString&, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL) override; void archive(ErrorString&, String* data) override; + void insertText(ErrorString&, const String& text) override; + void accessibilitySnapshot(ErrorString&, RefPtr& out_axNode) override; + void setInterceptFileChooserDialog(ErrorString&, bool enabled) override; // InspectorInstrumentation void domContentEventFired(); @@ -126,6 +134,7 @@ public: void frameStoppedLoading(Frame&); void frameScheduledNavigation(Frame&, Seconds delay); void frameClearedScheduledNavigation(Frame&); + void didNavigateWithinPage(Frame&); void defaultAppearanceDidChange(bool useDarkAppearance); void applyUserAgentOverride(String&); void applyEmulatedMedia(String&); @@ -134,6 +143,7 @@ public: void didLayout(); void didScroll(); void didRecalculateStyle(); + void runOpenPanel(HTMLInputElement* element, bool* intercept); Frame* frameForId(const String& frameId); WEBCORE_EXPORT String frameId(Frame*); @@ -153,6 +163,7 @@ private: RefPtr m_backendDispatcher; Page& m_inspectedPage; + Inspector::InjectedScriptManager& m_injectedScriptManager; InspectorClient* m_client { nullptr }; InspectorOverlay* m_overlay { nullptr }; @@ -165,6 +176,7 @@ private: String m_bootstrapScript; bool m_isFirstLayoutAfterOnLoad { false }; bool m_showPaintRects { false }; + bool m_interceptFileChooserDialog { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp index 8c4a104da04..3dc08926a75 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp @@ -70,14 +70,12 @@ PageRuntimeAgent::~PageRuntimeAgent() = default; void PageRuntimeAgent::enable(ErrorString& errorString) { - bool enabled = m_instrumentingAgents.pageRuntimeAgent() == this; + if (m_instrumentingAgents.pageRuntimeAgent() == this) + return; + reportExecutionContextCreation(); InspectorRuntimeAgent::enable(errorString); - m_instrumentingAgents.setPageRuntimeAgent(this); - - if (!enabled) - reportExecutionContextCreation(); } void PageRuntimeAgent::disable(ErrorString& errorString) @@ -142,8 +140,10 @@ void PageRuntimeAgent::reportExecutionContextCreation() frame->script().collectIsolatedContexts(isolatedContexts); if (isolatedContexts.isEmpty()) continue; - for (auto& context : isolatedContexts) - notifyContextCreated(frameId, context.first, context.second, false); + for (auto& context : isolatedContexts) { + if (scriptState != context.first) + notifyContextCreated(frameId, context.first, context.second, false); + } isolatedContexts.clear(); } } diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 9b4211b4212..5881bd624df 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -1179,6 +1179,7 @@ void FrameLoader::loadInSameDocument(const URL& url, SerializedScriptValue* stat } m_client.dispatchDidNavigateWithinPage(); + InspectorInstrumentation::didNavigateWithinPage(m_frame); m_frame.document()->statePopped(stateObject ? Ref { *stateObject } : SerializedScriptValue::nullValue()); m_client.dispatchDidPopStateWithinPage(); diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index 9c58b06f4c4..3d624733c36 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -259,6 +259,7 @@ ExceptionOr History::stateObjectAdded(RefPtr&& data if (!urlString.isEmpty()) frame->document()->updateURLForPushOrReplaceState(fullURL); + InspectorInstrumentation::didNavigateWithinPage(*frame); if (stateObjectType == StateObjectType::Push) { frame->loader().history().pushState(WTFMove(data), title, fullURL.string()); diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h index 4aaf5bde32b..e9c047d4f26 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -147,6 +147,7 @@ namespace WebCore { static String keyCodeForHardwareKeyCode(unsigned); static String keyIdentifierForGdkKeyCode(unsigned); static int windowsKeyCodeForGdkKeyCode(unsigned); + static unsigned gdkKeyCodeForWindowsKeyCode(int); static String singleCharacterString(unsigned); static bool modifiersContainCapsLock(unsigned); #endif @@ -156,6 +157,7 @@ namespace WebCore { static String keyCodeForHardwareKeyCode(unsigned); static String keyIdentifierForWPEKeyCode(unsigned); static int windowsKeyCodeForWPEKeyCode(unsigned); + static unsigned WPEKeyCodeForWindowsKeyCode(int); static String singleCharacterString(unsigned); #endif diff --git a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp index 356b09f2fba..8f0c19b6031 100644 --- a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp @@ -36,8 +36,10 @@ #include "WindowsKeyboardCodes.h" #include #include +#include #include #include +#include namespace WebCore { @@ -1293,6 +1295,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(unsigned keycode) } +static const HashMap& gdkToWindowsKeyCodeMap() +{ + static HashMap* result; + static std::once_flag once; + std::call_once( + once, + [] { + const unsigned gdkKeyCodes[] = { + GDK_KEY_Cancel, + // FIXME: non-keypad keys should take precedence, so we skip GDK_KEY_KP_* + // GDK_KEY_KP_0, + // GDK_KEY_KP_1, + // GDK_KEY_KP_2, + // GDK_KEY_KP_3, + // GDK_KEY_KP_4, + // GDK_KEY_KP_5, + // GDK_KEY_KP_6, + // GDK_KEY_KP_7, + // GDK_KEY_KP_8, + // GDK_KEY_KP_9, + // GDK_KEY_KP_Multiply, + // GDK_KEY_KP_Add, + // GDK_KEY_KP_Subtract, + // GDK_KEY_KP_Decimal, + // GDK_KEY_KP_Divide, + // GDK_KEY_KP_Page_Up, + // GDK_KEY_KP_Page_Down, + // GDK_KEY_KP_End, + // GDK_KEY_KP_Home, + // GDK_KEY_KP_Left, + // GDK_KEY_KP_Up, + // GDK_KEY_KP_Right, + // GDK_KEY_KP_Down, + GDK_KEY_BackSpace, + // GDK_KEY_ISO_Left_Tab, + // GDK_KEY_3270_BackTab, + GDK_KEY_Tab, + GDK_KEY_Clear, + // GDK_KEY_ISO_Enter, + // GDK_KEY_KP_Enter, + GDK_KEY_Return, + GDK_KEY_Menu, + GDK_KEY_Pause, + GDK_KEY_AudioPause, + GDK_KEY_Caps_Lock, + GDK_KEY_Kana_Lock, + GDK_KEY_Kana_Shift, + GDK_KEY_Hangul, + GDK_KEY_Hangul_Hanja, + GDK_KEY_Kanji, + GDK_KEY_Escape, + GDK_KEY_space, + GDK_KEY_Page_Up, + GDK_KEY_Page_Down, + GDK_KEY_End, + GDK_KEY_Home, + GDK_KEY_Left, + GDK_KEY_Up, + GDK_KEY_Right, + GDK_KEY_Down, + GDK_KEY_Select, + GDK_KEY_Print, + GDK_KEY_Execute, + GDK_KEY_Insert, + GDK_KEY_KP_Insert, + GDK_KEY_Delete, + GDK_KEY_KP_Delete, + GDK_KEY_Help, + GDK_KEY_0, + GDK_KEY_parenright, + GDK_KEY_1, + GDK_KEY_exclam, + GDK_KEY_2, + GDK_KEY_at, + GDK_KEY_3, + GDK_KEY_numbersign, + GDK_KEY_4, + GDK_KEY_dollar, + GDK_KEY_5, + GDK_KEY_percent, + GDK_KEY_6, + GDK_KEY_asciicircum, + GDK_KEY_7, + GDK_KEY_ampersand, + GDK_KEY_8, + GDK_KEY_asterisk, + GDK_KEY_9, + GDK_KEY_parenleft, + GDK_KEY_a, + GDK_KEY_A, + GDK_KEY_b, + GDK_KEY_B, + GDK_KEY_c, + GDK_KEY_C, + GDK_KEY_d, + GDK_KEY_D, + GDK_KEY_e, + GDK_KEY_E, + GDK_KEY_f, + GDK_KEY_F, + GDK_KEY_g, + GDK_KEY_G, + GDK_KEY_h, + GDK_KEY_H, + GDK_KEY_i, + GDK_KEY_I, + GDK_KEY_j, + GDK_KEY_J, + GDK_KEY_k, + GDK_KEY_K, + GDK_KEY_l, + GDK_KEY_L, + GDK_KEY_m, + GDK_KEY_M, + GDK_KEY_n, + GDK_KEY_N, + GDK_KEY_o, + GDK_KEY_O, + GDK_KEY_p, + GDK_KEY_P, + GDK_KEY_q, + GDK_KEY_Q, + GDK_KEY_r, + GDK_KEY_R, + GDK_KEY_s, + GDK_KEY_S, + GDK_KEY_t, + GDK_KEY_T, + GDK_KEY_u, + GDK_KEY_U, + GDK_KEY_v, + GDK_KEY_V, + GDK_KEY_w, + GDK_KEY_W, + GDK_KEY_x, + GDK_KEY_X, + GDK_KEY_y, + GDK_KEY_Y, + GDK_KEY_z, + GDK_KEY_Z, + GDK_KEY_Meta_L, + GDK_KEY_Meta_R, + GDK_KEY_Sleep, + GDK_KEY_Num_Lock, + GDK_KEY_Scroll_Lock, + GDK_KEY_Shift_L, + GDK_KEY_Shift_R, + GDK_KEY_Control_L, + GDK_KEY_Control_R, + GDK_KEY_Alt_L, + GDK_KEY_Alt_R, + GDK_KEY_Back, + GDK_KEY_Forward, + GDK_KEY_Refresh, + GDK_KEY_Stop, + GDK_KEY_Search, + GDK_KEY_Favorites, + GDK_KEY_HomePage, + GDK_KEY_AudioMute, + GDK_KEY_AudioLowerVolume, + GDK_KEY_AudioRaiseVolume, + GDK_KEY_AudioNext, + GDK_KEY_AudioPrev, + GDK_KEY_AudioStop, + GDK_KEY_AudioMedia, + GDK_KEY_semicolon, + GDK_KEY_colon, + GDK_KEY_plus, + GDK_KEY_equal, + GDK_KEY_comma, + GDK_KEY_less, + GDK_KEY_minus, + GDK_KEY_underscore, + GDK_KEY_period, + GDK_KEY_greater, + GDK_KEY_slash, + GDK_KEY_question, + GDK_KEY_asciitilde, + GDK_KEY_quoteleft, + GDK_KEY_bracketleft, + GDK_KEY_braceleft, + GDK_KEY_backslash, + GDK_KEY_bar, + GDK_KEY_bracketright, + GDK_KEY_braceright, + GDK_KEY_quoteright, + GDK_KEY_quotedbl, + GDK_KEY_AudioRewind, + GDK_KEY_AudioForward, + GDK_KEY_AudioPlay, + GDK_KEY_F1, + GDK_KEY_F2, + GDK_KEY_F3, + GDK_KEY_F4, + GDK_KEY_F5, + GDK_KEY_F6, + GDK_KEY_F7, + GDK_KEY_F8, + GDK_KEY_F9, + GDK_KEY_F10, + GDK_KEY_F11, + GDK_KEY_F12, + GDK_KEY_F13, + GDK_KEY_F14, + GDK_KEY_F15, + GDK_KEY_F16, + GDK_KEY_F17, + GDK_KEY_F18, + GDK_KEY_F19, + GDK_KEY_F20, + GDK_KEY_F21, + GDK_KEY_F22, + GDK_KEY_F23, + GDK_KEY_F24, + GDK_KEY_VoidSymbol, + GDK_KEY_Red, + GDK_KEY_Green, + GDK_KEY_Yellow, + GDK_KEY_Blue, + GDK_KEY_PowerOff, + GDK_KEY_AudioRecord, + GDK_KEY_Display, + GDK_KEY_Subtitle, + GDK_KEY_Video + }; + result = new HashMap(); + for (unsigned gdkKeyCode : gdkKeyCodes) { + int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(gdkKeyCode); + // If several gdk key codes map to the same win key code first one is used. + result->add(winKeyCode, gdkKeyCode); + } + }); + return *result; +} + +unsigned PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(int keycode) +{ + return gdkToWindowsKeyCodeMap().get(keycode); +} + String PlatformKeyboardEvent::singleCharacterString(unsigned val) { switch (val) { diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp index cf46da15083..efbda20f28b 100644 --- a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp @@ -1291,6 +1291,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(unsigned keycode) return 0; } +static const HashMap& WPEToWindowsKeyCodeMap() +{ + static HashMap* result; + static std::once_flag once; + std::call_once( + once, + [] { + const unsigned WPEKeyCodes[] = { + WPE_KEY_Cancel, + // FIXME: non-keypad keys should take precedence, so we skip WPE_KEY_KP_* + // WPE_KEY_KP_0, + // WPE_KEY_KP_1, + // WPE_KEY_KP_2, + // WPE_KEY_KP_3, + // WPE_KEY_KP_4, + // WPE_KEY_KP_5, + // WPE_KEY_KP_6, + // WPE_KEY_KP_7, + // WPE_KEY_KP_8, + // WPE_KEY_KP_9, + // WPE_KEY_KP_Multiply, + // WPE_KEY_KP_Add, + // WPE_KEY_KP_Subtract, + // WPE_KEY_KP_Decimal, + // WPE_KEY_KP_Divide, + // WPE_KEY_KP_Page_Up, + // WPE_KEY_KP_Page_Down, + // WPE_KEY_KP_End, + // WPE_KEY_KP_Home, + // WPE_KEY_KP_Left, + // WPE_KEY_KP_Up, + // WPE_KEY_KP_Right, + // WPE_KEY_KP_Down, + WPE_KEY_BackSpace, + // WPE_KEY_ISO_Left_Tab, + // WPE_KEY_3270_BackTab, + WPE_KEY_Tab, + WPE_KEY_Clear, + // WPE_KEY_ISO_Enter, + // WPE_KEY_KP_Enter, + WPE_KEY_Return, + WPE_KEY_Menu, + WPE_KEY_Pause, + WPE_KEY_AudioPause, + WPE_KEY_Caps_Lock, + WPE_KEY_Kana_Lock, + WPE_KEY_Kana_Shift, + WPE_KEY_Hangul, + WPE_KEY_Hangul_Hanja, + WPE_KEY_Kanji, + WPE_KEY_Escape, + WPE_KEY_space, + WPE_KEY_Page_Up, + WPE_KEY_Page_Down, + WPE_KEY_End, + WPE_KEY_Home, + WPE_KEY_Left, + WPE_KEY_Up, + WPE_KEY_Right, + WPE_KEY_Down, + WPE_KEY_Select, + WPE_KEY_Print, + WPE_KEY_Execute, + WPE_KEY_Insert, + WPE_KEY_KP_Insert, + WPE_KEY_Delete, + WPE_KEY_KP_Delete, + WPE_KEY_Help, + WPE_KEY_0, + WPE_KEY_parenright, + WPE_KEY_1, + WPE_KEY_exclam, + WPE_KEY_2, + WPE_KEY_at, + WPE_KEY_3, + WPE_KEY_numbersign, + WPE_KEY_4, + WPE_KEY_dollar, + WPE_KEY_5, + WPE_KEY_percent, + WPE_KEY_6, + WPE_KEY_asciicircum, + WPE_KEY_7, + WPE_KEY_ampersand, + WPE_KEY_8, + WPE_KEY_asterisk, + WPE_KEY_9, + WPE_KEY_parenleft, + WPE_KEY_a, + WPE_KEY_A, + WPE_KEY_b, + WPE_KEY_B, + WPE_KEY_c, + WPE_KEY_C, + WPE_KEY_d, + WPE_KEY_D, + WPE_KEY_e, + WPE_KEY_E, + WPE_KEY_f, + WPE_KEY_F, + WPE_KEY_g, + WPE_KEY_G, + WPE_KEY_h, + WPE_KEY_H, + WPE_KEY_i, + WPE_KEY_I, + WPE_KEY_j, + WPE_KEY_J, + WPE_KEY_k, + WPE_KEY_K, + WPE_KEY_l, + WPE_KEY_L, + WPE_KEY_m, + WPE_KEY_M, + WPE_KEY_n, + WPE_KEY_N, + WPE_KEY_o, + WPE_KEY_O, + WPE_KEY_p, + WPE_KEY_P, + WPE_KEY_q, + WPE_KEY_Q, + WPE_KEY_r, + WPE_KEY_R, + WPE_KEY_s, + WPE_KEY_S, + WPE_KEY_t, + WPE_KEY_T, + WPE_KEY_u, + WPE_KEY_U, + WPE_KEY_v, + WPE_KEY_V, + WPE_KEY_w, + WPE_KEY_W, + WPE_KEY_x, + WPE_KEY_X, + WPE_KEY_y, + WPE_KEY_Y, + WPE_KEY_z, + WPE_KEY_Z, + WPE_KEY_Meta_L, + WPE_KEY_Meta_R, + WPE_KEY_Sleep, + WPE_KEY_Num_Lock, + WPE_KEY_Scroll_Lock, + WPE_KEY_Shift_L, + WPE_KEY_Shift_R, + WPE_KEY_Control_L, + WPE_KEY_Control_R, + WPE_KEY_Alt_L, + WPE_KEY_Alt_R, + WPE_KEY_Back, + WPE_KEY_Forward, + WPE_KEY_Refresh, + WPE_KEY_Stop, + WPE_KEY_Search, + WPE_KEY_Favorites, + WPE_KEY_HomePage, + WPE_KEY_AudioMute, + WPE_KEY_AudioLowerVolume, + WPE_KEY_AudioRaiseVolume, + WPE_KEY_AudioNext, + WPE_KEY_AudioPrev, + WPE_KEY_AudioStop, + WPE_KEY_AudioMedia, + WPE_KEY_semicolon, + WPE_KEY_colon, + WPE_KEY_plus, + WPE_KEY_equal, + WPE_KEY_comma, + WPE_KEY_less, + WPE_KEY_minus, + WPE_KEY_underscore, + WPE_KEY_period, + WPE_KEY_greater, + WPE_KEY_slash, + WPE_KEY_question, + WPE_KEY_asciitilde, + WPE_KEY_quoteleft, + WPE_KEY_bracketleft, + WPE_KEY_braceleft, + WPE_KEY_backslash, + WPE_KEY_bar, + WPE_KEY_bracketright, + WPE_KEY_braceright, + WPE_KEY_quoteright, + WPE_KEY_quotedbl, + WPE_KEY_AudioRewind, + WPE_KEY_AudioForward, + WPE_KEY_AudioPlay, + WPE_KEY_F1, + WPE_KEY_F2, + WPE_KEY_F3, + WPE_KEY_F4, + WPE_KEY_F5, + WPE_KEY_F6, + WPE_KEY_F7, + WPE_KEY_F8, + WPE_KEY_F9, + WPE_KEY_F10, + WPE_KEY_F11, + WPE_KEY_F12, + WPE_KEY_F13, + WPE_KEY_F14, + WPE_KEY_F15, + WPE_KEY_F16, + WPE_KEY_F17, + WPE_KEY_F18, + WPE_KEY_F19, + WPE_KEY_F20, + WPE_KEY_F21, + WPE_KEY_F22, + WPE_KEY_F23, + WPE_KEY_F24, + WPE_KEY_VoidSymbol, + WPE_KEY_Red, + WPE_KEY_Green, + WPE_KEY_Yellow, + WPE_KEY_Blue, + WPE_KEY_PowerOff, + WPE_KEY_AudioRecord, + WPE_KEY_Display, + WPE_KEY_Subtitle, + WPE_KEY_Video + }; + result = new HashMap(); + for (unsigned WPEKeyCode : WPEKeyCodes) { + int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(WPEKeyCode); + // If several gdk key codes map to the same win key code first one is used. + result->add(winKeyCode, WPEKeyCode); + } + }); + return *result; +} + +unsigned PlatformKeyboardEvent::WPEKeyCodeForWindowsKeyCode(int keycode) +{ + return WPEToWindowsKeyCodeMap().get(keycode); +} + String PlatformKeyboardEvent::singleCharacterString(unsigned val) { switch (val) { diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp index dfc490d2a0b..0bcd1d98ad8 100644 --- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp +++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp @@ -394,8 +394,13 @@ void NetworkStorageSession::getHostnamesWithCookies(HashSet& hostnames) Vector NetworkStorageSession::getAllCookies() { - // FIXME: Implement for WK2 to use. - return { }; + Vector cookies; + GUniquePtr cookiesList(soup_cookie_jar_all_cookies(cookieStorage())); + for (GSList* item = cookiesList.get(); item; item = g_slist_next(item)) { + GUniquePtr soupCookie(static_cast(item->data)); + cookies.append(WebCore::Cookie(soupCookie.get())); + } + return cookies; } Vector NetworkStorageSession::getCookies(const URL& url) diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp index 5f23cc66aa1..488c3c3bbae 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "NetworkProcess.h" - #include "ArgumentCoders.h" #include "Attachment.h" #include "AuthenticationManager.h" @@ -580,6 +579,35 @@ void NetworkProcess::destroySession(PAL::SessionID sessionID) m_storageQuotaManagers.remove(sessionID); } +void NetworkProcess::getAllCookies(PAL::SessionID sessionID, CompletionHandler&&)>&& completionHandler) +{ + if (auto* networkStorageSession = storageSession(sessionID)) { + completionHandler(networkStorageSession->getAllCookies()); + return; + } + completionHandler({ }); +} + +void NetworkProcess::setCookies(PAL::SessionID sessionID, Vector cookies, CompletionHandler&& completionHandler) { + if (auto* networkStorageSession = storageSession(sessionID)) { + for (auto cookie : cookies) + networkStorageSession->setCookie(cookie); + completionHandler(true); + return; + } + completionHandler(false); +} + +void NetworkProcess::deleteAllCookies(PAL::SessionID sessionID, CompletionHandler&& completionHandler) +{ + if (auto* networkStorageSession = storageSession(sessionID)) { + networkStorageSession->deleteAllCookies(); + completionHandler(true); + return; + } + completionHandler(false); +} + #if ENABLE(RESOURCE_LOAD_STATISTICS) void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler&& completionHandler) { diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h index f62f01d380f..e33439eb278 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h @@ -74,6 +74,7 @@ class SessionID; namespace WebCore { class CertificateInfo; +struct Cookie; class CurlProxySettings; class DownloadID; class ProtectionSpace; @@ -200,6 +201,10 @@ public: void addWebsiteDataStore(WebsiteDataStoreParameters&&); + void getAllCookies(PAL::SessionID, CompletionHandler&&)>&&); + void setCookies(PAL::SessionID, Vector, CompletionHandler&&); + void deleteAllCookies(PAL::SessionID, CompletionHandler&&); + #if ENABLE(RESOURCE_LOAD_STATISTICS) void clearPrevalentResource(PAL::SessionID, const RegistrableDomain&, CompletionHandler&&); void clearUserInteraction(PAL::SessionID, const RegistrableDomain&, CompletionHandler&&); diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in index 3677677480b..2873e1c0f59 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in @@ -79,6 +79,10 @@ messages -> NetworkProcess LegacyReceiver { PrepareToSuspend(bool isSuspensionImminent) -> () Async ProcessDidResume() + GetAllCookies(PAL::SessionID sessionID) -> (Vector cookies) Async + SetCookies(PAL::SessionID sessionID, Vector cookies) -> (bool success) Async + DeleteAllCookies(PAL::SessionID sessionID) -> (bool success) Async + #if ENABLE(RESOURCE_LOAD_STATISTICS) ClearPrevalentResource(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () Async ClearUserInteraction(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () Async diff --git a/Source/WebKit/Shared/API/c/wpe/WebKit.h b/Source/WebKit/Shared/API/c/wpe/WebKit.h index 898e30b370d..74945e06fac 100644 --- a/Source/WebKit/Shared/API/c/wpe/WebKit.h +++ b/Source/WebKit/Shared/API/c/wpe/WebKit.h @@ -78,6 +78,7 @@ // From Source/WebKit/UIProcess/API/C #include #include +#include #include #include #include diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h index 6f4e29b7c65..9dd287efc40 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h +++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -34,6 +34,7 @@ #if USE(APPKIT) #include OBJC_CLASS NSView; +OBJC_CLASS NSEvent; namespace WebCore { struct KeypressCommand; @@ -70,6 +71,10 @@ public: enum class HandledByInputMethod : bool { No, Yes }; enum class FakedForComposition : bool { No, Yes }; NativeWebKeyboardEvent(GdkEvent*, const String&, HandledByInputMethod, FakedForComposition, Vector&& commands); + NativeWebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands)) + { + } #elif PLATFORM(IOS_FAMILY) enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(::WebEvent *, HandledByInputMethod); diff --git a/Source/WebKit/Shared/NativeWebMouseEvent.h b/Source/WebKit/Shared/NativeWebMouseEvent.h index 0fa557e9faa..db299d91de3 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h @@ -56,6 +56,10 @@ namespace WebKit { class NativeWebMouseEvent : public WebMouseEvent { public: + NativeWebMouseEvent(Type type, Button button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet modifiers, WallTime timestamp) + : WebMouseEvent(type, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp) + { + } #if USE(APPKIT) NativeWebMouseEvent(NSEvent *, NSEvent *lastPressureEvent, NSView *); #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/WebEvent.h b/Source/WebKit/Shared/WebEvent.h index c36100cf5c4..216402f0a24 100644 --- a/Source/WebKit/Shared/WebEvent.h +++ b/Source/WebKit/Shared/WebEvent.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -138,7 +139,7 @@ public: WebMouseEvent(); #if PLATFORM(MAC) - WebMouseEvent(Type, Button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet, WallTime timestamp, double force, SyntheticClickType = NoTap, int eventNumber = -1, int menuType = 0); + WebMouseEvent(Type, Button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet, WallTime timestamp, double force = 0, SyntheticClickType = NoTap, int eventNumber = -1, int menuType = 0); #else WebMouseEvent(Type, Button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet, WallTime timestamp, double force = 0, SyntheticClickType = NoTap); #endif @@ -258,6 +259,7 @@ public: WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector&, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); #elif PLATFORM(GTK) WebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, Vector&& commands, bool isKeypad, OptionSet, WallTime timestamp); + WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp, Vector&& commands); #elif PLATFORM(IOS_FAMILY) WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); #elif USE(LIBWPE) @@ -309,7 +311,7 @@ private: int32_t m_nativeVirtualKeyCode; int32_t m_macCharCode; #if USE(APPKIT) || USE(UIKIT_KEYBOARD_ADDITIONS) || PLATFORM(GTK) - bool m_handledByInputMethod; + bool m_handledByInputMethod = false; #endif #if USE(APPKIT) Vector m_commands; diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp index a5a23cf148e..390eaf847b6 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.cpp +++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp @@ -81,6 +81,28 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& ASSERT(isKeyboardEventType(type)); } +WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) +#if ENABLE(KEYBOARD_KEY_ATTRIBUTE) + , m_key(key) +#endif +#if ENABLE(KEYBOARD_CODE_ATTRIBUTE) + , m_code(code) +#endif + , m_keyIdentifier(keyIdentifier) + , m_windowsVirtualKeyCode(windowsVirtualKeyCode) + , m_nativeVirtualKeyCode(nativeVirtualKeyCode) + , m_macCharCode(0) + , m_commands(WTFMove(commands)) + , m_isAutoRepeat(isAutoRepeat) + , m_isKeypad(isKeypad) + , m_isSystemKey(isSystemKey) +{ + ASSERT(isKeyboardEventType(type)); +} + #elif PLATFORM(IOS_FAMILY) WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp index 45aa449644b..3a6b4169194 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -43,7 +43,7 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(GdkEvent* event, const String& te } NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event) - : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event.nativeEvent(), event.text(), event.handledByInputMethod(), Vector(event.commands()))) + : WebKeyboardEvent(event) , m_nativeEvent(gdk_event_copy(event.nativeEvent())) , m_text(event.text()) , m_handledByInputMethod(event.handledByInputMethod() ? HandledByInputMethod::Yes : HandledByInputMethod::No) diff --git a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp index 58e37fe3827..429d245ea99 100644 --- a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp @@ -38,8 +38,8 @@ NativeWebMouseEvent::NativeWebMouseEvent(GdkEvent* event, int eventClickCount, O } NativeWebMouseEvent::NativeWebMouseEvent(const NativeWebMouseEvent& event) - : WebMouseEvent(WebEventFactory::createWebMouseEvent(event.nativeEvent(), event.clickCount(), WebCore::IntPoint(event.deltaX(), event.deltaY()))) - , m_nativeEvent(gdk_event_copy(event.nativeEvent())) + : WebMouseEvent(event) + , m_nativeEvent(event.nativeEvent() ? gdk_event_copy(event.nativeEvent()) : nullptr) { } diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt index 3f7d3fb6216..f396e22edf5 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt @@ -241,17 +241,23 @@ Shared/WebsiteData/WebsiteData.cpp UIProcess/AuxiliaryProcessProxy.cpp UIProcess/BackgroundProcessResponsivenessTimer.cpp +UIProcess/BrowserInspectorController.cpp +UIProcess/BrowserInspectorPipe.cpp +UIProcess/BrowserInspectorTargetAgent.cpp UIProcess/DeviceIdHashSaltStorage.cpp UIProcess/DrawingAreaProxy.cpp UIProcess/FrameLoadState.cpp UIProcess/GeolocationPermissionRequestManagerProxy.cpp UIProcess/GeolocationPermissionRequestProxy.cpp +UIProcess/InspectorBrowserAgent.cpp +UIProcess/InspectorDialogAgent.cpp UIProcess/InspectorTargetProxy.cpp UIProcess/LegacyGlobalSettings.cpp UIProcess/PageLoadState.cpp UIProcess/ProcessAssertion.cpp UIProcess/ProcessThrottler.cpp UIProcess/ProvisionalPageProxy.cpp +UIProcess/RemoteInspectorPipe.cpp UIProcess/RemoteWebInspectorProxy.cpp UIProcess/ResponsivenessTimer.cpp UIProcess/StatisticsRequest.cpp @@ -293,6 +299,9 @@ UIProcess/WebPageDiagnosticLoggingClient.cpp UIProcess/WebPageGroup.cpp UIProcess/WebPageInjectedBundleClient.cpp UIProcess/WebPageInspectorController.cpp +UIProcess/WebPageInspectorEmulationAgent.cpp +UIProcess/WebPageInspectorInputAgent.cpp +UIProcess/WebPageInspectorTargetProxy.cpp UIProcess/WebPageProxy.cpp UIProcess/WebPasteboardProxy.cpp UIProcess/WebPreferences.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt index 63c4dfa10ab..c9a7dcf3dea 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt @@ -243,6 +243,7 @@ UIProcess/API/Cocoa/_WKApplicationManifest.mm UIProcess/API/Cocoa/_WKAttachment.mm UIProcess/API/Cocoa/_WKAutomationSession.mm UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm +UIProcess/API/Cocoa/_WKBrowserInspector.mm UIProcess/API/Cocoa/_WKContentRuleListAction.mm UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @no-unify diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt index 1a05e334343..33e6d47f028 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -128,6 +128,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify +UIProcess/API/glib/WebKitBrowserInspector.cpp @no-unify UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify UIProcess/API/glib/WebKitCookieManager.cpp @no-unify UIProcess/API/glib/WebKitCredential.cpp @no-unify @@ -224,6 +225,7 @@ UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp UIProcess/cairo/BackingStoreCairo.cpp @no-unify +UIProcess/glib/InspectorBrowserAgentClientGLib.cpp UIProcess/glib/RemoteInspectorClient.cpp UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp @@ -252,6 +254,9 @@ UIProcess/gtk/WebColorPickerGtk.cpp UIProcess/gtk/WebContextMenuProxyGtk.cpp UIProcess/gtk/WebDataListSuggestionsDropdownGtk.cpp UIProcess/gtk/WebInspectorProxyGtk.cpp +UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp +UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp +UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp UIProcess/gtk/WebKitInspectorWindow.cpp UIProcess/gtk/WebPageProxyGtk.cpp @no-unify UIProcess/gtk/WebPasteboardProxyGtk.cpp diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt index 3d200fa60e9..ced6b04bfd2 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -116,6 +116,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify +UIProcess/API/glib/WebKitBrowserInspector.cpp @no-unify UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify UIProcess/API/glib/WebKitCookieManager.cpp @no-unify UIProcess/API/glib/WebKitCredential.cpp @no-unify @@ -184,7 +185,7 @@ UIProcess/Automation/wpe/WebAutomationSessionWPE.cpp UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp UIProcess/geoclue/GeoclueGeolocationProvider.cpp - +UIProcess/glib/InspectorBrowserAgentClientGLib.cpp UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp UIProcess/glib/WebsiteDataStoreGLib.cpp @no-unify @@ -209,6 +210,9 @@ UIProcess/soup/WebProcessPoolSoup.cpp UIProcess/wpe/TextCheckerWPE.cpp UIProcess/wpe/WebInspectorProxyWPE.cpp UIProcess/wpe/WebPageProxyWPE.cpp +UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp +UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp +UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp UIProcess/wpe/WebPasteboardProxyWPE.cpp UIProcess/wpe/WebPreferencesWPE.cpp diff --git a/Source/WebKit/UIProcess/API/APIUIClient.h b/Source/WebKit/UIProcess/API/APIUIClient.h index 54513035b26..2d3200e4f6e 100644 --- a/Source/WebKit/UIProcess/API/APIUIClient.h +++ b/Source/WebKit/UIProcess/API/APIUIClient.h @@ -97,6 +97,7 @@ public: virtual void runJavaScriptAlert(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebCore::SecurityOriginData&&, Function&& completionHandler) { completionHandler(); } virtual void runJavaScriptConfirm(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebCore::SecurityOriginData&&, Function&& completionHandler) { completionHandler(false); } virtual void runJavaScriptPrompt(WebKit::WebPageProxy&, const WTF::String&, const WTF::String&, WebKit::WebFrameProxy*, WebCore::SecurityOriginData&&, Function&& completionHandler) { completionHandler(WTF::String()); } + virtual void handleJavaScriptDialog(WebKit::WebPageProxy&, bool, const WTF::String&) { } virtual void setStatusText(WebKit::WebPageProxy*, const WTF::String&) { } virtual void mouseDidMoveOverElement(WebKit::WebPageProxy&, const WebKit::WebHitTestResultData&, OptionSet, Object*) { } diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp index 19e273187ae..14b3ef74afb 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp @@ -1674,6 +1674,8 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient completionHandler(String()); } + void handleJavaScriptDialog(WebPageProxy&, bool, const String&) final { } + void setStatusText(WebPageProxy* page, const String& text) final { if (!m_client.setStatusText) @@ -1734,6 +1736,8 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient { if (!m_client.didNotHandleKeyEvent) return; + if (!event.nativeEvent()) + return; m_client.didNotHandleKeyEvent(toAPI(page), event.nativeEvent(), m_client.base.clientInfo); } diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h index cad87f3ef2a..66145a38463 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h @@ -123,6 +123,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler; +/*! @abstract Handle a JavaScript dialog. + @param webView The web view invoking the delegate method. + @param accept Whether to accept the dialog. + @param value Value to use for prompt dialog. + */ +- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(nullable NSString *)value; + #if TARGET_OS_IPHONE /*! @abstract Allows your app to determine whether or not the given element should show a preview. diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h index 726c4972aa0..c67f4087977 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h @@ -24,7 +24,6 @@ */ #import - #import NS_ASSUME_NONNULL_BEGIN @@ -78,6 +77,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) /*! @abstract Returns the cookie store representing HTTP cookies in this website data store. */ @property (nonatomic, readonly) WKHTTPCookieStore *httpCookieStore WK_API_AVAILABLE(macos(10.13), ios(11.0)); +- (uint64_t)sessionID; + @end NS_ASSUME_NONNULL_END diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm index 48467b7a833..eaca62adb3c 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm @@ -43,6 +43,7 @@ #import "_WKWebsiteDataStoreDelegate.h" #import #import +#import #import #import #import @@ -183,6 +184,11 @@ static WallTime toSystemClockTime(NSDate *date) }); } +- (uint64_t) sessionID +{ + return _websiteDataStore->sessionID().toUInt64(); +} + static Vector toWebsiteDataRecords(NSArray *dataRecords) { Vector result; diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h new file mode 100644 index 00000000000..aebcbc62682 --- /dev/null +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class WKWebView; + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserContext : NSObject +@property (nonatomic, strong) WKWebsiteDataStore *dataStore; +@property (nonatomic, strong) WKProcessPool *processPool; +@end + +@protocol _WKBrowserInspectorDelegate +- (WKWebView *)createNewPage:(uint64_t)sessionID; +- (_WKBrowserContext *)createBrowserContext; +- (void)deleteBrowserContext:(uint64_t)sessionID; +- (void)quit; +@end + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserInspector : NSObject ++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate; +@end + + +NS_ASSUME_NONNULL_END + diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm new file mode 100644 index 00000000000..d9497d2c862 --- /dev/null +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "_WKBrowserInspector.h" + +#include "BrowserInspectorPipe.h" +#include "InspectorBrowserAgentClientMac.h" +#include "WebsiteDataStore.h" + +#import "WKWebView.h" + +using namespace WebKit; + +@implementation _WKBrowserInspector + ++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate +{ +#if ENABLE(REMOTE_INSPECTOR) + WebsiteDataStore::defaultDataStore(); + initializeBrowserInspectorPipe(makeUnique(delegate)); +#endif +} + +@end + +@implementation _WKBrowserContext +@end diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp new file mode 100644 index 00000000000..c21192686c9 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp @@ -0,0 +1,114 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebKitBrowserInspector.h" + +#include "BrowserInspectorPipe.h" +#include "InspectorBrowserAgentClientGLib.h" +#include "WebKitBrowserInspectorPrivate.h" +#include "WebKitWebViewPrivate.h" +#include +#include + +/** + * SECTION: WebKitBrowserInspector + * @Short_description: Access to the WebKit browser inspector + * @Title: WebKitBrowserInspector + * + * The WebKit Browser Inspector is an experimental API that provides + * access to the inspector via the remote debugging protocol. The protocol + * allows to create ephemeral contexts and create pages in them and then + * manipulate them using the inspector commands. This may be useful for + * the browser automation or remote debugging. + * + * Currently the protocol can be exposed to the parent process via a unix + * pipe. + */ + +enum { + CREATE_NEW_PAGE, + + LAST_SIGNAL +}; + +struct _WebKitBrowserInspectorPrivate { + int unused { 0 }; +}; + +WEBKIT_DEFINE_TYPE(WebKitBrowserInspector, webkit_browser_inspector, G_TYPE_OBJECT) + +static guint signals[LAST_SIGNAL] = { 0, }; + +static void webkit_browser_inspector_class_init(WebKitBrowserInspectorClass* findClass) +{ + GObjectClass* gObjectClass = G_OBJECT_CLASS(findClass); + + /** + * WebKitBrowserInspector::create-new-page: + * @inspector: the #WebKitBrowserInspector on which the signal is emitted + * + * Emitted when the inspector is requested to create a new page in the provided + * #WebKitWebContext. + * + * This signal is emitted when inspector receives 'Browser.createPage' command + * from its remote client. If the signla is not handled the command will fail. + * + * Returns: %WebKitWebView that contains created page. + */ + signals[CREATE_NEW_PAGE] = g_signal_new( + "create-new-page", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitBrowserInspectorClass, create_new_page), + nullptr, nullptr, + g_cclosure_marshal_generic, +#if PLATFORM(GTK) + GTK_TYPE_WIDGET, +#else + WEBKIT_TYPE_WEB_VIEW, +#endif + 1, + WEBKIT_TYPE_WEB_CONTEXT); +} + +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext* context) +{ + WebKitWebView* newWebView; + g_signal_emit(webkit_browser_inspector_get_default(), signals[CREATE_NEW_PAGE], 0, context, &newWebView); + if (!newWebView) + return nullptr; + return &webkitWebViewGetPage(newWebView); +} + +static gpointer createWebKitBrowserInspector(gpointer) +{ + static GRefPtr browserInspector = adoptGRef(WEBKIT_BROWSER_INSPECTOR(g_object_new(WEBKIT_TYPE_BROWSER_INSPECTOR, nullptr))); + return browserInspector.get(); +} + +/** + * webkit_browser_inspector_get_default: + * + * Gets the default instance of the browser inspector. + * + * Returns: (transfer none): a #WebKitBrowserInspector + */ +WebKitBrowserInspector* webkit_browser_inspector_get_default(void) +{ + static GOnce onceInit = G_ONCE_INIT; + return WEBKIT_BROWSER_INSPECTOR(g_once(&onceInit, createWebKitBrowserInspector, 0)); +} + +/** + * webkit_browser_inspector_initialize_pipe: + * + * Creates browser inspector and configures pipe handler to communicate with + * the parent process. + */ +void webkit_browser_inspector_initialize_pipe(void) +{ +#if ENABLE(REMOTE_INSPECTOR) + WebKit::initializeBrowserInspectorPipe(makeUnique()); +#endif +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h new file mode 100644 index 00000000000..ab6b7621d10 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "WebKitBrowserInspector.h" +#include "WebPageProxy.h" + +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext*); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp index 47801342ea6..ef163b6615a 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp @@ -90,6 +90,10 @@ private: { webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTFMove(completionHandler)); } + void handleJavaScriptDialog(WebPageProxy&, bool accept, const String& value) final + { + webkitWebViewHandleJavaScriptDialog(m_webView, accept, value); + } bool canRunBeforeUnloadConfirmPanel() const final { return true; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 126bccf1314..a095db63bc5 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -373,6 +373,11 @@ static void webkitWebContextConstructed(GObject* object) if (!webkit_website_data_manager_is_ephemeral(priv->websiteDataManager.get())) WebKit::LegacyGlobalSettings::singleton().setHSTSStorageDirectory(FileSystem::stringFromFileSystemRepresentation(webkit_website_data_manager_get_hsts_cache_directory(priv->websiteDataManager.get()))); + const gchar *singleprocess = g_getenv("MINIBROWSER_SINGLEPROCESS"); + if (singleprocess && *singleprocess) { + // processModel is not set at this point, force single process. + configuration.setUsesSingleWebProcess(true); + } priv->processPool = WebProcessPool::create(configuration); priv->processPool->setPrimaryDataStore(webkitWebsiteDataManagerGetDataStore(priv->websiteDataManager.get())); priv->processPool->setUserMessageHandler([webContext](UserMessage&& message, CompletionHandler&& completionHandler) { diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index d21c782eded..c42842b14a7 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -2379,6 +2379,15 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const webkit_script_dialog_unref(webView->priv->currentScriptDialog); } +void webkitWebViewHandleJavaScriptDialog(WebKitWebView* webView, bool accept, const String& value) { + if (!value.isNull()) + webkitWebViewSetCurrentScriptDialogUserInput(webView, value); + if (accept) + webkitWebViewAcceptCurrentScriptDialog(webView); + else + webkitWebViewDismissCurrentScriptDialog(webView); +} + bool webkitWebViewIsShowingScriptDialog(WebKitWebView* webView) { if (!webView->priv->currentScriptDialog) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h index a5f99b325dd..9ab1efc678b 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h @@ -58,6 +58,7 @@ void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message, Fun void webkitWebViewRunJavaScriptConfirm(WebKitWebView*, const CString& message, Function&& completionHandler); void webkitWebViewRunJavaScriptPrompt(WebKitWebView*, const CString& message, const CString& defaultText, Function&& completionHandler); void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView*, const CString& message, Function&& completionHandler); +void webkitWebViewHandleJavaScriptDialog(WebKitWebView*, bool accept, const String& value); bool webkitWebViewIsShowingScriptDialog(WebKitWebView*); bool webkitWebViewIsScriptDialogRunning(WebKitWebView*, WebKitScriptDialog*); String webkitWebViewGetCurrentScriptDialogMessage(WebKitWebView*); diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp index 00b7c6bbc46..c3a6cf416e1 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp @@ -226,6 +226,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool return; if (event.fakedForComposition()) return; + if (!event.nativeEvent()) + return; WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(m_viewWidget); webkitWebViewBaseForwardNextKeyEvent(webkitWebViewBase); diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h new file mode 100644 index 00000000000..9bd1cd6c216 --- /dev/null +++ b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef WebKitBrowserInspector_h +#define WebKitBrowserInspector_h + +#include +#include +#include + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_BROWSER_INSPECTOR (webkit_browser_inspector_get_type()) +#define WEBKIT_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspector)) +#define WEBKIT_IS_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) +#define WEBKIT_IS_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) + +typedef struct _WebKitBrowserInspector WebKitBrowserInspector; +typedef struct _WebKitBrowserInspectorClass WebKitBrowserInspectorClass; +typedef struct _WebKitBrowserInspectorPrivate WebKitBrowserInspectorPrivate; + +struct _WebKitBrowserInspector { + GObject parent; + + WebKitBrowserInspectorPrivate *priv; +}; + +struct _WebKitBrowserInspectorClass { + GObjectClass parent_class; + + WebKitWebView *(* create_new_page) (WebKitBrowserInspector *browser_inspector, + WebKitWebContext *context); + + void (*_webkit_reserved0) (void); + void (*_webkit_reserved1) (void); + void (*_webkit_reserved2) (void); + void (*_webkit_reserved3) (void); +}; + +WEBKIT_API GType +webkit_browser_inspector_get_type (void); + +WEBKIT_API WebKitBrowserInspector * +webkit_browser_inspector_get_default (void); + +WEBKIT_API void +webkit_browser_inspector_initialize_pipe (void); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/gtk/webkit2.h b/Source/WebKit/UIProcess/API/gtk/webkit2.h index 4c196217e6f..a7208990a7e 100644 --- a/Source/WebKit/UIProcess/API/gtk/webkit2.h +++ b/Source/WebKit/UIProcess/API/gtk/webkit2.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h new file mode 100644 index 00000000000..11fde7598a3 --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#if !defined(__WEBKIT_H_INSIDE__) && !defined(WEBKIT2_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef WebKitBrowserInspector_h +#define WebKitBrowserInspector_h + +#include +#include +#include + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_BROWSER_INSPECTOR (webkit_browser_inspector_get_type()) +#define WEBKIT_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspector)) +#define WEBKIT_IS_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) +#define WEBKIT_IS_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) + +typedef struct _WebKitBrowserInspector WebKitBrowserInspector; +typedef struct _WebKitBrowserInspectorClass WebKitBrowserInspectorClass; +typedef struct _WebKitBrowserInspectorPrivate WebKitBrowserInspectorPrivate; + +struct _WebKitBrowserInspector { + GObject parent; + + WebKitBrowserInspectorPrivate *priv; +}; + +struct _WebKitBrowserInspectorClass { + GObjectClass parent_class; + + WebKitWebView *(* create_new_page) (WebKitBrowserInspector *browser_inspector, + WebKitWebContext *context); + + void (*_webkit_reserved0) (void); + void (*_webkit_reserved1) (void); + void (*_webkit_reserved2) (void); + void (*_webkit_reserved3) (void); +}; + +WEBKIT_API GType +webkit_browser_inspector_get_type (void); + +WEBKIT_API WebKitBrowserInspector * +webkit_browser_inspector_get_default (void); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/webkit.h b/Source/WebKit/UIProcess/API/wpe/webkit.h index 9cc31cb4968..930499e65b6 100644 --- a/Source/WebKit/UIProcess/API/wpe/webkit.h +++ b/Source/WebKit/UIProcess/API/wpe/webkit.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/Source/WebKit/UIProcess/BrowserInspectorController.cpp b/Source/WebKit/UIProcess/BrowserInspectorController.cpp new file mode 100644 index 00000000000..bd9351774f9 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorController.cpp @@ -0,0 +1,101 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "BrowserInspectorController.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "BrowserInspectorTargetAgent.h" +#include "InspectorBrowserAgent.h" +#include "InspectorBrowserAgentClient.h" +#include "WebPageInspectorController.h" +#include "WebPageProxy.h" +#include "WebProcessPool.h" +#include "WebProcessProxy.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace Inspector; + +namespace WebKit { + +static Vector allPages() +{ + ASSERT(isMainThread()); + Vector result; + for (WebProcessPool* pool : WebProcessPool::allProcessPools()) { + for (auto& process : pool->processes()) { + result.appendRange(process->pages().begin(), process->pages().end()); + } + } + return result; +} + +BrowserInspectorController::BrowserInspectorController(std::unique_ptr client) + : m_frontendChannel(nullptr) + , m_frontendRouter(FrontendRouter::create()) + , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) + , m_browserAgentClient(std::move(client)) +{ + m_agents.append(makeUnique(m_backendDispatcher, m_browserAgentClient.get())); + m_agents.append(makeUnique(m_backendDispatcher)); +} + +BrowserInspectorController::~BrowserInspectorController() = default; + +void BrowserInspectorController::connectFrontend(FrontendChannel& frontendChannel) +{ + ASSERT(!m_frontendChannel); + m_frontendChannel = &frontendChannel; + // Auto-connect to all new pages. + WebPageInspectorController::setCreationListener([this](WebPageInspectorController& inspectorController) { + inspectorController.connectFrontend(*m_frontendChannel); + }); + + bool connectingFirstFrontend = !m_frontendRouter->hasFrontends(); + m_frontendRouter->connectFrontend(frontendChannel); + if (connectingFirstFrontend) + m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get()); + + connectToAllPages(); +} + +void BrowserInspectorController::disconnectFrontend() +{ + ASSERT(m_frontendChannel); + disconnectFromAllPages(); + + m_frontendRouter->disconnectFrontend(*m_frontendChannel); + if (!m_frontendRouter->hasFrontends()) + m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed); + + WebPageInspectorController::setCreationListener(nullptr); + m_frontendChannel = nullptr; +} + +void BrowserInspectorController::dispatchMessageFromFrontend(const String& message) +{ + m_backendDispatcher->dispatch(message); +} + +void BrowserInspectorController::connectToAllPages() +{ + for (auto* page : allPages()) + page->inspectorController().connectFrontend(*m_frontendChannel); +} + +void BrowserInspectorController::disconnectFromAllPages() +{ + for (auto* page : allPages()) + page->inspectorController().disconnectFrontend(*m_frontendChannel); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorController.h b/Source/WebKit/UIProcess/BrowserInspectorController.h new file mode 100644 index 00000000000..9de68f71fbd --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorController.h @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class InspectorBrowserAgentClient; + +class BrowserInspectorController { + WTF_MAKE_NONCOPYABLE(BrowserInspectorController); + WTF_MAKE_FAST_ALLOCATED; +public: + BrowserInspectorController(std::unique_ptr client); + ~BrowserInspectorController(); + + void connectFrontend(Inspector::FrontendChannel&); + void disconnectFrontend(); + void dispatchMessageFromFrontend(const String& message); + +private: + class TargetHandler; + void connectToAllPages(); + void disconnectFromAllPages(); + + Inspector::FrontendChannel* m_frontendChannel { nullptr }; + Ref m_frontendRouter; + Ref m_backendDispatcher; + std::unique_ptr m_browserAgentClient; + Inspector::AgentRegistry m_agents; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp new file mode 100644 index 00000000000..46f05a2a45f --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "BrowserInspectorPipe.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "BrowserInspectorController.h" +#include "RemoteInspectorPipe.h" +#include +#include "InspectorBrowserAgentClient.h" + +namespace WebKit { + +void initializeBrowserInspectorPipe(std::unique_ptr client) +{ + class BrowserInspectorPipe { + public: + BrowserInspectorPipe(std::unique_ptr client) + : m_browserInspectorController(std::move(client)) + , m_remoteInspectorPipe(m_browserInspectorController) + { + } + + BrowserInspectorController m_browserInspectorController; + RemoteInspectorPipe m_remoteInspectorPipe; + }; + + static NeverDestroyed pipe(std::move(client)); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.h b/Source/WebKit/UIProcess/BrowserInspectorPipe.h new file mode 100644 index 00000000000..ac0caaabaed --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.h @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +namespace WebKit { + +class InspectorBrowserAgentClient; + +void initializeBrowserInspectorPipe(std::unique_ptr client); + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorTargetAgent.cpp b/Source/WebKit/UIProcess/BrowserInspectorTargetAgent.cpp new file mode 100644 index 00000000000..a2873d5e0f7 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorTargetAgent.cpp @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "BrowserInspectorTargetAgent.h" + +#include "WebPageInspectorController.h" +#include "WebPageProxy.h" +#include "WebProcessPool.h" +#include "WebProcessProxy.h" +#include +#include + +using namespace Inspector; + +namespace WebKit { + +namespace { + +InspectorTarget* targetForId(const String& targetId) +{ + ASSERT(isMainThread()); + for (auto* pool : WebProcessPool::allProcessPools()) { + for (auto& process : pool->processes()) { + for (auto* page : process->pages()) { + auto* result = page->inspectorController().findTarget(targetId); + if (result != nullptr) + return result; + } + } + } + return nullptr; +} + +} // namespace + +BrowserInspectorTargetAgent::BrowserInspectorTargetAgent(BackendDispatcher& backendDispatcher) + : InspectorAgentBase("Target"_s) + , m_backendDispatcher(TargetBackendDispatcher::create(backendDispatcher, this)) +{ +} + +BrowserInspectorTargetAgent::~BrowserInspectorTargetAgent() = default; + +void BrowserInspectorTargetAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ +} + +void BrowserInspectorTargetAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ +} + +void BrowserInspectorTargetAgent::sendMessageToTarget(ErrorString& error, const String& in_targetId, const String& in_message) +{ + auto* target = targetForId(in_targetId); + if (target == nullptr) { + error = "Cannot find target with provided id."; + return; + } + target->sendMessageToTargetBackend(in_message); +} + +void BrowserInspectorTargetAgent::activate(ErrorString& error, const String& targetId) +{ + auto* target = targetForId(targetId); + if (target == nullptr) { + error = "Cannot find target with provided id."; + return; + } + target->activate(error); +} + +void BrowserInspectorTargetAgent::close(ErrorString& error, const String& targetId) +{ + auto* target = targetForId(targetId); + if (target == nullptr) { + error = "Cannot find target with provided id."; + return; + } + target->close(error); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/BrowserInspectorTargetAgent.h b/Source/WebKit/UIProcess/BrowserInspectorTargetAgent.h new file mode 100644 index 00000000000..5c274280846 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorTargetAgent.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "config.h" + +#include +#include +#include +#include + +namespace WebKit { + +class BrowserInspectorTargetAgent final : public Inspector::InspectorAgentBase, public Inspector::TargetBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(BrowserInspectorTargetAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + explicit BrowserInspectorTargetAgent(Inspector::BackendDispatcher&); + ~BrowserInspectorTargetAgent() override; + + // InspectorAgentBase + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + // TargetBackendDispatcherHandler + void sendMessageToTarget(Inspector::ErrorString&, const String& targetId, const String& message) final; + void activate(Inspector::ErrorString&, const String& targetId) override; + void close(Inspector::ErrorString&, const String& targetId) override; + +private: + Ref m_backendDispatcher; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h index 454c61ffdef..6de7509037b 100644 --- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h +++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h @@ -27,6 +27,8 @@ #if HAVE(APP_SSO) +#include +#include #include "SOAuthorizationSession.h" #include @@ -39,6 +41,8 @@ class NavigationAction; namespace WebKit { +class WebPageProxy; + // FSM: Idle => Active => Completed class PopUpSOAuthorizationSession final : public SOAuthorizationSession { public: diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm index 0f18038de98..82a96677940 100644 --- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm +++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm @@ -29,6 +29,7 @@ #if HAVE(APP_SSO) #import "APINavigationAction.h" +#import "WebPageProxy.h" #import "WKNavigationDelegatePrivate.h" #import "WKUIDelegate.h" #import "WKWebViewConfigurationPrivate.h" diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h index c9498f99107..d9ab65cc0d3 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h @@ -91,6 +91,7 @@ private: void runJavaScriptAlert(WebPageProxy&, const WTF::String&, WebFrameProxy*, WebCore::SecurityOriginData&&, Function&& completionHandler) final; void runJavaScriptConfirm(WebPageProxy&, const WTF::String&, WebFrameProxy*, WebCore::SecurityOriginData&&, Function&& completionHandler) final; void runJavaScriptPrompt(WebPageProxy&, const WTF::String&, const WTF::String&, WebFrameProxy*, WebCore::SecurityOriginData&&, Function&&) final; + void handleJavaScriptDialog(WebKit::WebPageProxy&, bool accept, const WTF::String&) final; void presentStorageAccessConfirmDialog(const WTF::String& requestingDomain, const WTF::String& currentDomain, CompletionHandler&&); void requestStorageAccessConfirm(WebPageProxy&, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, CompletionHandler&&) final; void decidePolicyForGeolocationPermissionRequest(WebPageProxy&, WebFrameProxy&, API::SecurityOrigin&, Function&) final; @@ -171,6 +172,7 @@ private: bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1; + bool webViewHandleJavaScriptDialogValue : 1; bool webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler : 1; bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRequestGeolocationPermissionForFrameDecisionHandler : 1; diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm index 83990d9e81e..732566829b3 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm @@ -104,6 +104,7 @@ void UIDelegate::setDelegate(id delegate) m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)]; + m_delegateMethods.webViewHandleJavaScriptDialogValue = [delegate respondsToSelector:@selector(webView:handleJavaScriptDialog:value:)]; m_delegateMethods.webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:)]; m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRequestGeolocationPermissionForFrameDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestGeolocationPermissionForFrame:decisionHandler:)]; @@ -341,6 +342,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy&, const WTF::String& }).get()]; } +void UIDelegate::UIClient::handleJavaScriptDialog(WebKit::WebPageProxy&, bool accept, const WTF::String& value) { + if (!m_uiDelegate.m_delegateMethods.webViewHandleJavaScriptDialogValue) + return; + auto delegate = m_uiDelegate.m_delegate.get(); + if (!delegate) + return; + [delegate webView:m_uiDelegate.m_webView handleJavaScriptDialog:accept value:value]; +} + void UIDelegate::UIClient::requestStorageAccessConfirm(WebPageProxy&, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, CompletionHandler&& completionHandler) { auto delegate = m_uiDelegate.m_delegate.get(); diff --git a/Source/WebKit/UIProcess/InspectorBrowserAgent.cpp b/Source/WebKit/UIProcess/InspectorBrowserAgent.cpp new file mode 100644 index 00000000000..556be919504 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorBrowserAgent.cpp @@ -0,0 +1,255 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "InspectorBrowserAgent.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorBrowserAgentClient.h" +#include "NetworkProcessMessages.h" +#include "NetworkProcessProxy.h" +#include "WebPageInspectorTarget.h" +#include "WebPageProxy.h" +#include "WebProcessPool.h" +#include +#include +#include +#include + + +using namespace Inspector; + +namespace WebKit { + +namespace { + +Inspector::Protocol::Browser::CookieSameSitePolicy cookieSameSitePolicy(WebCore::Cookie::SameSitePolicy policy) +{ + switch (policy) { + case WebCore::Cookie::SameSitePolicy::None: + return Inspector::Protocol::Browser::CookieSameSitePolicy::None; + case WebCore::Cookie::SameSitePolicy::Lax: + return Inspector::Protocol::Browser::CookieSameSitePolicy::Lax; + case WebCore::Cookie::SameSitePolicy::Strict: + return Inspector::Protocol::Browser::CookieSameSitePolicy::Strict; + } + ASSERT_NOT_REACHED(); + return Inspector::Protocol::Browser::CookieSameSitePolicy::None; +} + +Ref buildObjectForCookie(const WebCore::Cookie& cookie) +{ + return Inspector::Protocol::Browser::Cookie::create() + .setName(cookie.name) + .setValue(cookie.value) + .setDomain(cookie.domain) + .setPath(cookie.path) + .setExpires(cookie.expires) + .setHttpOnly(cookie.httpOnly) + .setSecure(cookie.secure) + .setSession(cookie.session) + .setSameSite(cookieSameSitePolicy(cookie.sameSite)) + .release(); +} + +} // namespace + +InspectorBrowserAgent::InspectorBrowserAgent(Inspector::BackendDispatcher& backendDispatcher, InspectorBrowserAgentClient* client) + : InspectorAgentBase("Browser"_s) + , m_backendDispatcher(BrowserBackendDispatcher::create(backendDispatcher, this)) + , m_client(client) +{ +} + +InspectorBrowserAgent::~InspectorBrowserAgent() = default; + +void InspectorBrowserAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ +} + +void InspectorBrowserAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ +} + +void InspectorBrowserAgent::close(ErrorString& errorString) +{ + if (m_client == nullptr) { + errorString = "no platform delegate to close browser"; + } else { + m_client->closeAllWindows(); + } +} + +void InspectorBrowserAgent::createContext(ErrorString& errorString, String* browserContextID) +{ + BrowserContext browserContext = m_client->createBrowserContext(errorString); + if (!errorString.isEmpty()) + return; + browserContext.processPool->setPrimaryDataStore(*browserContext.dataStore); + browserContext.processPool->ensureNetworkProcess(browserContext.dataStore.get()); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + *browserContextID = toBrowserContextIDProtocolString(sessionID); + m_browserContexts.set(*browserContextID, browserContext); +} + +void InspectorBrowserAgent::deleteContext(ErrorString& errorString, const String& browserContextID) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, &browserContextID); + if (!errorString.isEmpty()) + return; + + Vector pages; + for (auto& process : browserContext.processPool->processes()) { + for (auto* page : process->pages()) + pages.append(page); + } + + for (auto* page : pages) + page->closePage(false); + + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + m_client->deleteBrowserContext(errorString, sessionID); + m_browserContexts.remove(browserContextID); +} + +void InspectorBrowserAgent::createPage(ErrorString& errorString, const String* browserContextID, String* targetID) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + RefPtr page = m_client->createPage(errorString, sessionID); + if (page == nullptr) + return; + *targetID = WebPageInspectorTarget::toTargetID(page->webPageID()); +} + +void InspectorBrowserAgent::getAllCookies(const String* browserContextID, Ref&& callback) { + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + NetworkProcessProxy* networkProcess = browserContext.processPool->networkProcess(); + networkProcess->sendWithAsyncReply(Messages::NetworkProcess::GetAllCookies(sessionID), + [callback = WTFMove(callback)](Vector allCookies) { + if (!callback->isActive()) + return; + auto cookies = JSON::ArrayOf::create(); + for (const auto& cookie : allCookies) + cookies->addItem(buildObjectForCookie(cookie)); + callback->sendSuccess(WTFMove(cookies)); + }, 0); +} + +void InspectorBrowserAgent::setCookies(const String* browserContextID, const JSON::Array& in_cookies, Ref&& callback) { + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + NetworkProcessProxy* networkProcess = browserContext.processPool->networkProcess(); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + + Vector cookies; + for (unsigned i = 0; i < in_cookies.length(); ++i) { + RefPtr item = in_cookies.get(i); + RefPtr obj; + if (!item->asObject(obj)) { + errorString = "Invalid cookie payload format"_s; + return; + } + + WebCore::Cookie cookie; + if (!obj->getString("name", cookie.name) || + !obj->getString("value", cookie.value) || + !obj->getString("domain", cookie.domain) || + !obj->getString("path", cookie.path)) { + errorString = "Invalid file payload format"_s; + return; + } + + obj->getDouble("expires", cookie.expires); + obj->getBoolean("httpOnly", cookie.httpOnly); + obj->getBoolean("secure", cookie.secure); + obj->getBoolean("session", cookie.session); + String sameSite; + if (obj->getString("sameSite", sameSite)) { + if (sameSite == "None") + cookie.sameSite = WebCore::Cookie::SameSitePolicy::None; + if (sameSite == "Lax") + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Lax; + if (sameSite == "Strict") + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Strict; + } + cookies.append(WTFMove(cookie)); + } + + networkProcess->sendWithAsyncReply(Messages::NetworkProcess::SetCookies(sessionID, WTFMove(cookies)), + [callback = WTFMove(callback)](bool success) { + if (!callback->isActive()) + return; + + if (success) + callback->sendSuccess(); + else + callback->sendFailure("Internal error: no network storage"_s); + callback->sendSuccess(); + }, 0); +} + +void InspectorBrowserAgent::deleteAllCookies(const String* browserContextID, Ref&& callback) { + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + NetworkProcessProxy* networkProcess = browserContext.processPool->networkProcess(); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + networkProcess->sendWithAsyncReply(Messages::NetworkProcess::DeleteAllCookies(sessionID), + [callback = WTFMove(callback)](bool success) { + if (!callback->isActive()) + return; + if (success) + callback->sendSuccess(); + else + callback->sendFailure("Internal error: no network storage"_s); + }, 0); +} + +String InspectorBrowserAgent::toBrowserContextIDProtocolString(const PAL::SessionID& sessionID) +{ + StringBuilder builder; + appendUnsignedAsHexFixedSize(sessionID.toUInt64(), builder, 16); + return builder.toString(); +} + +BrowserContext InspectorBrowserAgent::lookupBrowserContext(ErrorString& errorString, const String* browserContextID) { + if (!browserContextID) { + for (auto& pool : WebProcessPool::allProcessPools()) { + BrowserContext context; + context.processPool = pool; + context.dataStore = pool->websiteDataStore(); + return context; + } + errorString = "No default context"_s; + return BrowserContext(); + } + + BrowserContext browserContext = m_browserContexts.get(*browserContextID); + if (!browserContext.processPool) + errorString = "Could not find browser context for given id"_s; + return browserContext; +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorBrowserAgent.h b/Source/WebKit/UIProcess/InspectorBrowserAgent.h new file mode 100644 index 00000000000..a0d439f661f --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorBrowserAgent.h @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorBrowserAgentClient.h" +#include +#include +#include +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace PAL { +class SessionID; +} + +namespace WebKit { + +class NetworkProcess; +class WebProcessPool; + +class InspectorBrowserAgent final : public Inspector::InspectorAgentBase, public Inspector::BrowserBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(InspectorBrowserAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorBrowserAgent(Inspector::BackendDispatcher&, InspectorBrowserAgentClient*); + ~InspectorBrowserAgent() override; + + // InspectorAgentBase + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + // BrowserBackendDispatcherHandler + void close(Inspector::ErrorString&) override; + void createContext(Inspector::ErrorString&, String* browserContextID) override; + void deleteContext(Inspector::ErrorString&, const String& browserContextID) override; + void createPage(Inspector::ErrorString&, const String* browserContextID, String* targetId) override; + + void getAllCookies(const String* browserContextID, Ref&&) override; + void setCookies(const String* browserContextID, const JSON::Array& in_cookies, Ref&&) override; + void deleteAllCookies(const String* browserContextID, Ref&&) override; + + static String toBrowserContextIDProtocolString(const PAL::SessionID&); + +private: + BrowserContext lookupBrowserContext(Inspector::ErrorString&, const String* browserContextID); + Ref m_backendDispatcher; + InspectorBrowserAgentClient* m_client; + HashMap m_browserContexts; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorBrowserAgentClient.h b/Source/WebKit/UIProcess/InspectorBrowserAgentClient.h new file mode 100644 index 00000000000..866db590d59 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorBrowserAgentClient.h @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include + +namespace WebKit { + +class WebsiteDataStore; +class WebPageProxy; +class WebProcessPool; + +struct BrowserContext { + RefPtr dataStore; + RefPtr processPool; +}; + +class InspectorBrowserAgentClient { +public: + virtual ~InspectorBrowserAgentClient() = default; + virtual RefPtr createPage(WTF::String& error, PAL::SessionID) = 0; + virtual void closeAllWindows() = 0; + virtual BrowserContext createBrowserContext(WTF::String& error) = 0; + virtual void deleteBrowserContext(WTF::String& error, PAL::SessionID) = 0; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp new file mode 100644 index 00000000000..121b5969d4a --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "InspectorDialogAgent.h" + +#include "APINavigation.h" +#include "APIUIClient.h" +#include "WebPageProxy.h" +#include + + +namespace WebKit { + +using namespace Inspector; + +InspectorDialogAgent::InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page) + : InspectorAgentBase("Dialog"_s) + , m_frontendDispatcher(makeUnique(frontendRouter)) + , m_backendDispatcher(DialogBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +InspectorDialogAgent::~InspectorDialogAgent() +{ + Inspector::ErrorString err; + disable(err); +} + +void InspectorDialogAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ +} + +void InspectorDialogAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ +} + +void InspectorDialogAgent::enable(Inspector::ErrorString& errorString) +{ + if (m_page.inspectorDialogAgent()) { + errorString = "Dialog domain is already enabled."_s; + return; + } + m_page.setInspectorDialogAgent(this); +} + +void InspectorDialogAgent::disable(Inspector::ErrorString&) +{ + if (m_page.inspectorDialogAgent() != this) + return; + m_page.setInspectorDialogAgent(nullptr); +} + +void InspectorDialogAgent::handleJavaScriptDialog(Inspector::ErrorString& errorString, bool accept, const String* value) +{ + m_page.uiClient().handleJavaScriptDialog(m_page, accept, value ? *value : String()); +} + +void InspectorDialogAgent::javascriptDialogOpening(const String& type, const String& message, const String* defaultValue) { + m_frontendDispatcher->javascriptDialogOpening(type, message, defaultValue); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.h b/Source/WebKit/UIProcess/InspectorDialogAgent.h new file mode 100644 index 00000000000..203c203a0e2 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.h @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "WebEvent.h" + +#include +#include +#include + +#include +#include + +namespace Inspector { +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class NativeWebKeyboardEvent; +class WebPageProxy; + +class InspectorDialogAgent : public Inspector::InspectorAgentBase, public Inspector::DialogBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(InspectorDialogAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorDialogAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + void enable(Inspector::ErrorString&) override; + void disable(Inspector::ErrorString&) override; + void handleJavaScriptDialog(Inspector::ErrorString& errorString, bool accept, const String* promptText) override; + + void javascriptDialogOpening(const String& type, const String& message, const String* defaultValue = nullptr); + +private: + void platformHandleJavaScriptDialog(bool accept, const String* promptText); + std::unique_ptr m_frontendDispatcher; + Ref m_backendDispatcher; + WebPageProxy& m_page; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorTargetProxy.cpp b/Source/WebKit/UIProcess/InspectorTargetProxy.cpp index 1b37c1ed439..c45d45de342 100644 --- a/Source/WebKit/UIProcess/InspectorTargetProxy.cpp +++ b/Source/WebKit/UIProcess/InspectorTargetProxy.cpp @@ -32,6 +32,8 @@ #include "WebPageMessages.h" #include "WebPageProxy.h" #include "WebProcessProxy.h" +#include "ProvisionalPageProxy.h" + namespace WebKit { @@ -39,23 +41,29 @@ using namespace Inspector; std::unique_ptr InspectorTargetProxy::create(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) { - return makeUnique(page, targetId, type); + return makeUnique(page, nullptr, targetId, type); } std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId, Inspector::InspectorTargetType type) { - auto target = InspectorTargetProxy::create(provisionalPage.page(), targetId, type); - target->m_provisionalPage = makeWeakPtr(provisionalPage); - return target; + return makeUnique(provisionalPage.page(), &provisionalPage, targetId, type); } -InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) +InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, ProvisionalPageProxy* provisionalPage, const String& targetId, Inspector::InspectorTargetType type) : m_page(page) + , m_provisionalPage(makeWeakPtr(provisionalPage)) , m_identifier(targetId) , m_type(type) { } +String InspectorTargetProxy::url() const +{ + if (m_page.provisionalPageProxy()) + return m_page.provisionalPageProxy()->provisionalURL().string(); + return m_page.pageLoadState().activeURL(); +} + void InspectorTargetProxy::connect(Inspector::FrontendChannel::ConnectionType connectionType) { if (m_provisionalPage) { diff --git a/Source/WebKit/UIProcess/InspectorTargetProxy.h b/Source/WebKit/UIProcess/InspectorTargetProxy.h index a2239cec8e1..43415afbc77 100644 --- a/Source/WebKit/UIProcess/InspectorTargetProxy.h +++ b/Source/WebKit/UIProcess/InspectorTargetProxy.h @@ -37,17 +37,18 @@ class WebPageProxy; // NOTE: This UIProcess side InspectorTarget doesn't care about the frontend channel, since // any target -> frontend messages will be routed to the WebPageProxy with a targetId. -class InspectorTargetProxy final : public Inspector::InspectorTarget { +class InspectorTargetProxy : public Inspector::InspectorTarget { WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(InspectorTargetProxy); public: static std::unique_ptr create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); - InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); + InspectorTargetProxy(WebPageProxy&, ProvisionalPageProxy*, const String& targetId, Inspector::InspectorTargetType); ~InspectorTargetProxy() = default; Inspector::InspectorTargetType type() const final { return m_type; } String identifier() const final { return m_identifier; } + String url() const final; void didCommitProvisionalTarget(); bool isProvisional() const override; @@ -56,11 +57,13 @@ public: void disconnect() override; void sendMessageToTargetBackend(const String&) override; -private: +protected: WebPageProxy& m_page; + +private: + WeakPtr m_provisionalPage; String m_identifier; Inspector::InspectorTargetType m_type; - WeakPtr m_provisionalPage; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp new file mode 100644 index 00000000000..a3a3bb02dcd --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "RemoteInspectorPipe.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "BrowserInspectorController.h" +#include +#include +#include +#include +#include +#include + +#if OS(UNIX) +#include +#include +#endif + +namespace WebKit { + +static const int readFD = 3; +static const int writeFD = 4; + +class RemoteInspectorPipe::RemoteFrontendChannel : public Inspector::FrontendChannel { + WTF_MAKE_FAST_ALLOCATED; +public: + RemoteFrontendChannel() + : m_senderQueue(WorkQueue::create("Inspector pipe writer")) + { + } + + ~RemoteFrontendChannel() override = default; + + ConnectionType connectionType() const override + { + return ConnectionType::Remote; + } + + void sendMessageToFrontend(const String& message) override + { + m_senderQueue->dispatch([message = message.isolatedCopy()]() { + dprintf(writeFD, "%s%c", message.ascii().data(), '\0'); + }); + } + +private: + Ref m_senderQueue; +}; + +RemoteInspectorPipe::RemoteInspectorPipe(BrowserInspectorController& browserInspectorController) + : m_remoteFrontendChannel(makeUnique()) + , m_browserInspectorController(browserInspectorController) +{ + start(); +} + +RemoteInspectorPipe::~RemoteInspectorPipe() +{ + stop(); +} + +bool RemoteInspectorPipe::start() +{ + if (m_receiverThread) + return true; + + m_browserInspectorController.connectFrontend(*m_remoteFrontendChannel); + m_terminated = false; + m_receiverThread = Thread::create("Inspector pipe reader", [this] { + workerRun(); + }); + return true; +} + +void RemoteInspectorPipe::stop() +{ + if (!m_receiverThread) + return; + + m_browserInspectorController.disconnectFrontend(); + + m_terminated = true; + m_receiverThread->waitForCompletion(); + m_receiverThread = nullptr; +} + +void RemoteInspectorPipe::workerRun() +{ + const size_t bufSize = 256 * 1024; + auto buffer = makeUniqueArray(bufSize); + Vector line; + while (!m_terminated) { + ssize_t size = read(readFD, buffer.get(), bufSize); + if (size == 0) { + break; + } + if (size < 0) { + break; + } + size_t start = 0; + size_t end = line.size(); + line.append(buffer.get(), size); + while (true) { + for (; end < line.size(); ++end) { + if (line[end] == '\0') + break; + } + if (end == line.size()) + break; + + if (end > start) { + String message = String::fromUTF8(line.data() + start, end - start); + RunLoop::main().dispatch([this, message] { + if (!m_terminated) + m_browserInspectorController.dispatchMessageFromFrontend(message); + }); + } + ++end; + start = end; + } + if (start != 0 && start < line.size()) + memmove(line.data(), line.data() + start, line.size() - start); + line.shrink(line.size() - start); + } +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.h b/Source/WebKit/UIProcess/RemoteInspectorPipe.h new file mode 100644 index 00000000000..426eb17d012 --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.h @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include +#include + +namespace Inspector { +class FrontendChannel; +} + +namespace WebKit { + +class BrowserInspectorController; + +class RemoteInspectorPipe { + WTF_MAKE_NONCOPYABLE(RemoteInspectorPipe); + WTF_MAKE_FAST_ALLOCATED; +public: + explicit RemoteInspectorPipe(BrowserInspectorController&); + ~RemoteInspectorPipe(); + +private: + class RemoteFrontendChannel; + + bool start(); + void stop(); + + void workerRun(); + + RefPtr m_receiverThread; + std::atomic m_terminated { false }; + std::unique_ptr m_remoteFrontendChannel; + BrowserInspectorController& m_browserInspectorController; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp index baabe8def1d..83d089d87d0 100644 --- a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp +++ b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp @@ -35,6 +35,7 @@ #include "NfcService.h" #include "WebPageProxy.h" #include "WebPreferencesKeys.h" +#include "WebProcessProxy.h" #include #include #include diff --git a/Source/WebKit/UIProcess/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/WebPageInspectorController.cpp index b9a9469ab59..81129896554 100644 --- a/Source/WebKit/UIProcess/WebPageInspectorController.cpp +++ b/Source/WebKit/UIProcess/WebPageInspectorController.cpp @@ -26,9 +26,11 @@ #include "config.h" #include "WebPageInspectorController.h" +#include "InspectorBrowserAgent.h" #include "ProvisionalPageProxy.h" #include "WebFrameProxy.h" #include "WebPageInspectorTarget.h" +#include "WebPageInspectorTargetProxy.h" #include "WebPageProxy.h" #include #include @@ -46,26 +48,59 @@ static String getTargetID(const ProvisionalPageProxy& provisionalPage) return WebPageInspectorTarget::toTargetID(provisionalPage.webPageID()); } +static WebPageInspectorController::CreationListener& creationListener() { + static NeverDestroyed listener; + return listener; +} + +void WebPageInspectorController::setCreationListener(CreationListener listener) +{ + creationListener() = listener; +} + WebPageInspectorController::WebPageInspectorController(WebPageProxy& page) : m_page(page) , m_frontendRouter(FrontendRouter::create()) , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) { - auto targetAgent = makeUnique(m_frontendRouter.get(), m_backendDispatcher.get()); + String browserContextID; +#if ENABLE(REMOTE_INSPECTOR) + browserContextID = InspectorBrowserAgent::toBrowserContextIDProtocolString(page.sessionID()); +#endif + auto targetAgent = makeUnique(m_frontendRouter.get(), m_backendDispatcher.get(), browserContextID); m_targetAgent = targetAgent.get(); m_agents.append(WTFMove(targetAgent)); + + if (creationListener()) + creationListener()(*this); } void WebPageInspectorController::init() { + // window.open will create page with already running process. + if (!m_page.hasRunningProcess()) + return; String pageTargetId = WebPageInspectorTarget::toTargetID(m_page.webPageID()); createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page); } +void WebPageInspectorController::didFinishAttachingToWebProcess() +{ + String pageTargetID = WebPageInspectorTarget::toTargetID(m_page.webPageID()); + // Create target only after attaching to a Web Process first time. Before that + // we cannot event establish frontend connection. + if (m_targets.contains(pageTargetID)) + return; + createInspectorTarget(pageTargetID, Inspector::InspectorTargetType::Page); +} + void WebPageInspectorController::pageClosed() { + String pageTargetId = WebPageInspectorTarget::toTargetID(m_page.webPageID()); + destroyInspectorTarget(pageTargetId); + disconnectAllFrontends(); m_agents.discardValues(); @@ -134,6 +169,16 @@ void WebPageInspectorController::dispatchMessageFromFrontend(const String& messa m_backendDispatcher->dispatch(message); } +bool WebPageInspectorController::dispatchMessageToTargetBackend(const String& message) +{ + return m_backendDispatcher->dispatch(message, BackendDispatcher::Mode::ContinueIfDomainIsMissing) == BackendDispatcher::DispatchResult::Finished; +} + +Inspector::InspectorTarget* WebPageInspectorController::findTarget(const String& targetId) +{ + return m_targets.get(targetId); +} + #if ENABLE(REMOTE_INSPECTOR) void WebPageInspectorController::setIndicating(bool indicating) { @@ -150,7 +195,12 @@ void WebPageInspectorController::setIndicating(bool indicating) void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { - addTarget(InspectorTargetProxy::create(m_page, targetId, type)); + std::unique_ptr target; + if (type == Inspector::InspectorTargetType::Page) + target = WebPageInspectorTargetProxy::create(m_page, *m_targetAgent, targetId); + else + target = InspectorTargetProxy::create(m_page, targetId, type); + addTarget(WTFMove(target)); } void WebPageInspectorController::destroyInspectorTarget(const String& targetId) @@ -169,7 +219,7 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage) { - addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page)); + addTarget(WebPageInspectorTargetProxy::create(provisionalPage, *m_targetAgent, getTargetID(provisionalPage))); } void WebPageInspectorController::willDestroyProvisionalPage(const ProvisionalPageProxy& provisionalPage) diff --git a/Source/WebKit/UIProcess/WebPageInspectorController.h b/Source/WebKit/UIProcess/WebPageInspectorController.h index 828bc3ccc7e..40a333b7004 100644 --- a/Source/WebKit/UIProcess/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/WebPageInspectorController.h @@ -48,7 +48,13 @@ public: WebPageInspectorController(WebPageProxy&); void init(); + void didFinishAttachingToWebProcess(); + + using CreationListener = std::function; + static void setCreationListener(CreationListener); + void pageClosed(); + void didProcessAllPendingKeyboardEvents(); bool hasLocalFrontend() const; @@ -57,6 +63,8 @@ public: void disconnectAllFrontends(); void dispatchMessageFromFrontend(const String& message); + Inspector::InspectorTarget* findTarget(const String& targetId); + bool dispatchMessageToTargetBackend(const String&); #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp new file mode 100644 index 00000000000..e903413c95d --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" + +#include "WebPageProxy.h" +#include "WebPreferences.h" +#include + + +namespace WebKit { + +using namespace Inspector; + +WebPageInspectorEmulationAgent::WebPageInspectorEmulationAgent(BackendDispatcher& backendDispatcher, WebPageProxy& page) + : InspectorAgentBase("Emulation"_s) + , m_backendDispatcher(EmulationBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +WebPageInspectorEmulationAgent::~WebPageInspectorEmulationAgent() +{ +} + +void WebPageInspectorEmulationAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ +} + +void WebPageInspectorEmulationAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ +} + +void WebPageInspectorEmulationAgent::setDeviceMetricsOverride(ErrorString& error, int in_width, int in_height) +{ + platformSetSize(error, in_width, in_height); +} + +void WebPageInspectorEmulationAgent::setJavaScriptEnabled(ErrorString&, bool enabled) +{ + auto copy = m_page.preferences().copy(); + copy->setJavaScriptEnabled(enabled); + m_page.setPreferences(copy); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h new file mode 100644 index 00000000000..b02753590b3 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include +#include + +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class WebPageProxy; + +class WebPageInspectorEmulationAgent : public Inspector::InspectorAgentBase, public Inspector::EmulationBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(WebPageInspectorEmulationAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + WebPageInspectorEmulationAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorEmulationAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + void setDeviceMetricsOverride(Inspector::ErrorString&, int in_width, int in_height) override; + void setJavaScriptEnabled(Inspector::ErrorString&, bool enabled) override; + +private: + void platformSetSize(String& error, int width, int height); + + Ref m_backendDispatcher; + WebPageProxy& m_page; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp new file mode 100644 index 00000000000..6bd5242c9c2 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "APINavigation.h" +#include "NativeWebKeyboardEvent.h" +#include "NativeWebMouseEvent.h" +#include "WebPageProxy.h" +#include + + +namespace WebKit { + +using namespace Inspector; + +namespace { + +template +class CallbackList { + WTF_MAKE_FAST_ALLOCATED; +public: + ~CallbackList() + { + for (const auto& callback : m_callbacks) + callback->sendFailure("Page closed"); + } + + void append(Ref&& callback) + { + m_callbacks.append(WTFMove(callback)); + } + + void sendSuccess() + { + for (const auto& callback : m_callbacks) + callback->sendSuccess(); + m_callbacks.clear(); + } + +private: + Vector> m_callbacks; +}; + +} // namespace + +class WebPageInspectorInputAgent::InspectorInputObserver : public WebPageProxy::InputProcessingObserver { + WTF_MAKE_FAST_ALLOCATED; +public: + using KeyboardCallback = Inspector::InputBackendDispatcherHandler::DispatchKeyEventCallback; + using MouseCallback = Inspector::InputBackendDispatcherHandler::DispatchMouseEventCallback; + + ~InspectorInputObserver() override = default; + + void didProcessAllPendingKeyboardEvents() override + { + m_keyboardCallbacks.sendSuccess(); + } + + void didProcessAllPendingMouseEvents() override + { + m_mouseCallbacks.sendSuccess(); + } + + void addMouseCallback(Ref&& callback) + { + m_mouseCallbacks.append(WTFMove(callback)); + } + + void addKeyboardCallback(Ref&& callback) + { + m_keyboardCallbacks.append(WTFMove(callback)); + } + +private: + CallbackList m_keyboardCallbacks; + CallbackList m_mouseCallbacks; +}; + +WebPageInspectorInputAgent::WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page) + : InspectorAgentBase("Input"_s) + , m_backendDispatcher(InputBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) + , m_inputObserver(makeUnique()) +{ + m_page.setObserber(m_inputObserver.get()); +} + +WebPageInspectorInputAgent::~WebPageInspectorInputAgent() +{ + m_page.setObserber(nullptr); +} + +void WebPageInspectorInputAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ +} + +void WebPageInspectorInputAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ +} + +void WebPageInspectorInputAgent::dispatchKeyEvent(const String& in_type, const int* opt_in_modifiers, const String* opt_in_text, const String* opt_in_unmodifiedText, const String* opt_in_code, const String* opt_in_key, const int* opt_in_windowsVirtualKeyCode, const int* opt_in_nativeVirtualKeyCode, const bool* opt_in_autoRepeat, const bool* opt_in_isKeypad, const bool* opt_in_isSystemKey, Ref&& callback) +{ + WebKit::WebEvent::Type type; + if (in_type == "keyDown") { + type = WebKit::WebEvent::KeyDown; + } else if (in_type == "keyUp") { + type = WebKit::WebEvent::KeyUp; + } else { + callback->sendFailure("Unsupported event type."); + return; + } + OptionSet modifiers; + if (opt_in_modifiers) + modifiers = modifiers.fromRaw(*opt_in_modifiers); + String text; + if (opt_in_text) + text = *opt_in_text; + String unmodifiedText; + if (opt_in_unmodifiedText) + unmodifiedText = *opt_in_unmodifiedText; + String code; + if (opt_in_code) + code = *opt_in_code; + String key; + if (opt_in_key) + key = *opt_in_key; + int windowsVirtualKeyCode = 0; + if (opt_in_windowsVirtualKeyCode) + windowsVirtualKeyCode = *opt_in_windowsVirtualKeyCode; + int nativeVirtualKeyCode = 0; + if (opt_in_nativeVirtualKeyCode) + nativeVirtualKeyCode = *opt_in_nativeVirtualKeyCode; + bool isAutoRepeat = false; + if (opt_in_autoRepeat) + isAutoRepeat = *opt_in_autoRepeat; + bool isKeypad = false; + if (opt_in_isKeypad) + isKeypad = *opt_in_isKeypad; + bool isSystemKey = false; + if (opt_in_isSystemKey) + isSystemKey = *opt_in_isSystemKey; + WallTime timestamp = WallTime::now(); + + m_inputObserver->addKeyboardCallback(WTFMove(callback)); + platformDispatchKeyEvent( + type, + text, + unmodifiedText, + key, + code, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp); +} + +void WebPageInspectorInputAgent::dispatchMouseEvent(const String& in_type, int in_x, int in_y, const int* opt_in_modifiers, const String* opt_in_button, const int* opt_in_buttons, const int* opt_in_clickCount, const int* opt_in_deltaX, const int* opt_in_deltaY, Ref&& callback) +{ + WebEvent::Type type = WebEvent::NoType; + if (in_type == "down") + type = WebEvent::MouseDown; + else if (in_type == "up") + type = WebEvent::MouseUp; + else if (in_type == "move") + type = WebEvent::MouseMove; + else { + callback->sendFailure("Unsupported event type"); + return; + } + + OptionSet modifiers; + if (opt_in_modifiers) + modifiers = modifiers.fromRaw(*opt_in_modifiers); + + WebMouseEvent::Button button = WebMouseEvent::NoButton; + if (opt_in_button) { + if (*opt_in_button == "left") + button = WebMouseEvent::LeftButton; + else if (*opt_in_button == "middle") + button = WebMouseEvent::MiddleButton; + else if (*opt_in_button == "right") + button = WebMouseEvent::RightButton; + else if (*opt_in_button == "none") + button = WebMouseEvent::NoButton; + else { + callback->sendFailure("Unsupported button"); + return; + } + } + + unsigned short buttons = 0; + if (opt_in_buttons) + buttons = *opt_in_buttons; + + int clickCount = 0; + if (opt_in_clickCount) + clickCount = *opt_in_clickCount; + int deltaX = 0; + if (opt_in_deltaX) + deltaX = *opt_in_deltaX; + int deltaY = 0; + if (opt_in_deltaY) + deltaY = *opt_in_deltaY; + m_inputObserver->addMouseCallback(WTFMove(callback)); +#if PLATFORM(WPE) + platformDispatchMouseEvent(type, in_x, in_y, button, modifiers); +#elif PLATFORM(GTK) || PLATFORM(MAC) + WallTime timestamp = WallTime::now(); + NativeWebMouseEvent event( + type, + button, + buttons, + {in_x, in_y}, + WebCore::IntPoint(), + deltaX, + deltaY, + 0, + clickCount, + modifiers, + timestamp); + m_page.handleMouseEvent(event); +#endif +} + +void WebPageInspectorInputAgent::goBack(Inspector::ErrorString&) +{ + auto navigation = m_page.goBack(); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h new file mode 100644 index 00000000000..36531345add --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "WebEvent.h" + +#include +#include + +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class NativeWebKeyboardEvent; +class WebPageProxy; + +class WebPageInspectorInputAgent : public Inspector::InspectorAgentBase, public Inspector::InputBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(WebPageInspectorInputAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorInputAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + void dispatchKeyEvent(const String& in_type, const int* opt_in_modifiers, const String* opt_in_text, const String* opt_in_unmodifiedText, const String* opt_in_code, const String* opt_in_key, const int* opt_in_windowsVirtualKeyCode, const int* opt_in_nativeVirtualKeyCode, const bool* opt_in_autoRepeat, const bool* opt_in_isKeypad, const bool* opt_in_isSystemKey, Ref&& callback) override; + void dispatchMouseEvent(const String& in_type, int in_x, int in_y, const int* opt_in_modifiers, const String* opt_in_button, const int* opt_in_buttons, const int* opt_in_clickCount, const int* opt_in_deltaX, const int* opt_in_deltaY, Ref&& callback) override; + void goBack(Inspector::ErrorString&) override; + +private: + void platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp); +#if PLATFORM(WPE) + void platformDispatchMouseEvent(WebMouseEvent::Type type, int x, int y, WebMouseEvent::Button button, OptionSet modifiers); +#endif + + Ref m_backendDispatcher; + WebPageProxy& m_page; + // Keep track of currently active modifiers across multiple keystrokes. + // Most platforms do not track current modifiers from synthesized events. + unsigned m_currentModifiers { 0 }; + class InspectorInputObserver; + std::unique_ptr m_inputObserver; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorTargetProxy.cpp b/Source/WebKit/UIProcess/WebPageInspectorTargetProxy.cpp new file mode 100644 index 00000000000..cf99a7c8ccc --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorTargetProxy.cpp @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorTargetProxy.h" + +#include "InspectorDialogAgent.h" +#include "ProvisionalPageProxy.h" +#include "WebPageInspectorController.h" +#include "WebPageInspectorEmulationAgent.h" +#include "WebPageInspectorInputAgent.h" +#include "WebPageMessages.h" +#include "WebPageProxy.h" +#include "WebProcessProxy.h" +#include +#include +#include +#include + +namespace WebKit { + +using namespace Inspector; + +namespace { + +class TargetFrontendChannel final : public FrontendChannel { + WTF_MAKE_NONCOPYABLE(TargetFrontendChannel); +public: + TargetFrontendChannel(InspectorTargetAgent& targetAgent, const String& targetId, FrontendChannel::ConnectionType type) + : m_targetAgent(targetAgent) + , m_targetId(targetId) + , m_connectionType(type) + { + } + ~TargetFrontendChannel() override = default; + + ConnectionType connectionType() const override { return m_connectionType; } + void sendMessageToFrontend(const String& message) override + { + m_targetAgent.sendMessageFromTargetToFrontend(m_targetId, message); + } + +private: + InspectorTargetAgent& m_targetAgent; + String m_targetId; + FrontendChannel::ConnectionType m_connectionType; +}; + +} // namespace + +std::unique_ptr WebPageInspectorTargetProxy::create(WebPageProxy& page, Inspector::InspectorTargetAgent& targetAgent, const String& targetId) +{ + return makeUnique(page, nullptr, targetAgent, targetId); +} + +std::unique_ptr WebPageInspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, Inspector::InspectorTargetAgent& targetAgent, const String& targetId) +{ + return makeUnique(provisionalPage.page(), &provisionalPage, targetAgent, targetId); +} + +WebPageInspectorTargetProxy::WebPageInspectorTargetProxy(WebPageProxy& page, ProvisionalPageProxy* provisionalPage, Inspector::InspectorTargetAgent& targetAgent, const String& targetId) + : InspectorTargetProxy(page, provisionalPage, targetId, Inspector::InspectorTargetType::Page) + , m_frontendRouter(FrontendRouter::create()) + , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) + , m_targetAgent(targetAgent) +{ + m_agents.append(std::make_unique(m_backendDispatcher.get(), page)); + m_agents.append(std::make_unique(m_backendDispatcher.get(), page)); + m_agents.append(std::make_unique(m_backendDispatcher.get(), m_frontendRouter.get(), page)); +} + +void WebPageInspectorTargetProxy::connect(Inspector::FrontendChannel::ConnectionType connectionType) +{ + InspectorTargetProxy::connect(connectionType); + ASSERT(!m_frontendChannel); + if (m_frontendChannel) + return; + m_frontendChannel = std::make_unique(m_targetAgent, identifier(), connectionType); + m_frontendRouter->connectFrontend(*m_frontendChannel); +} + +void WebPageInspectorTargetProxy::disconnect() +{ + ASSERT(m_frontendChannel); + m_frontendRouter->disconnectAllFrontends(); + m_frontendChannel.reset(); + InspectorTargetProxy::disconnect(); +} + +void WebPageInspectorTargetProxy::sendMessageToTargetBackend(const String& message) +{ + if (m_backendDispatcher->dispatch(message, BackendDispatcher::Mode::ContinueIfDomainIsMissing) == BackendDispatcher::DispatchResult::Finished) + return; + if (m_page.inspectorController().dispatchMessageToTargetBackend(message)) + return; + InspectorTargetProxy::sendMessageToTargetBackend(message); +} + +void WebPageInspectorTargetProxy::activate(String& error) +{ + platformActivate(error); +} + +void WebPageInspectorTargetProxy::close(String& error) +{ + m_page.closePage(false); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorTargetProxy.h b/Source/WebKit/UIProcess/WebPageInspectorTargetProxy.h new file mode 100644 index 00000000000..0655b5ea376 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorTargetProxy.h @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "InspectorTargetProxy.h" +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class InspectorTargetAgent; +} + +namespace WebKit { + +class WebPageProxy; + +class WebPageInspectorTargetProxy final : public InspectorTargetProxy { + WTF_MAKE_FAST_ALLOCATED; + WTF_MAKE_NONCOPYABLE(WebPageInspectorTargetProxy); +public: + static std::unique_ptr create(WebPageProxy&, Inspector::InspectorTargetAgent&, const String& targetId); + static std::unique_ptr create(ProvisionalPageProxy&, Inspector::InspectorTargetAgent&, const String& targetId); + WebPageInspectorTargetProxy(WebPageProxy&, ProvisionalPageProxy*, Inspector::InspectorTargetAgent&, const String& targetId); + ~WebPageInspectorTargetProxy() = default; + + void connect(Inspector::FrontendChannel::ConnectionType) override; + void disconnect() override; + void sendMessageToTargetBackend(const String&) override; + void activate(String& error) override; + void close(String& error) override; + +private: + void platformActivate(String& error) const; + + Ref m_frontendRouter; + Ref m_backendDispatcher; + Inspector::InspectorTargetAgent& m_targetAgent; + Inspector::AgentRegistry m_agents; + std::unique_ptr m_frontendChannel; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index 81b65c6e2db..2b7677a25a2 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -867,6 +867,7 @@ void WebPageProxy::finishAttachingToWebProcess(ProcessLaunchReason reason) m_pageLoadState.didSwapWebProcesses(); if (reason != ProcessLaunchReason::InitialProcess) m_drawingArea->waitForBackingStoreUpdateOnNextPaint(); + m_inspectorController->didFinishAttachingToWebProcess(); } void WebPageProxy::didAttachToRunningProcess() @@ -1620,6 +1621,11 @@ void WebPageProxy::setControlledByAutomation(bool controlled) m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation)); } +void WebPageProxy::setObserber(InputProcessingObserver* observer) +{ + m_inputProcessingObserver = observer; +} + void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { m_inspectorController->createInspectorTarget(targetId, type); @@ -5330,6 +5336,8 @@ void WebPageProxy::runJavaScriptAlert(FrameIdentifier frameID, SecurityOriginDat if (auto* automationSession = process().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("alert"_s, message); m_uiClient->runJavaScriptAlert(*this, message, frame, WTFMove(securityOrigin), WTFMove(reply)); } @@ -5349,6 +5357,8 @@ void WebPageProxy::runJavaScriptConfirm(FrameIdentifier frameID, SecurityOriginD if (auto* automationSession = process().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("confirm"_s, message); m_uiClient->runJavaScriptConfirm(*this, message, frame, WTFMove(securityOrigin), WTFMove(reply)); } @@ -5368,6 +5378,8 @@ void WebPageProxy::runJavaScriptPrompt(FrameIdentifier frameID, SecurityOriginDa if (auto* automationSession = process().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("prompt"_s, message, &defaultValue); m_uiClient->runJavaScriptPrompt(*this, message, defaultValue, frame, WTFMove(securityOrigin), WTFMove(reply)); } @@ -5526,6 +5538,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(FrameIdentifier frameID, Security return; } } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("beforeunload"_s, message); // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer. m_process->responsivenessTimer().stop(); @@ -6543,6 +6557,8 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) if (auto* automationSession = process().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); pageClient().didFinishProcessingAllPendingMouseEvents(); + if (m_inputProcessingObserver) + m_inputProcessingObserver->didProcessAllPendingMouseEvents(); } break; @@ -6569,7 +6585,6 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) case WebEvent::RawKeyDown: case WebEvent::Char: { LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s (queue empty %d)", webKeyboardEventTypeString(type), m_keyEventQueue.isEmpty()); - MESSAGE_CHECK(m_process, !m_keyEventQueue.isEmpty()); NativeWebKeyboardEvent event = m_keyEventQueue.takeFirst(); @@ -6584,7 +6599,6 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) // The call to doneWithKeyEvent may close this WebPage. // Protect against this being destroyed. Ref protect(*this); - pageClient().doneWithKeyEvent(event, handled); if (!handled) m_uiClient->didNotHandleKeyEvent(this, event); @@ -6593,6 +6607,8 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) if (!canProcessMoreKeyEvents) { if (auto* automationSession = process().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); + if (m_inputProcessingObserver) + m_inputProcessingObserver->didProcessAllPendingKeyboardEvents(); } break; } diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h index 488ac80306d..700b332f427 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -35,6 +35,7 @@ #include "FocusedElementInformation.h" #include "GeolocationPermissionRequestManagerProxy.h" #include "HiddenPageThrottlingAutoIncreasesCounter.h" +#include "InspectorDialogAgent.h" #include "LayerTreeContext.h" #include "MessageSender.h" #include "NotificationPermissionRequestManagerProxy.h" @@ -470,6 +471,8 @@ public: void setControlledByAutomation(bool); WebPageInspectorController& inspectorController() { return *m_inspectorController; } + InspectorDialogAgent* inspectorDialogAgent() { return m_inspectorDialogAgent; } + void setInspectorDialogAgent(InspectorDialogAgent * dialogAgent) { m_inspectorDialogAgent = dialogAgent; } #if PLATFORM(IOS_FAMILY) void showInspectorIndication(); @@ -535,6 +538,14 @@ public: void setPageLoadStateObserver(std::unique_ptr&&); + class InputProcessingObserver { + public: + virtual ~InputProcessingObserver() = default; + virtual void didProcessAllPendingKeyboardEvents() = 0; + virtual void didProcessAllPendingMouseEvents() = 0; + }; + void setObserber(InputProcessingObserver*); + void initializeWebPage(); void setDrawingArea(std::unique_ptr&&); @@ -2229,6 +2240,7 @@ private: bool m_treatsSHA1CertificatesAsInsecure { true }; RefPtr m_inspector; + InspectorDialogAgent* m_inspectorDialogAgent { nullptr }; #if ENABLE(FULLSCREEN_API) std::unique_ptr m_fullScreenManager; @@ -2577,6 +2589,7 @@ private: #if ENABLE(REMOTE_INSPECTOR) std::unique_ptr m_inspectorDebuggable; #endif + InputProcessingObserver* m_inputProcessingObserver { nullptr }; Optional m_spellDocumentTag; diff --git a/Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.cpp b/Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.cpp new file mode 100644 index 00000000000..2c7c9f07daf --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.cpp @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "InspectorBrowserAgentClientGLib.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorBrowserAgent.h" +#include "WebKitBrowserInspectorPrivate.h" +#include "WebKitWebContextPrivate.h" +#include "WebKitWebsiteDataManagerPrivate.h" +#include "WebKitWebViewPrivate.h" +#include "WebPageProxy.h" +#include +#include +#include +#include + +namespace WebKit { + +static Vector collectPages(Optional sessionID) +{ + Vector result; + for (WebProcessPool* pool : WebProcessPool::allProcessPools()) { + for (auto& process : pool->processes()) { + for (auto* page : process->pages()) { + if (!sessionID || page->sessionID() == sessionID) + result.append(page); + } + } + } + return result; +} + +static void closeAllPages(Optional sessionID) +{ + Vector pages = collectPages(sessionID); + for (auto* page : pages) + page->closePage(false); +} + +InspectorBrowserAgentClientGlib::InspectorBrowserAgentClientGlib() +{ +} + +RefPtr InspectorBrowserAgentClientGlib::createPage(WTF::String& error, PAL::SessionID sessionID) +{ + WebKitWebContext* context; + if (!sessionID || webkitWebContextGetProcessPool(webkit_web_context_get_default()).websiteDataStore()->sessionID() == sessionID) + context = webkit_web_context_get_default(); + else + context = m_idToContext.get(sessionID); + + if (context == nullptr) { + error = "Context with provided id not found"; + return nullptr; + } + + RefPtr page = webkitBrowserInspectorCreateNewPageInContext(context); + if (page == nullptr) + error = "Failed to create new page in the context"; + return page; +} + +void InspectorBrowserAgentClientGlib::closeAllWindows() +{ + closeAllPages(Optional()); + m_idToContext.clear(); + // FIXME(yurys): call g_main_loop_quit() ? +} + +static PAL::SessionID sessionIDFromContext(WebKitWebContext* context) +{ + WebKitWebsiteDataManager* data_manager = webkit_web_context_get_website_data_manager(context); + WebsiteDataStore& websiteDataStore = webkitWebsiteDataManagerGetDataStore(data_manager); + return websiteDataStore.sessionID(); +} + +BrowserContext InspectorBrowserAgentClientGlib::createBrowserContext(WTF::String& error) +{ + BrowserContext browserContext; + GRefPtr data_manager = adoptGRef(webkit_website_data_manager_new_ephemeral()); + GRefPtr context = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", data_manager.get(), "process-swap-on-cross-site-navigation-enabled", true, nullptr))); + if (!context) { + error = "Failed to create GLib ephemeral context"; + return browserContext; + } + browserContext.processPool = &webkitWebContextGetProcessPool(context.get()); + browserContext.dataStore = &webkitWebsiteDataManagerGetDataStore(data_manager.get()); + PAL::SessionID sessionID = sessionIDFromContext(context.get()); + m_idToContext.set(sessionID, WTFMove(context)); + return browserContext; +} + +void InspectorBrowserAgentClientGlib::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + m_idToContext.remove(sessionID); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.h b/Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.h new file mode 100644 index 00000000000..37a5e7ad390 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorBrowserAgentClientGLib.h @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorBrowserAgentClient.h" +#include "WebKitWebContext.h" +#include +#include +#include +#include + +namespace WebKit { + +class InspectorBrowserAgentClientGlib : public InspectorBrowserAgentClient { + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorBrowserAgentClientGlib(); + ~InspectorBrowserAgentClientGlib() override = default; + + RefPtr createPage(WTF::String& error, PAL::SessionID) override; + void closeAllWindows() override; + BrowserContext createBrowserContext(WTF::String& error) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + WebKitWebContext* findContext(WTF::String& error, PAL::SessionID); + + HashMap> m_idToContext; +}; + +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp new file mode 100644 index 00000000000..e8a29bebe24 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" + +#include "WebPageProxy.h" +#include + +namespace WebKit { +void WebPageInspectorEmulationAgent::platformSetSize(String& error, int width, int height) +{ + GtkWidget* viewWidget = m_page.viewWidget(); + GtkWidget* window = gtk_widget_get_toplevel(viewWidget); + if (!window) { + error = "Cannot find parent window"; + return; + } + if (!GTK_IS_WINDOW(window)) { + error = "Toplevel is not a window"; + return; + } + GtkAllocation viewAllocation; + gtk_widget_get_allocation(viewWidget, &viewAllocation); + + GtkAllocation windowAllocation; + gtk_widget_get_allocation(window, &windowAllocation); + + width += windowAllocation.width - viewAllocation.width; + height += windowAllocation.height - viewAllocation.height; + + gtk_window_resize(GTK_WINDOW(window), width, height); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp new file mode 100644 index 00000000000..1019c4fed53 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "KeyBindingTranslator.h" +#include "NativeWebKeyboardEvent.h" +#include "WebPageProxy.h" +#include + +namespace WebKit { + +static Vector commandsForKeyEvent(GdkEventType type, unsigned keyVal, unsigned state) +{ + ASSERT(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE); + + GUniquePtr event(gdk_event_new(type)); + event->key.keyval = keyVal; + event->key.time = GDK_CURRENT_TIME; + event->key.state = state; + // When synthesizing an event, an invalid hardware_keycode value can cause it to be badly processed by GTK+. + GUniqueOutPtr keys; + int keysCount; + if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyVal, &keys.outPtr(), &keysCount) && keysCount) + event->key.hardware_keycode = keys.get()[0].keycode; + return KeyBindingTranslator().commandsForKeyEvent(&event->key); +} + +static unsigned modifiersToEventState(OptionSet modifiers) +{ + unsigned state = 0; + if (modifiers.contains(WebEvent::Modifier::ControlKey)) + state |= GDK_CONTROL_MASK; + if (modifiers.contains(WebEvent::Modifier::ShiftKey)) + state |= GDK_SHIFT_MASK; + if (modifiers.contains(WebEvent::Modifier::AltKey)) + state |= GDK_META_MASK; + if (modifiers.contains(WebEvent::Modifier::CapsLockKey)) + state |= GDK_LOCK_MASK; + return state; +} + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) +{ + Vector commands; + const guint keyVal = WebCore::PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(windowsVirtualKeyCode); + String keyIdentifier; + if (keyVal) { + GdkEventType event = GDK_NOTHING; + switch (type) + { + case WebKeyboardEvent::KeyDown: + event = GDK_KEY_PRESS; + break; + case WebKeyboardEvent::KeyUp: + event = GDK_KEY_RELEASE; + break; + default: + fprintf(stderr, "Unsupported event type = %d\n", type); + break; + } + unsigned state = modifiersToEventState(modifiers); + commands = commandsForKeyEvent(event, keyVal, state); + keyIdentifier = WebCore::PlatformKeyboardEvent::keyIdentifierForGdkKeyCode(keyVal); + } + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp, + WTFMove(commands)); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp new file mode 100644 index 00000000000..5805ee6fdf4 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorTargetProxyGtk.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include +#include + +namespace WebKit { + +void WebPageInspectorTargetProxy::platformActivate(String& error) const +{ + GtkWidget* parent = gtk_widget_get_toplevel(m_page.viewWidget()); + if (WebCore::widgetIsOnscreenToplevelWindow(parent)) + gtk_window_present(GTK_WINDOW(parent)); + else + error = "The view is not on screen"; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm index e139968d4f0..98093c684db 100644 --- a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm +++ b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm @@ -408,6 +408,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { + if (!event.nativeEvent()) + return; [m_contentView _didHandleKeyEvent:event.nativeEvent() eventWasHandled:eventWasHandled]; } diff --git a/Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.h b/Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.h new file mode 100644 index 00000000000..03aff71e9f9 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.h @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#pragma once + +#include "InspectorBrowserAgentClient.h" +#include + +OBJC_PROTOCOL(_WKBrowserInspectorDelegate); + +namespace WebKit { + +class InspectorBrowserAgentClientMac : public InspectorBrowserAgentClient { + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorBrowserAgentClientMac(_WKBrowserInspectorDelegate* delegate); + ~InspectorBrowserAgentClientMac() override = default; + + RefPtr createPage(WTF::String& error, PAL::SessionID) override; + void closeAllWindows() override; + BrowserContext createBrowserContext(WTF::String& error) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + private: + + _WKBrowserInspectorDelegate* delegate_; +}; + + +} // namespace API diff --git a/Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.mm b/Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.mm new file mode 100644 index 00000000000..e3062b3651f --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorBrowserAgentClientMac.mm @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#import "config.h" +#import "InspectorBrowserAgentClientMac.h" + +#import +#import +#import "WebPageProxy.h" +#import "WebProcessPool.h" +#import "WebsiteDataStore.h" +#import "_WKBrowserInspector.h" +#import "WKProcessPoolInternal.h" +#import "WKWebsiteDataStoreInternal.h" +#import "WKWebView.h" +#import "WKWebViewInternal.h" + +namespace WebKit { + +InspectorBrowserAgentClientMac::InspectorBrowserAgentClientMac(_WKBrowserInspectorDelegate* delegate) + : delegate_(delegate) +{ +} + +RefPtr InspectorBrowserAgentClientMac::createPage(WTF::String& error, PAL::SessionID sessionID) +{ + WKWebView *webView = [delegate_ createNewPage:sessionID.toUInt64()]; + if (!webView) { + error = "Internal error: can't create page in given context"_s; + return nil; + } + return [webView _page]; +} + +void InspectorBrowserAgentClientMac::closeAllWindows() +{ + [delegate_ quit]; +} + +BrowserContext InspectorBrowserAgentClientMac::createBrowserContext(WTF::String& error) +{ + _WKBrowserContext* wkBrowserContext = [[delegate_ createBrowserContext] autorelease]; + BrowserContext browserContext; + browserContext.processPool = &static_cast([[wkBrowserContext processPool] _apiObject]); + browserContext.dataStore = &static_cast([[wkBrowserContext dataStore] _apiObject]); + return browserContext; +} + +void InspectorBrowserAgentClientMac::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + [delegate_ deleteBrowserContext:sessionID.toUInt64()]; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm index 22653d74398..bf27558fdfd 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm @@ -455,6 +455,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { + if (!event.nativeEvent()) + return; m_impl->doneWithKeyEvent(event.nativeEvent(), eventWasHandled); } @@ -930,6 +932,9 @@ void PageClientImpl::didRestoreScrollPosition() bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event) { + // Simulated event. + if (!event.nativeEvent()) + return false; return m_impl->windowIsFrontWindowUnderMouse(event.nativeEvent()); } diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm new file mode 100644 index 00000000000..d364ca6d955 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#import "config.h" +#import "WebPageInspectorEmulationAgent.h" + +#import "WebPageProxy.h" + +namespace WebKit { + +void WebPageInspectorEmulationAgent::platformSetSize(String& error, int width, int height) +{ + NSWindow* window = m_page.platformWindow(); + NSRect windowRect = [window frame]; + NSRect viewRect = window.contentLayoutRect; + windowRect.size.width += width - viewRect.size.width; + windowRect.size.height += height - viewRect.size.height; + [window setFrame:windowRect display:YES animate:NO]; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm new file mode 100644 index 00000000000..7ce9b71b0fb --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +namespace WebKit { + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) +{ + fprintf(stderr, "Mac does not support dispatching key events"); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm new file mode 100644 index 00000000000..06a7e286abf --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorTargetProxyMac.mm @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorTargetProxy.h" + +#if PLATFORM(MAC) + +namespace WebKit { + +void WebPageInspectorTargetProxy::platformActivate(String& error) const +{ + error = "Not Implemented"; +} + +} // namespace WebKit + +#endif diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp new file mode 100644 index 00000000000..2fef19fd5ee --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" + +#include "WebPageProxy.h" +#include + +namespace WebKit { + +void WebPageInspectorEmulationAgent::platformSetSize(String& error, int width, int height) +{ + struct wpe_view_backend* backend = m_page.viewBackend(); + wpe_view_backend_dispatch_set_size(backend, width, height); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp new file mode 100644 index 00000000000..4ae3eb95dff --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "NativeWebKeyboardEvent.h" +#include "WebPageProxy.h" +#include +#include + +namespace WebKit { + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(String& error, const String& type, const String& keyRef) +{ +} + +static unsigned toWPEButton(WebMouseEvent::Button button) +{ + switch (button) { + case WebMouseEvent::NoButton: + case WebMouseEvent::LeftButton: + return 1; + case WebMouseEvent::MiddleButton: + return 3; + case WebMouseEvent::RightButton: + return 2; + } + return 1; +} + +static unsigned toWPEModifiers(OptionSet modifiers) +{ + unsigned result = 0; + if (modifiers.contains(WebEvent::Modifier::ControlKey)) + result |= wpe_input_keyboard_modifier_control; + if (modifiers.contains(WebEvent::Modifier::ShiftKey)) + result |= wpe_input_keyboard_modifier_shift; + if (modifiers.contains(WebEvent::Modifier::AltKey)) + result |= wpe_input_keyboard_modifier_alt; + if (modifiers.contains(WebEvent::Modifier::CapsLockKey)) + fprintf(stderr, "Unsupported modifier CapsLock will be ignored.\n"); + return result; +} + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) +{ + unsigned keyCode = WebCore::PlatformKeyboardEvent::WPEKeyCodeForWindowsKeyCode(windowsVirtualKeyCode); + struct wpe_input_xkb_keymap_entry* entries; + uint32_t entriesCount; + fprintf(stderr, "platformDispatchKeyEvent %s => %d\n", key.ascii().data(), keyCode); + wpe_input_xkb_context_get_entries_for_key_code(wpe_input_xkb_context_get_default(), keyCode, &entries, &entriesCount); + bool pressed = type == WebKeyboardEvent::KeyDown; + struct wpe_input_keyboard_event event = { 0, keyCode, entriesCount ? entries[0].hardware_key_code : 0, pressed, toWPEModifiers(modifiers) }; + // event.time = timestamp.secondsSinceEpoch().milliseconds(); + wpe_view_backend_dispatch_keyboard_event(m_page.viewBackend(), &event); + free(entries); +} + +void WebPageInspectorInputAgent::platformDispatchMouseEvent(WebMouseEvent::Type type, int x, int y, WebMouseEvent::Button button, OptionSet modifiers) +{ + wpe_input_pointer_event_type eventType = wpe_input_pointer_event_type_null; + uint32_t eventButton = 0; + uint32_t state = 0; + if (type == WebEvent::MouseDown || type == WebEvent::MouseUp) { + eventType = wpe_input_pointer_event_type_button; + state = (type == WebEvent::MouseDown); + eventButton = toWPEButton(button); + } else if (type == WebEvent::MouseMove) { + eventType = wpe_input_pointer_event_type_motion; + } + struct wpe_input_pointer_event event { eventType, 0, x, y, eventButton, state, toWPEModifiers(modifiers) }; + wpe_view_backend_dispatch_pointer_event(m_page.viewBackend(), &event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp new file mode 100644 index 00000000000..74dace1cc7c --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorTargetProxyWPE.cpp @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +#include "config.h" +#include "WebPageInspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include + +namespace WebKit { + +void WebPageInspectorTargetProxy::platformActivate(String& error) const +{ + struct wpe_view_backend* backend = m_page.viewBackend(); + wpe_view_backend_add_activity_state(backend, wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window); +} + +} // namespace WebKit diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj index 5cb81ccc202..2bf6772abb6 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj @@ -1667,6 +1667,20 @@ CEE4AE2B1A5DCF430002F49B /* UIKitSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = CEE4AE2A1A5DCF430002F49B /* UIKitSPI.h */; }; D3B9484711FF4B6500032B39 /* WebPopupMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = D3B9484311FF4B6500032B39 /* WebPopupMenu.h */; }; D3B9484911FF4B6500032B39 /* WebSearchPopupMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */; }; + D71A94322370E025002C4D9E /* InspectorBrowserAgentClientMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94302370E025002C4D9E /* InspectorBrowserAgentClientMac.h */; }; + D71A94342370E07A002C4D9E /* InspectorBrowserAgentClient.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94332370E07A002C4D9E /* InspectorBrowserAgentClient.h */; }; + D71A94382370F032002C4D9E /* BrowserInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94372370F032002C4D9E /* BrowserInspectorController.h */; }; + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */; }; + D71A94412371F67E002C4D9E /* WebPageInspectorTargetProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A943E2371F67E002C4D9E /* WebPageInspectorTargetProxy.h */; }; + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */; }; + D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */; }; + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94492372290B002C4D9E /* _WKBrowserInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */; }; + D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D76D6887238DBD80008D314B /* InspectorDialogAgent.h */; }; + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */; }; + D79902B2236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm */; }; + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */; }; + D7EB04E72372A73B00F744CE /* InspectorBrowserAgentClientMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D7EB04E62372A73B00F744CE /* InspectorBrowserAgentClientMac.mm */; }; E105FE5418D7B9DE008F57A8 /* EditingRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E105FE5318D7B9DE008F57A8 /* EditingRange.h */; }; E11D35AE16B63D1B006D23D7 /* com.apple.WebProcess.sb in Resources */ = {isa = PBXBuildFile; fileRef = E1967E37150AB5E200C73169 /* com.apple.WebProcess.sb */; }; E14A954A16E016A40068DE82 /* NetworkProcessPlatformStrategies.h in Headers */ = {isa = PBXBuildFile; fileRef = E14A954816E016A40068DE82 /* NetworkProcessPlatformStrategies.h */; }; @@ -4704,6 +4718,21 @@ D3B9484311FF4B6500032B39 /* WebPopupMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPopupMenu.h; sourceTree = ""; }; D3B9484411FF4B6500032B39 /* WebSearchPopupMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSearchPopupMenu.cpp; sourceTree = ""; }; D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSearchPopupMenu.h; sourceTree = ""; }; + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBrowserInspector.h; sourceTree = ""; }; + D71A94302370E025002C4D9E /* InspectorBrowserAgentClientMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorBrowserAgentClientMac.h; sourceTree = ""; }; + D71A94332370E07A002C4D9E /* InspectorBrowserAgentClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorBrowserAgentClient.h; sourceTree = ""; }; + D71A94372370F032002C4D9E /* BrowserInspectorController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserInspectorController.h; sourceTree = ""; }; + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorPipe.h; sourceTree = ""; }; + D71A943E2371F67E002C4D9E /* WebPageInspectorTargetProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorTargetProxy.h; sourceTree = ""; }; + D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorEmulationAgent.h; sourceTree = ""; }; + D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorInputAgent.h; sourceTree = ""; }; + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKBrowserInspector.h; sourceTree = ""; }; + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserInspectorPipe.h; sourceTree = ""; }; + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDialogAgent.h; sourceTree = ""; }; + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorEmulationAgentMac.mm; sourceTree = ""; }; + D79902AF236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorTargetProxyMac.mm; sourceTree = ""; }; + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorInputAgentMac.mm; sourceTree = ""; }; + D7EB04E62372A73B00F744CE /* InspectorBrowserAgentClientMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorBrowserAgentClientMac.mm; sourceTree = ""; }; DF58C6311371AC5800F9A37C /* NativeWebWheelEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebWheelEvent.h; sourceTree = ""; }; DF58C6351371ACA000F9A37C /* NativeWebWheelEventMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NativeWebWheelEventMac.mm; sourceTree = ""; }; E105FE5318D7B9DE008F57A8 /* EditingRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingRange.h; sourceTree = ""; }; @@ -6305,6 +6334,7 @@ 37C4C08318149C2A003688B9 /* Cocoa */ = { isa = PBXGroup; children = ( + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */, 1A43E826188F38E2009E4D30 /* Deprecated */, 37A5E01218BBF937000A081E /* _WKActivatedElementInfo.h */, 37A5E01118BBF937000A081E /* _WKActivatedElementInfo.mm */, @@ -7783,6 +7813,14 @@ BC032DC310F438260058C15A /* UIProcess */ = { isa = PBXGroup; children = ( + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */, + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */, + D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */, + D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */, + D71A943E2371F67E002C4D9E /* WebPageInspectorTargetProxy.h */, + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */, + D71A94372370F032002C4D9E /* BrowserInspectorController.h */, + D71A94332370E07A002C4D9E /* InspectorBrowserAgentClient.h */, BC032DC410F4387C0058C15A /* API */, 512F588D12A8836F00629530 /* Authentication */, 9955A6E81C79809000EB6A93 /* Automation */, @@ -8060,6 +8098,7 @@ BC0C376610F807660076D7CB /* C */ = { isa = PBXGroup; children = ( + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */, 5123CF18133D25E60056F800 /* cg */, 6EE849C41368D9040038D481 /* mac */, BCB63477116BF10600603215 /* WebKit2_C.h */, @@ -8655,6 +8694,11 @@ BCCF085C113F3B7500C650C5 /* mac */ = { isa = PBXGroup; children = ( + D7EB04E62372A73B00F744CE /* InspectorBrowserAgentClientMac.mm */, + D71A94302370E025002C4D9E /* InspectorBrowserAgentClientMac.h */, + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */, + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */, + D79902AF236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm */, B878B613133428DC006888E9 /* CorrectionPanel.h */, B878B614133428DC006888E9 /* CorrectionPanel.mm */, C1817362205844A900DFDA65 /* DisplayLink.cpp */, @@ -9334,6 +9378,7 @@ 510F59101DDE296900412FF5 /* _WKIconLoadingDelegate.h in Headers */, 37A64E5518F38E3C00EB30F1 /* _WKInputDelegate.h in Headers */, 5CAFDE452130846300B1F7E1 /* _WKInspector.h in Headers */, + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */, 5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */, 9979CA58237F49F10039EC05 /* _WKInspectorPrivate.h in Headers */, A5C0F0AB2000658200536536 /* _WKInspectorWindow.h in Headers */, @@ -9447,6 +9492,7 @@ 7C89D2981A6753B2003A5FDE /* APIPageConfiguration.h in Headers */, 1AC1336C18565C7A00F3EC05 /* APIPageHandle.h in Headers */, 1AFDD3151891B54000153970 /* APIPolicyClient.h in Headers */, + D71A94382370F032002C4D9E /* BrowserInspectorController.h in Headers */, 7CE4D2201A4914CA00C7F152 /* APIProcessPoolConfiguration.h in Headers */, F634445612A885C8000612D8 /* APISecurityOrigin.h in Headers */, 1AFDE6621954E9B100C48FFA /* APISessionState.h in Headers */, @@ -9566,6 +9612,7 @@ BC06F43A12DBCCFB002D78DE /* GeolocationPermissionRequestProxy.h in Headers */, 2DA944A41884E4F000ED86DB /* GestureTypes.h in Headers */, 2DA049B8180CCD0A00AAFA9E /* GraphicsLayerCARemote.h in Headers */, + D71A94342370E07A002C4D9E /* InspectorBrowserAgentClient.h in Headers */, C0CE72AD1247E78D00BC0EC4 /* HandleMessage.h in Headers */, 1AC75A1B1B3368270056745B /* HangDetectionDisabler.h in Headers */, 57AC8F50217FEED90055438C /* HidConnection.h in Headers */, @@ -9689,8 +9736,10 @@ 41DC45961E3D6E2200B11F51 /* NetworkRTCProvider.h in Headers */, 413075AB1DE85F330039EC69 /* NetworkRTCSocket.h in Headers */, 5C20CBA01BB1ECD800895BB1 /* NetworkSession.h in Headers */, + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */, 532159551DBAE7290054AA3C /* NetworkSessionCocoa.h in Headers */, 417915B92257046F00D6F97E /* NetworkSocketChannel.h in Headers */, + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */, 570DAAC22303730300E8FC04 /* NfcConnection.h in Headers */, 570DAAAE23026F5C00E8FC04 /* NfcService.h in Headers */, 31A2EC5614899C0900810D71 /* NotificationPermissionRequest.h in Headers */, @@ -9772,6 +9821,7 @@ CD2865EE2255562000606AC7 /* ProcessTaskStateObserver.h in Headers */, 463FD4821EB94EC000A2982C /* ProcessTerminationReason.h in Headers */, 86E67A251910B9D100004AB7 /* ProcessThrottler.h in Headers */, + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */, 83048AE61ACA45DC0082C832 /* ProcessThrottlerClient.h in Headers */, A1E688701F6E2BAB007006A6 /* QuarantineSPI.h in Headers */, 57FD318222B3515E008D0E8B /* RedirectSOAuthorizationSession.h in Headers */, @@ -9820,7 +9870,6 @@ 511F8A7B138B460900A95F44 /* SecItemShimLibrary.h in Headers */, E18E690C169B563F009B6670 /* SecItemShimProxy.h in Headers */, E18E6918169B667B009B6670 /* SecItemShimProxyMessages.h in Headers */, - 7AA746D523593D8100095050 /* SecItemSPI.h in Headers */, 570AB8F320AE3BD700B8BE87 /* SecKeyProxyStore.h in Headers */, 514D9F5719119D35000063A7 /* ServicesController.h in Headers */, 1AFDE65A1954A42B00C48FFA /* SessionState.h in Headers */, @@ -9934,6 +9983,7 @@ F430E94422473DFF005FE053 /* WebContentMode.h in Headers */, 31A505FA1680025500A930EB /* WebContextClient.h in Headers */, BC09B8F9147460F7005F5625 /* WebContextConnectionClient.h in Headers */, + D71A94412371F67E002C4D9E /* WebPageInspectorTargetProxy.h in Headers */, BCDE059B11CDA8AE00E41AF1 /* WebContextInjectedBundleClient.h in Headers */, 51871B5C127CB89D00F76232 /* WebContextMenu.h in Headers */, BC032D7710F4378D0058C15A /* WebContextMenuClient.h in Headers */, @@ -10167,6 +10217,7 @@ BCD25F1711D6BDE100169B0E /* WKBundleFrame.h in Headers */, BCF049E611FE20F600F86A58 /* WKBundleFramePrivate.h in Headers */, BC49862F124D18C100D834E1 /* WKBundleHitTestResult.h in Headers */, + D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */, BC204EF211C83EC8008F3375 /* WKBundleInitialize.h in Headers */, 65B86F1E12F11DE300B7DD8A /* WKBundleInspector.h in Headers */, 1A8B66B41BC45B010082DF77 /* WKBundleMac.h in Headers */, @@ -10215,6 +10266,7 @@ 5C795D71229F3757003FF1C4 /* WKContextMenuElementInfoPrivate.h in Headers */, 51A555F6128C6C47009ABCEC /* WKContextMenuItem.h in Headers */, 51A55601128C6D92009ABCEC /* WKContextMenuItemTypes.h in Headers */, + D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */, A1EA02381DABFF7E0096021F /* WKContextMenuListener.h in Headers */, BCC938E11180DE440085E5FE /* WKContextPrivate.h in Headers */, 9FB5F395169E6A80002C25BF /* WKContextPrivateMac.h in Headers */, @@ -10363,6 +10415,7 @@ 1AB8A1F818400BB800E9AE69 /* WKPageContextMenuClient.h in Headers */, 8372DB251A674C8F00C697C5 /* WKPageDiagnosticLoggingClient.h in Headers */, 1AB8A1F418400B8F00E9AE69 /* WKPageFindClient.h in Headers */, + D71A94322370E025002C4D9E /* InspectorBrowserAgentClientMac.h in Headers */, 1AB8A1F618400B9D00E9AE69 /* WKPageFindMatchesClient.h in Headers */, 1AB8A1F018400B0000E9AE69 /* WKPageFormClient.h in Headers */, BC7B633712A45ABA00D174A4 /* WKPageGroup.h in Headers */, @@ -11318,6 +11371,7 @@ 2D92A781212B6A7100F493FD /* MessageReceiverMap.cpp in Sources */, 2D92A782212B6A7100F493FD /* MessageSender.cpp in Sources */, 2D92A77A212B6A6100F493FD /* Module.cpp in Sources */, + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */, 57B826452304F14000B72EB0 /* NearFieldSoftLink.mm in Sources */, 2D913443212CF9F000128AFD /* NetscapeBrowserFuncs.cpp in Sources */, 2D913444212CF9F000128AFD /* NetscapePlugin.cpp in Sources */, @@ -11342,6 +11396,7 @@ 1A2D8439127F65D5001EB962 /* NPObjectMessageReceiverMessageReceiver.cpp in Sources */, 2D92A792212B6AD400F493FD /* NPObjectProxy.cpp in Sources */, 2D92A793212B6AD400F493FD /* NPRemoteObjectMap.cpp in Sources */, + D7EB04E72372A73B00F744CE /* InspectorBrowserAgentClientMac.mm in Sources */, 2D913447212CF9F000128AFD /* NPRuntimeObjectMap.cpp in Sources */, 2D913448212CF9F000128AFD /* NPRuntimeUtilities.cpp in Sources */, 2D92A794212B6AD400F493FD /* NPVariantData.cpp in Sources */, @@ -11381,11 +11436,13 @@ A1ADAFB62368E6A8009CB776 /* SharedMemory.cpp in Sources */, 2DE6943D18BD2A68005C15E5 /* SmartMagnificationControllerMessageReceiver.cpp in Sources */, 1A334DED16DE8F88006A8E38 /* StorageAreaMapMessageReceiver.cpp in Sources */, + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */, 9368EEDE2303A90200BDB11A /* StorageManagerSetMessageReceiver.cpp in Sources */, 2D92A783212B6A7100F493FD /* StringReference.cpp in Sources */, 2D11B7512126A282006F8878 /* UnifiedSource1-mm.mm in Sources */, 2D11B7522126A282006F8878 /* UnifiedSource1.cpp in Sources */, 2D11B7542126A282006F8878 /* UnifiedSource2.cpp in Sources */, + D79902B2236E9404005D6F7E /* WebPageInspectorTargetProxyMac.mm in Sources */, 2D11B7532126A282006F8878 /* UnifiedSource2-mm.mm in Sources */, 2D11B7562126A282006F8878 /* UnifiedSource3.cpp in Sources */, 2D11B7552126A282006F8878 /* UnifiedSource3-mm.mm in Sources */, diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp index a70f6fd5209..f02e5c774a4 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "WebPageInspectorTarget.h" +#include "FrameInfoData.h" +#include "WebFrame.h" #include "WebPage.h" #include "WebPageInspectorTargetFrontendChannel.h" #include @@ -45,6 +47,11 @@ String WebPageInspectorTarget::identifier() const return toTargetID(m_page.identifier()); } +String WebPageInspectorTarget::url() const +{ + return m_page.mainWebFrame()->info().request.url().string(); +} + void WebPageInspectorTarget::connect(Inspector::FrontendChannel::ConnectionType connectionType) { if (m_channel) diff --git a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h index 6cbd7fad5ff..176c46f186b 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h +++ b/Source/WebKit/WebProcess/WebPage/WebPageInspectorTarget.h @@ -44,6 +44,7 @@ public: Inspector::InspectorTargetType type() const final { return Inspector::InspectorTargetType::Page; } String identifier() const final; + String url() const final; void connect(Inspector::FrontendChannel::ConnectionType) override; void disconnect() override; diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp index 0c92cd9b030..0ed5b37c4d5 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp @@ -628,7 +628,8 @@ void WebProcess::setCacheModel(CacheModel cacheModel) unsigned cacheMaxDeadCapacity = 0; Seconds deadDecodedDataDeletionInterval; unsigned backForwardCacheSize = 0; - calculateMemoryCacheSizes(cacheModel, cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval, backForwardCacheSize); + // FIXME(yurys): forcefully disable cache becaus it swallows Runtime.executionContextCreated events on goBack navigation. + // calculateMemoryCacheSizes(cacheModel, cacheTotalCapacity, cacheMinDeadCapacity, cacheMaxDeadCapacity, deadDecodedDataDeletionInterval, backForwardCacheSize); auto& memoryCache = MemoryCache::singleton(); memoryCache.setCapacities(cacheMinDeadCapacity, cacheMaxDeadCapacity, cacheTotalCapacity); diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.h b/Tools/MiniBrowser/gtk/BrowserWindow.h index 1570d65effb..456f96cf589 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.h +++ b/Tools/MiniBrowser/gtk/BrowserWindow.h @@ -37,7 +37,7 @@ G_BEGIN_DECLS #define BROWSER_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_WINDOW)) #define BROWSER_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BROWSER_TYPE_WINDOW)) #define BROWSER_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), BROWSER_TYPE_WINDOW, BrowserWindowClass)) -#define BROWSER_DEFAULT_URL "http://www.webkitgtk.org/" +#define BROWSER_DEFAULT_URL "about:blank" #define BROWSER_ABOUT_SCHEME "minibrowser-about" typedef struct _BrowserWindow BrowserWindow; diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c index 4c5147dcd38..c04110b8033 100644 --- a/Tools/MiniBrowser/gtk/main.c +++ b/Tools/MiniBrowser/gtk/main.c @@ -53,6 +53,7 @@ static const char *cookiesFile; static const char *cookiesPolicy; static const char *proxy; static gboolean darkMode; +static gboolean inspectorPipe; static gboolean printVersion; typedef enum { @@ -121,6 +122,7 @@ static const GOptionEntry commandLineOptions[] = { "ignore-tls-errors", 0, 0, G_OPTION_ARG_NONE, &ignoreTLSErrors, "Ignore TLS errors", NULL }, { "content-filter", 0, 0, G_OPTION_ARG_FILENAME, &contentFilter, "JSON with content filtering rules", "FILE" }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WebKitGTK version", NULL }, + { "inspector-pipe", 0, 0, G_OPTION_ARG_NONE, &inspectorPipe, "Open pipe connection to the remote inspector", NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" }, { 0, 0, 0, 0, 0, 0, 0 } }; @@ -498,6 +500,29 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } +static WebKitWebView *createNewPage(WebKitBrowserInspector *browser_inspector, WebKitWebContext *context) +{ + WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "web-context", context, + "is-ephemeral", webkit_web_context_is_ephemeral(context), + "is-controlled-by-automation", TRUE, + NULL)); + GtkWidget *newWindow = browser_window_new(NULL, context); + browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView); + gtk_widget_grab_focus(GTK_WIDGET(newWebView)); + gtk_widget_show(GTK_WIDGET(newWindow)); + webkit_web_view_load_uri(newWebView, "about:blank"); + return newWebView; +} + +static void configureBrowserInspectorPipe() +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + + webkit_browser_inspector_initialize_pipe(); +} + int main(int argc, char *argv[]) { #if ENABLE_DEVELOPER_MODE @@ -545,6 +570,9 @@ int main(int argc, char *argv[]) WebKitWebContext *webContext = g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", manager, "process-swap-on-cross-site-navigation-enabled", TRUE, NULL); g_object_unref(manager); + if (inspectorPipe) + configureBrowserInspectorPipe(); + if (cookiesPolicy) { WebKitCookieManager *cookieManager = webkit_web_context_get_cookie_manager(webContext); GEnumClass *enumClass = g_type_class_ref(WEBKIT_TYPE_COOKIE_ACCEPT_POLICY); diff --git a/Tools/MiniBrowser/mac/AppDelegate.h b/Tools/MiniBrowser/mac/AppDelegate.h index 45ef1a6424e..6e015fcb8bc 100644 --- a/Tools/MiniBrowser/mac/AppDelegate.h +++ b/Tools/MiniBrowser/mac/AppDelegate.h @@ -23,10 +23,22 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#import + @class ExtensionManagerWindowController; -@interface BrowserAppDelegate : NSObject { +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface WebViewDialog : NSObject +@property (nonatomic, strong) WKWebView *webView; +@property (nonatomic, copy) void (^completionHandler)(BOOL accept, NSString* value); +@end + +@interface BrowserAppDelegate : NSObject { NSMutableSet *_browserWindowControllers; + NSMutableSet *_headlessWindows; + NSMutableSet *_browserContexts; + bool _headless; + NSMutableSet *_dialogs; ExtensionManagerWindowController *_extensionManagerWindowController; IBOutlet NSMenuItem *_newWebKit1WindowItem; diff --git a/Tools/MiniBrowser/mac/AppDelegate.m b/Tools/MiniBrowser/mac/AppDelegate.m index b6af4ef724f..54157dc246a 100644 --- a/Tools/MiniBrowser/mac/AppDelegate.m +++ b/Tools/MiniBrowser/mac/AppDelegate.m @@ -34,6 +34,7 @@ #import #import #import +#import #import #import #import @@ -52,16 +53,44 @@ @interface NSApplication (TouchBar) @property (getter=isAutomaticCustomizeTouchBarMenuItemEnabled) BOOL automaticCustomizeTouchBarMenuItemEnabled; @end +@implementation WebViewDialog +@end + +enum { + _NSBackingStoreUnbuffered = 3 +}; + +NSString* const ActivityReason = @"Batch headless process"; +const NSActivityOptions ActivityOptions = + (NSActivityUserInitiatedAllowingIdleSystemSleep | + NSActivityLatencyCritical) & + ~(NSActivitySuddenTerminationDisabled | + NSActivityAutomaticTerminationDisabled); + @implementation BrowserAppDelegate - (id)init { self = [super init]; - if (self) { - _browserWindowControllers = [[NSMutableSet alloc] init]; + if (!self) + return nil; + + NSArray *arguments = [[NSProcessInfo processInfo] arguments]; + _headless = [arguments containsObject: @"--headless"]; + _browserContexts = [[NSMutableSet alloc] init]; + + if (_headless) { + _headlessWindows = [[NSMutableSet alloc] init]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; + [[NSProcessInfo processInfo] beginActivityWithOptions:ActivityOptions + reason:ActivityReason]; + _dialogs = [[NSMutableSet alloc] init]; + } else { _extensionManagerWindowController = [[ExtensionManagerWindowController alloc] init]; + _browserWindowControllers = [[NSMutableSet alloc] init]; } - + if ([arguments containsObject: @"--inspector-pipe"]) + [_WKBrowserInspector initializeRemoteInspectorPipe:self]; return self; } @@ -88,7 +117,7 @@ - (void)awakeFromNib configuration.networkCacheSpeculativeValidationEnabled = YES; dataStore = [[WKWebsiteDataStore alloc] _initWithConfiguration:configuration]; } - + return dataStore; } @@ -109,7 +138,7 @@ - (void)awakeFromNib processConfiguration.usesSingleWebProcess = YES; if ([SettingsController shared].processSwapOnWindowOpenWithOpenerEnabled) processConfiguration.processSwapsOnWindowOpenWithOpener = true; - + configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease]; NSArray<_WKExperimentalFeature *> *experimentalFeatures = [WKPreferences _experimentalFeatures]; @@ -145,6 +174,9 @@ - (void)awakeFromNib - (BrowserWindowController *)createBrowserWindowController:(id)sender { + if (_headless) + return nil; + BrowserWindowController *controller = nil; BOOL useWebKit2 = NO; BOOL makeEditable = NO; @@ -158,9 +190,9 @@ - (BrowserWindowController *)createBrowserWindowController:(id)sender } if (!useWebKit2) - controller = [[WK1BrowserWindowController alloc] initWithWindowNibName:@"BrowserWindow"]; + controller = [[[WK1BrowserWindowController alloc] initWithWindowNibName:@"BrowserWindow"] autorelease]; else - controller = [[WK2BrowserWindowController alloc] initWithConfiguration:defaultConfiguration()]; + controller = [[[WK2BrowserWindowController alloc] initWithConfiguration:defaultConfiguration()] autorelease]; if (makeEditable) controller.editable = YES; @@ -185,6 +217,9 @@ - (IBAction)newWindow:(id)sender - (IBAction)newPrivateWindow:(id)sender { + if (_headless) + return; + WKWebViewConfiguration *privateConfiguraton = [defaultConfiguration() copy]; privateConfiguraton.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore]; @@ -209,11 +244,20 @@ - (IBAction)newEditorWindow:(id)sender - (void)browserWindowWillClose:(NSWindow *)window { - [_browserWindowControllers removeObject:window.windowController]; + if (_headless) { + [_headlessWindows removeObject:window]; + } else { + [_browserWindowControllers removeObject:window.windowController]; + } } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + if (_headless) { + [self createNewPage:0]; + return; + } + WebHistory *webHistory = [[WebHistory alloc] init]; [WebHistory setOptionalSharedHistory:webHistory]; [webHistory release]; @@ -255,6 +299,9 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filenam - (IBAction)openDocument:(id)sender { + if (_headless) + return; + BrowserWindowController *browserWindowController = [self frontmostBrowserWindowController]; if (browserWindowController) { @@ -284,6 +331,9 @@ - (IBAction)openDocument:(id)sender - (void)didChangeSettings { + if (_headless) + return; + [self _updateNewWindowKeyEquivalents]; // Let all of the BrowserWindowControllers know that a setting changed, so they can attempt to dynamically update. @@ -312,6 +362,8 @@ - (void)_updateNewWindowKeyEquivalents - (IBAction)showExtensionsManager:(id)sender { + if (_headless) + return; [_extensionManagerWindowController showWindow:sender]; } @@ -345,4 +397,123 @@ - (IBAction)clearDefaultStoreWebsiteData:(id)sender }]; } +#pragma mark WKBrowserInspectorDelegate + +- (WKWebViewConfiguration *) sessionConfiguration:(uint64_t)sessionID +{ + for (_WKBrowserContext *browserContext in _browserContexts) { + if ([[browserContext dataStore] sessionID] != sessionID) + continue; + WKWebViewConfiguration *configuration = [[defaultConfiguration() copy] autorelease]; + configuration.websiteDataStore = [browserContext dataStore]; + configuration.processPool = [browserContext processPool]; + return configuration; + } + return defaultConfiguration(); +} + +- (WKWebView *)createNewPage:(uint64_t)sessionID +{ + if (_headless) + return [self createHeadlessPage:sessionID]; + + WKWebViewConfiguration *configuration = [self sessionConfiguration:sessionID]; + WK2BrowserWindowController *controller = [[[WK2BrowserWindowController alloc] initWithConfiguration:configuration] autorelease]; + if (!controller) + return nil; + [[controller window] makeKeyAndOrderFront:nil]; + [_browserWindowControllers addObject:controller]; + [controller loadURLString:[SettingsController shared].defaultURL]; + return [controller webView]; +} + +- (WKWebView *)createHeadlessPage:(uint64_t)sessionID +{ + NSRect rect = NSMakeRect(0, 0, 1024, 768); + NSScreen *firstScreen = [[NSScreen screens] objectAtIndex:0]; + NSRect windowRect = NSOffsetRect(rect, -10000, [firstScreen frame].size.height - rect.size.height + 10000); + NSWindow* window = [[[NSWindow alloc] initWithContentRect:windowRect styleMask:NSWindowStyleMaskBorderless backing:(NSBackingStoreType)_NSBackingStoreUnbuffered defer:YES] autorelease]; + + WKWebViewConfiguration *configuration = [self sessionConfiguration:sessionID]; + WKWebView* webView = [[WKWebView alloc] initWithFrame:[window.contentView bounds] configuration:configuration]; + if (!webView) + return nil; + + webView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [window.contentView addSubview:webView]; + NSURL *url = [NSURL _webkit_URLWithUserTypedString:@"about:blank"]; + [webView loadRequest:[NSURLRequest requestWithURL:url]]; + [_headlessWindows addObject:window]; + webView.UIDelegate = self; + return webView; +} + +- (_WKBrowserContext *)createBrowserContext +{ + _WKBrowserContext *browserContext = [[_WKBrowserContext alloc] init]; + _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease]; + browserContext.dataStore = [WKWebsiteDataStore nonPersistentDataStore]; + browserContext.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease]; + [_browserContexts addObject:browserContext]; + return browserContext; +} + +- (void)deleteBrowserContext:(uint64_t)sessionID +{ + for (_WKBrowserContext *browserContext in _browserContexts) { + if ([[browserContext dataStore] sessionID] != sessionID) + continue; + [_browserContexts removeObject:browserContext]; + return; + } +} + +- (void)quit +{ + [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(); + [_dialogs removeObject:dialog]; + }; + [_dialogs addObject:dialog]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(accept); + [_dialogs removeObject:dialog]; + }; + [_dialogs addObject:dialog]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(accept && value ? value : nil); + [_dialogs removeObject:dialog]; + }; + [_dialogs addObject:dialog]; +} + +- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(NSString *)value +{ + for (WebViewDialog *dialog in _dialogs) { + if (dialog.webView != webView) + continue; + dialog.completionHandler(accept, value); + break; + } +} + @end diff --git a/Tools/MiniBrowser/mac/SettingsController.m b/Tools/MiniBrowser/mac/SettingsController.m index 4a3a65505cd..2e48e0a52bb 100644 --- a/Tools/MiniBrowser/mac/SettingsController.m +++ b/Tools/MiniBrowser/mac/SettingsController.m @@ -31,7 +31,7 @@ #import #import -static NSString * const defaultURL = @"http://www.webkit.org/"; +static NSString * const defaultURL = @"about:blank"; static NSString * const DefaultURLPreferenceKey = @"DefaultURL"; static NSString * const UseWebKit2ByDefaultPreferenceKey = @"UseWebKit2ByDefault"; diff --git a/Tools/MiniBrowser/mac/WK2BrowserWindowController.h b/Tools/MiniBrowser/mac/WK2BrowserWindowController.h index 6f0949b0f4a..e774433031a 100644 --- a/Tools/MiniBrowser/mac/WK2BrowserWindowController.h +++ b/Tools/MiniBrowser/mac/WK2BrowserWindowController.h @@ -25,8 +25,11 @@ #import "BrowserWindowController.h" +@class WKWebView; + @interface WK2BrowserWindowController : BrowserWindowController - (instancetype)initWithConfiguration:(WKWebViewConfiguration *)configuration; +- (WKWebView *)webView; @end diff --git a/Tools/MiniBrowser/mac/WK2BrowserWindowController.m b/Tools/MiniBrowser/mac/WK2BrowserWindowController.m index 0063266ed33..7d6b8d6f05f 100644 --- a/Tools/MiniBrowser/mac/WK2BrowserWindowController.m +++ b/Tools/MiniBrowser/mac/WK2BrowserWindowController.m @@ -72,6 +72,7 @@ @implementation WK2BrowserWindowController { WKWebView *_webView; BOOL _zoomTextOnly; BOOL _isPrivateBrowsingWindow; + NSAlert* _alert; BOOL _useShrinkToFit; @@ -105,7 +106,7 @@ - (void)awakeFromNib // telling WebKit to load every icon referenced by the page. if ([[SettingsController shared] loadsAllSiteIcons]) _webView._iconLoadingDelegate = self; - + _webView._observedRenderingProgressEvents = _WKRenderingProgressEventFirstLayout | _WKRenderingProgressEventFirstVisuallyNonEmptyLayout | _WKRenderingProgressEventFirstPaintWithSignificantArea @@ -113,6 +114,7 @@ - (void)awakeFromNib | _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering; _zoomTextOnly = NO; + _alert = nil; _webView._usePlatformFindUI = NO; @@ -139,14 +141,10 @@ - (instancetype)initWithConfiguration:(WKWebViewConfiguration *)configuration - (void)dealloc { - [_webView removeObserver:self forKeyPath:@"title"]; - [_webView removeObserver:self forKeyPath:@"URL"]; - [progressIndicator unbind:NSHiddenBinding]; [progressIndicator unbind:NSValueBinding]; [_textFinder release]; - [_webView release]; [_configuration release]; @@ -372,9 +370,15 @@ - (BOOL)windowShouldClose:(id)sender - (void)windowWillClose:(NSNotification *)notification { [(BrowserAppDelegate *)[[NSApplication sharedApplication] delegate] browserWindowWillClose:self.window]; + [_webView removeObserver:self forKeyPath:@"title"]; + [_webView removeObserver:self forKeyPath:@"URL"]; [self autorelease]; } +- (void)webViewDidClose:(WKWebView *)webView { + [self.window close]; +} + #define DefaultMinimumZoomFactor (.5) #define DefaultMaximumZoomFactor (3.0) #define DefaultZoomFactorRatio (1.2) @@ -512,9 +516,11 @@ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSStrin [alert setInformativeText:message]; [alert addButtonWithTitle:@"OK"]; + _alert = alert; [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { completionHandler(); [alert release]; + _alert = nil; }]; } @@ -528,9 +534,11 @@ - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSStr [alert addButtonWithTitle:@"OK"]; [alert addButtonWithTitle:@"Cancel"]; + _alert = alert; [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { completionHandler(response == NSAlertFirstButtonReturn); [alert release]; + _alert = nil; }]; } @@ -548,13 +556,25 @@ - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSSt [input setStringValue:defaultText]; [alert setAccessoryView:input]; + _alert = alert; [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { [input validateEditing]; completionHandler(response == NSAlertFirstButtonReturn ? [input stringValue] : nil); [alert release]; + _alert = nil; }]; } +- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(NSString *)value +{ + if (!_alert) + return; + NSTextField* input = (NSTextField*)_alert.accessoryView; + if (accept && input && value) + [input setStringValue:value]; + [self.window endSheet:_alert.window returnCode: accept ? NSAlertFirstButtonReturn : NSModalResponseCancel]; +} + #if __has_feature(objc_generics) - (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray * URLs))completionHandler #else @@ -848,4 +868,9 @@ - (IBAction)saveAsWebArchive:(id)sender }]; } +- (WKWebView *)webView +{ + return _webView; +} + @end diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp index 2d183d39412..d94d4f06fc5 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp @@ -172,6 +172,41 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi return newWebView; } +static WebKitWebView *createNewPage(WebKitBrowserInspector*, WebKitWebContext *context) +{ + auto backend = createViewBackend(1280, 720); + struct wpe_view_backend* wpeBackend = backend->backend(); + if (!wpeBackend) + return nullptr; + + auto* viewBackend = webkit_web_view_backend_new(wpeBackend, + [](gpointer data) { + delete static_cast(data); + }, backend.release()); + + auto* newWebView = webkit_web_view_new_with_context(viewBackend, context); + + g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), nullptr); + + webkit_web_view_load_uri(newWebView, "about:blank"); + + return newWebView; + +} + +static void closeAll(WebKitBrowserInspector*, GMainLoop* mainLoop) +{ + g_main_loop_quit(mainLoop); +} + +static void configureBrowserInspector(GMainLoop* mainLoop, WebKitWebView *firstWebView) +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + // FIXME: This signal is received only when closeAll is called. We should not rely on that. + g_signal_connect(firstWebView, "close", G_CALLBACK(closeAll), mainLoop); +} + int main(int argc, char *argv[]) { #if ENABLE_DEVELOPER_MODE @@ -301,6 +336,8 @@ int main(int argc, char *argv[]) g_signal_connect(webView, "permission-request", G_CALLBACK(decidePermissionRequest), nullptr); g_signal_connect(webView, "create", G_CALLBACK(createWebView), nullptr); + configureBrowserInspector(loop, webView); + if (ignoreTLSErrors) webkit_web_context_set_tls_errors_policy(webContext, WEBKIT_TLS_ERRORS_POLICY_IGNORE); -- 2.22.1