diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index c257f6a5a523ce12f67857e0d344aadffea6601a..f8c46e22eb4fa79c6b9f56846828391c3bf4de21 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -1615,21 +1615,26 @@ set(JavaScriptCore_INSPECTOR_DOMAINS ${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/Debugger.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Emulation.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/GenericTypes.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Heap.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/IndexedDB.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Input.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Inspector.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/LayerTree.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Memory.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Network.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Page.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Playwright.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Recording.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Runtime.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/ScriptProfiler.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Screencast.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Security.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/ServiceWorker.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Target.json diff --git a/Source/JavaScriptCore/DerivedSources-input.xcfilelist b/Source/JavaScriptCore/DerivedSources-input.xcfilelist index 55eacb0d378fddea15ece56db612655ac5d64061..cb6cfa7c542e82671f68984ff9373e1bf58da2b8 100644 --- a/Source/JavaScriptCore/DerivedSources-input.xcfilelist +++ b/Source/JavaScriptCore/DerivedSources-input.xcfilelist @@ -101,20 +101,25 @@ $(PROJECT_DIR)/inspector/protocol/CPUProfiler.json $(PROJECT_DIR)/inspector/protocol/CSS.json $(PROJECT_DIR)/inspector/protocol/Canvas.json $(PROJECT_DIR)/inspector/protocol/Console.json +$(PROJECT_DIR)/inspector/protocol/Dialog.json $(PROJECT_DIR)/inspector/protocol/DOM.json $(PROJECT_DIR)/inspector/protocol/DOMDebugger.json $(PROJECT_DIR)/inspector/protocol/DOMStorage.json $(PROJECT_DIR)/inspector/protocol/Debugger.json +$(PROJECT_DIR)/inspector/protocol/Emulation.json $(PROJECT_DIR)/inspector/protocol/GenericTypes.json $(PROJECT_DIR)/inspector/protocol/Heap.json $(PROJECT_DIR)/inspector/protocol/IndexedDB.json +$(PROJECT_DIR)/inspector/protocol/Input.json $(PROJECT_DIR)/inspector/protocol/Inspector.json $(PROJECT_DIR)/inspector/protocol/LayerTree.json $(PROJECT_DIR)/inspector/protocol/Memory.json $(PROJECT_DIR)/inspector/protocol/Network.json $(PROJECT_DIR)/inspector/protocol/Page.json +$(PROJECT_DIR)/inspector/protocol/Playwright.json $(PROJECT_DIR)/inspector/protocol/Recording.json $(PROJECT_DIR)/inspector/protocol/Runtime.json +$(PROJECT_DIR)/inspector/protocol/Screencast.json $(PROJECT_DIR)/inspector/protocol/ScriptProfiler.json $(PROJECT_DIR)/inspector/protocol/Security.json $(PROJECT_DIR)/inspector/protocol/ServiceWorker.json diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make index 7eb4f1c1e0cd3abdf61203d33cd2f53d77d4264d..01adf210b42055612dc02aba0ed52e6f6ed1d10f 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make @@ -298,21 +298,26 @@ INSPECTOR_DOMAINS := \ $(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/Debugger.json \ + $(JavaScriptCore)/inspector/protocol/Emulation.json \ $(JavaScriptCore)/inspector/protocol/GenericTypes.json \ $(JavaScriptCore)/inspector/protocol/Heap.json \ $(JavaScriptCore)/inspector/protocol/IndexedDB.json \ + $(JavaScriptCore)/inspector/protocol/Input.json \ $(JavaScriptCore)/inspector/protocol/Inspector.json \ $(JavaScriptCore)/inspector/protocol/LayerTree.json \ $(JavaScriptCore)/inspector/protocol/Memory.json \ $(JavaScriptCore)/inspector/protocol/Network.json \ $(JavaScriptCore)/inspector/protocol/Page.json \ + $(JavaScriptCore)/inspector/protocol/Playwright.json \ $(JavaScriptCore)/inspector/protocol/Recording.json \ $(JavaScriptCore)/inspector/protocol/Runtime.json \ $(JavaScriptCore)/inspector/protocol/ScriptProfiler.json \ + $(JavaScriptCore)/inspector/protocol/Screencast.json \ $(JavaScriptCore)/inspector/protocol/Security.json \ $(JavaScriptCore)/inspector/protocol/ServiceWorker.json \ $(JavaScriptCore)/inspector/protocol/Target.json \ diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp index 9bc5d1fd8e2a7e576be046b3c6ae1266696cf552..610f810db1dd6865c500c0796386a8284f4178e9 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp @@ -32,14 +32,21 @@ namespace Inspector { namespace { +static uint64_t s_processID = 0; static unsigned long s_lastUsedIdentifier = 0; } static String addPrefixToIdentifier(unsigned long identifier) { - return makeString("0."_s, identifier); + return makeString(s_processID, '.', identifier); } +void IdentifiersFactory::initializeWithProcessID(uint64_t processID) { + ASSERT(!s_processID); + s_processID = processID; +} + + String IdentifiersFactory::createIdentifier() { return addPrefixToIdentifier(++s_lastUsedIdentifier); diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.h b/Source/JavaScriptCore/inspector/IdentifiersFactory.h index e145f18eff043f6d718f38d14159415327a0b43b..747c06864110ef4488d8e4b0f6fd74a1d9badadd 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.h +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.h @@ -32,6 +32,7 @@ namespace Inspector { class IdentifiersFactory { public: + JS_EXPORT_PRIVATE static void initializeWithProcessID(uint64_t); JS_EXPORT_PRIVATE static String createIdentifier(); JS_EXPORT_PRIVATE static String requestId(unsigned long identifier); }; diff --git a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp index 4d9152423abf35dfbdf338435b567a822b2f6904..4e6b551494e1d124655c8cc54f121ac4843c3298 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp @@ -85,7 +85,10 @@ static RefPtr jsToInspectorValue(JSC::JSGlobalObject* globalObject, JSC::PropertyNameArrayBuilder propertyNames(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude); object.methodTable()->getOwnPropertyNames(&object, globalObject, propertyNames, JSC::DontEnumPropertiesMode::Exclude); for (auto& name : propertyNames) { - auto inspectorValue = jsToInspectorValue(globalObject, object.get(globalObject, name), maxDepth); + JSC::JSValue childValue = object.get(globalObject, name); + if (childValue.isUndefined()) + continue; + auto inspectorValue = jsToInspectorValue(globalObject, childValue, maxDepth); if (!inspectorValue) return nullptr; inspectorObject->setValue(name.string(), inspectorValue.releaseNonNull()); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp index 449ff9c805107a41f783eaf72b9901d0df6a3e72..a56a086892caa03e171616bd90db8cbf94905b0d 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp @@ -103,7 +103,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple m_dispatchers.set(domain, dispatcher); } -void BackendDispatcher::dispatch(const String& message) +void BackendDispatcher::dispatch(const String& message, Interceptor&& interceptor) { Ref protect(*this); @@ -148,6 +148,9 @@ void BackendDispatcher::dispatch(const String& message) requestId = *requestIdInt; } + if (interceptor && interceptor(messageObject) == InterceptionResult::Intercepted) + return; + { // We could be called re-entrantly from a nested run loop, so restore the previous id. SetForScope scopedRequestId(m_currentRequestId, requestId); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h index ed0cb419967759a258d3d250fd42d2b86ca32561..0788de297278f875d18dd9da22df53a72f34d52b 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h @@ -97,8 +97,11 @@ public: ServerError }; + enum class InterceptionResult { Intercepted, Continue }; + using Interceptor = WTF::Function&)>; + JS_EXPORT_PRIVATE void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); - JS_EXPORT_PRIVATE void dispatch(const String& message); + JS_EXPORT_PRIVATE void dispatch(const String& message, Interceptor&& interceptor = Interceptor()); // 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/InspectorFrontendRouter.cpp b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp index 13207d2da597e3b96cc9e83d0bee83fa859cdcf0..c4f9f4714578652cb71f106bb0bfdb69440ed238 100644 --- a/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp +++ b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp @@ -52,7 +52,7 @@ void FrontendRouter::connectFrontend(FrontendChannel& connection) void FrontendRouter::disconnectFrontend(FrontendChannel& connection) { if (!m_connections.contains(&connection)) { - ASSERT_NOT_REACHED(); + ASSERT(m_connections.isEmpty()); return; } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.cpp b/Source/JavaScriptCore/inspector/InspectorTarget.cpp index b68a7eb5e8d26ea7631b451f629734c886896684..92dba414b7e9c3587ae40c4cb7bb6e4f10895a70 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.cpp +++ b/Source/JavaScriptCore/inspector/InspectorTarget.cpp @@ -48,6 +48,8 @@ void InspectorTarget::resume() ASSERT(m_isPaused); m_isPaused = false; + willResume(); + if (m_resumeCallback) { m_resumeCallback(); m_resumeCallback = nullptr; @@ -56,7 +58,6 @@ void InspectorTarget::resume() void InspectorTarget::setResumeCallback(WTF::Function&& callback) { - ASSERT(!m_resumeCallback); m_resumeCallback = WTF::move(callback); } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h index 421d62c0071a43b7fb111a4e2b120e28c5ba96af..de764f8519c3df6a9325d3eb87e7fe907c5b5b6a 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.h +++ b/Source/JavaScriptCore/inspector/InspectorTarget.h @@ -61,8 +61,12 @@ 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"_s; } + virtual void close(String& error, bool /* runBeforeUnload */) { error = "Target cannot be closed"_s; } private: + virtual void willResume() { } + WTF::Function m_resumeCallback; bool m_isPaused { false }; }; diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp index ddd58da62382291979c72d62700c61c137f5b965..ab114ba249ec6901c78da7703b5e8140d7cebcca 100644 --- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp +++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp @@ -232,6 +232,14 @@ void JSGlobalObjectConsoleClient::screenshot(JSGlobalObject*, RefdeveloperExtrasEnabled()) + return; + + warnUnimplemented("console.bindingCalled"_s); +} + void JSGlobalObjectConsoleClient::warnUnimplemented(const String& method) { auto message = makeString(method, " is currently ignored in JavaScript context inspection."_s); diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h index ed7dbb3ee1de5183f1c1868310b332f52d2e8cd6..90dd8331ba5cf87a32407a01cfe9d218b4822f1c 100644 --- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h +++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h @@ -68,6 +68,7 @@ private: void record(JSC::JSGlobalObject*, Ref&&) final; void recordEnd(JSC::JSGlobalObject*, Ref&&) final; void screenshot(JSC::JSGlobalObject*, Ref&&) final; + void bindingCalled(JSC::JSGlobalObject*, const String&, const String&) final; void warnUnimplemented(const String& method); void internalAddMessage(MessageType, MessageLevel, JSC::JSGlobalObject*, Ref&&); diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp index bd5258cf60b70750c52277007f657fbfaeaeec68..8ad812f65d8f2f6112d2456789a82520e215633b 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp @@ -219,6 +219,11 @@ void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const unmuteConsole(); } +Protocol::ErrorStringOr InspectorRuntimeAgent::addBinding(const String&) +{ + return makeUnexpected("Not implemented in this type of agent."_s); +} + Protocol::ErrorStringOr> InspectorRuntimeAgent::getPreview(const Protocol::Runtime::RemoteObjectId& objectId) { Protocol::ErrorString errorString; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h index f7ed41f0b3aaa9bb0eb388c4edbef2645e9b1dd4..511ff1799f7480c85fb46beda36fb52f3d489099 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h @@ -65,6 +65,7 @@ public: Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture) override; void awaitPromise(const Protocol::Runtime::RemoteObjectId&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, Ref&&) final; void callFunctionOn(const Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture, std::optional&& awaitPromise, Ref&&) override; + Protocol::ErrorStringOr addBinding(const String& name) override; Protocol::ErrorStringOr releaseObject(const Protocol::Runtime::RemoteObjectId&) final; Protocol::ErrorStringOr> getPreview(const Protocol::Runtime::RemoteObjectId&) final; Protocol::ErrorStringOr>, RefPtr>>> getProperties(const Protocol::Runtime::RemoteObjectId&, std::optional&& ownProperties, std::optional&& fetchStart, std::optional&& fetchCount, std::optional&& generatePreview) final; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp index 38d8aa7a256deab40470631c8f2231d9d34613e1..6c7f776c0b7f2ab7a1a3870ebaa42a3da5ad794c 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp @@ -90,6 +90,34 @@ Protocol::ErrorStringOr InspectorTargetAgent::sendMessageToTarget(const St return { }; } +Protocol::ErrorStringOr InspectorTargetAgent::activate(const String& targetId) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) + return makeUnexpected("Missing target for given targetId"_s); + + String errorString; + target->activate(errorString); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + return { }; +} + +Protocol::ErrorStringOr InspectorTargetAgent::close(const String& targetId, std::optional&& runBeforeUnload) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) + return makeUnexpected("Missing target for given targetId"_s); + + String errorString; + target->close(errorString, runBeforeUnload && *runBeforeUnload); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + return { }; +} + void InspectorTargetAgent::sendMessageFromTargetToFrontend(const String& targetId, const String& message) { m_frontendDispatcher->dispatchMessageFromTarget(targetId, message); @@ -147,7 +175,17 @@ void InspectorTargetAgent::targetDestroyed(InspectorTarget& target) if (!m_isConnected) return; - m_frontendDispatcher->targetDestroyed(target.identifier()); + m_frontendDispatcher->targetDestroyed(target.identifier(), false); +} + +void InspectorTargetAgent::targetCrashed(InspectorTarget& target) +{ + m_targets.remove(target.identifier()); + + if (!m_isConnected) + return; + + m_frontendDispatcher->targetDestroyed(target.identifier(), true); } void InspectorTargetAgent::didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID) diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h index 0b7d732f036fce96b01bd06f4c47f5d471a0ab38..a9efea4bec66aa68966c99d9e77f8a36f7f7205a 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h @@ -53,8 +53,11 @@ public: Protocol::ErrorStringOr setPauseOnStart(bool) final; Protocol::ErrorStringOr resume(const String& targetId) final; Protocol::ErrorStringOr sendMessageToTarget(const String& targetId, const String& message) final; + Protocol::ErrorStringOr activate(const String& targetId) override; + Protocol::ErrorStringOr close(const String& targetId, std::optional&& runBeforeUnload) override; // Target lifecycle. + void targetCrashed(InspectorTarget&); void targetCreated(InspectorTarget&); void targetDestroyed(InspectorTarget&); void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID); @@ -62,6 +65,9 @@ public: // Target messages. void sendMessageFromTargetToFrontend(const String& targetId, const String& message); + bool shouldPauseOnStart() const { return m_shouldPauseOnStart; } + bool isConnected() { return m_isConnected; } + private: // FrontendChannel FrontendChannel::ConnectionType connectionType() const; diff --git a/Source/JavaScriptCore/inspector/protocol/DOM.json b/Source/JavaScriptCore/inspector/protocol/DOM.json index 0b41f31605a2407fd068e28eaec60dbeabefd4d8..80fc7f1351949447c1f988641a26bcf695d589f2 100644 --- a/Source/JavaScriptCore/inspector/protocol/DOM.json +++ b/Source/JavaScriptCore/inspector/protocol/DOM.json @@ -80,6 +80,16 @@ { "name": "value", "type": "string", "description": "The value that is resolved to with this data binding relationship." } ] }, + { + "id": "Rect", + "type": "object", + "properties": [ + { "name": "x", "type": "integer", "description": "X coordinate" }, + { "name": "y", "type": "integer", "description": "Y coordinate" }, + { "name": "width", "type": "integer", "description": "Rectangle width" }, + { "name": "height", "type": "integer", "description": "Rectangle height" } + ] + }, { "id": "EventListener", "type": "object", @@ -740,7 +750,10 @@ "description": "Resolves JavaScript node object for given node id.", "targetTypes": ["page"], "parameters": [ - { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to resolve." }, + { "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Id of the node to resolve." }, + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "Source element handle." }, + { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to resolve the owner element." }, + { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "optional": true, "description": "Specifies in which execution context to adopt to." }, { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." } ], "returns": [ @@ -817,6 +830,46 @@ "returns": [ { "name": "mediaStats", "$ref": "MediaStats", "description": "An interleaved array of node attribute names and values." } ] + }, + { + "name": "describeNode", + "description": "Returns node description.", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id of the node wrapper." } + ], + "returns": [ + { "name": "contentFrameId", "$ref": "Network.FrameId", "optional": true, "description": "Frame ID for frame owner elements." }, + { "name": "ownerFrameId", "$ref": "Network.FrameId", "optional": true, "description": "ID of the owning frame element." } + ] + }, + { + "name": "scrollIntoViewIfNeeded", + "description": "Scrolls the given rect into view if not already in the viewport.", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id of the node wrapper." }, + { "name": "rect", "$ref": "Rect", "optional": true, "description": "Rect relative to the node's border box, in CSS pixels." } + ] + }, + { + "name": "getContentQuads", + "description": "Returns quads that describe node position on the page. This method\nmight return multiple quads for inline nodes.", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id of the node wrapper." } + ], + "returns": [ + { + "name": "quads", "type": "array", "items": { "$ref": "Quad" }, "description": "Quads that describe node layout relative to viewport." + } + ] + }, + { + "name": "setInputFiles", + "description": "Sets input files for given ", + "parameters": [ + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Input element handle." }, + { "name": "paths", "type": "array", "items": { "type": "string" }, "description": "File paths to set" } + ], + "async": true } ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Dialog.json b/Source/JavaScriptCore/inspector/protocol/Dialog.json new file mode 100644 index 0000000000000000000000000000000000000000..79edea03fed4e9be5da96e1275e182a479cb7a0a --- /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 0000000000000000000000000000000000000000..8377901cb3ad75c29532a1f0f547efb53558a327 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Emulation.json @@ -0,0 +1,59 @@ +{ + "domain": "Emulation", + "availability": ["web"], + "commands": [ + { + "name": "setDeviceMetricsOverride", + "description": "Overrides device metrics with provided values.", + "async": true, + "parameters": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" }, + { "name": "fixedLayout", "type": "boolean" }, + { "name": "deviceScaleFactor", "type": "number", "optional": true } + ] + }, + { + "name": "setJavaScriptEnabled", + "description": "Allows to disable script execution for the page.", + "parameters": [ + { "name": "enabled", "type": "boolean" } + ] + }, + { + "name": "setAuthCredentials", + "description": "Credentials to use during HTTP authentication.", + "parameters": [ + { "name": "username", "type": "string", "optional": true }, + { "name": "password", "type": "string", "optional": true }, + { "name": "origin", "type": "string", "optional": true } + ] + }, + { + "name": "setActiveAndFocused", + "description": "Makes page focused for test.", + "parameters": [ + { "name": "active", "type": "boolean", "optional": true } + ] + }, + { + "name": "grantPermissions", + "parameters": [ + { "name": "origin", "type": "string" }, + { "name": "permissions", "type": "array", "items": { "type": "string" } } + ], + "description": "Overrides the permissions." + }, + { + "name": "resetPermissions", + "description": "Clears permission overrides." + }, + { + "name": "setOrientationOverride", + "description": "Overrides window.orientation with provided value.", + "parameters": [ + { "name": "angle", "type": "integer", "optional": true } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Input.json b/Source/JavaScriptCore/inspector/protocol/Input.json new file mode 100644 index 0000000000000000000000000000000000000000..1c43b476603325fa412bcfded9163e7a00aebbfa --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Input.json @@ -0,0 +1,264 @@ +{ + "domain": "Input", + "availability": ["web"], + "types": [ + { + "id": "TimeSinceEpoch", + "description": "UTC time in seconds, counted from January 1, 1970.", + "type": "number" + }, + { + "id": "TouchPoint", + "type": "object", + "description": "Touch point.", + "properties": [ + { "name": "x", "type": "integer", "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels." }, + { "name": "y", "type": "integer", "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels." }, + { "name": "id", "type": "integer", "description": "Identifier used to track touch sources between events, must be unique within an event." } + ] + } + ], + "commands": [ + { + "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": "macCommands", + "description": "Mac editing commands associated with this key", + "type": "array", + "optional": true, + "items": { + "type": "string" + } + } + ] + }, + { + "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" + } + ] + }, + { + "name": "dispatchWheelEvent", + "description": "Dispatches a wheel event to the page.", + "async": true, + "parameters": [ + { + "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": "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" + } + ] + }, + { + "name": "dispatchTapEvent", + "description": "Dispatches a tap event to the page.", + "async": true, + "parameters": [ + { + "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": "dispatchTouchEvent", + "description": "Dispatches a touch event to the page.", + "async": true, + "parameters": [ + { + "name": "type", + "description": "Type of the touch event.", + "type": "string", + "enum": [ + "touchStart", + "touchMove", + "touchEnd", + "touchCancel" + ] + }, + { + "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": "touchPoints", + "description": "List of touch points", + "type": "array", + "optional": true, + "items": { "$ref": "TouchPoint" } + } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Network.json b/Source/JavaScriptCore/inspector/protocol/Network.json index 29a3ef3294dcdf9e9559b665e9f1bb9a5727cf4b..b6b90f356dd6b7de7752ab4296069c8f07b4de38 100644 --- a/Source/JavaScriptCore/inspector/protocol/Network.json +++ b/Source/JavaScriptCore/inspector/protocol/Network.json @@ -360,6 +360,13 @@ "parameters": [ { "name": "bytesPerSecondLimit", "type": "integer", "optional": true, "description": "Limits the bytes per second of requests if positive. Removes any limits if zero or not provided." } ] + }, + { + "name": "setEmulateOfflineState", + "description": "Emulate offline state overriding the actual state.", + "parameters": [ + { "name": "offline", "type": "boolean", "description": "True to emulate offline." } + ] } ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json index 374b26c3ee9acf39aeb23fb60821b39d0afd971c..8843241e3e669c2d7537adb11e83325f216febba 100644 --- a/Source/JavaScriptCore/inspector/protocol/Page.json +++ b/Source/JavaScriptCore/inspector/protocol/Page.json @@ -20,7 +20,15 @@ "ScriptEnabled", "ShowDebugBorders", "ShowRepaintCounter", - "WebSecurityEnabled" + "WebSecurityEnabled", + "DeviceOrientationEventEnabled", + "SpeechRecognitionEnabled", + "PointerLockEnabled", + "NotificationsEnabled", + "FullScreenEnabled", + "InputTypeMonthEnabled", + "InputTypeWeekEnabled", + "FixedBackgroundsPaintRelativeToDocument" ] }, { @@ -62,6 +70,12 @@ "enum": ["None", "Lax", "Strict"], "description": "Same-Site policy of a cookie." }, + { + "id": "ForcedColors", + "type": "string", + "enum": ["Active", "None"], + "description": "Page forced-colors media query override." + }, { "id": "Frame", "type": "object", @@ -126,6 +140,16 @@ { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." }, { "name": "partitionKey", "type": "string", "optional": true, "description": "Cookie partition key. If null and partitioned property is true, then key must be computed." } ] + }, + { + "id": "Insets", + "type": "object", + "properties": [ + { "name": "top", "type": "number" }, + { "name": "right", "type": "number" }, + { "name": "bottom", "type": "number" }, + { "name": "left", "type": "number" } + ] } ], "commands": [ @@ -145,6 +169,14 @@ { "name": "revalidateAllResources", "type": "boolean", "optional": true, "description": "If true, all cached subresources will be revalidated when the main resource loads. Otherwise, only expired cached subresources will be revalidated (the default behavior for most WebKit clients)." } ] }, + { + "name": "goBack", + "description": "Goes back in the history." + }, + { + "name": "goForward", + "description": "Goes forward in the history." + }, { "name": "overrideUserAgent", "description": "Override's the user agent of the inspected page", @@ -153,6 +185,14 @@ { "name": "value", "type": "string", "optional": true, "description": "Value to override the user agent with. If this value is not provided, the override is removed. Overrides are removed when Web Inspector closes/disconnects." } ] }, + { + "name": "overridePlatform", + "description": "Override's the navigator.platform of the inspected page", + "targetTypes": ["page"], + "parameters": [ + { "name": "value", "type": "string", "optional": true, "description": "Value to override the platform with. If this value is not provided, the override is removed. Overrides are removed when Web Inspector closes/disconnects." } + ] + }, { "name": "overrideSetting", "description": "Allows the frontend to override the inspected page's settings.", @@ -277,6 +317,28 @@ { "name": "media", "type": "string", "description": "Media type to emulate. Empty string disables the override." } ] }, + { + "name": "setForcedColors", + "description": "Forces the forced-colors media query for the page.", + "targetTypes": ["page"], + "parameters": [ + { "name": "forcedColors", "$ref": "ForcedColors", "optional": true } + ] + }, + { + "name": "setTimeZone", + "description": "Enables time zone emulation.", + "parameters": [ + { "name": "timeZone", "type": "string", "optional": true } + ] + }, + { + "name": "setTouchEmulationEnabled", + "description": "Enables touch events on platforms that lack them.", + "parameters": [ + {"name": "enabled", "type": "boolean", "description": "Whether touch should be enabled."} + ] + }, { "name": "snapshotNode", "description": "Capture a snapshot of the specified node that does not include unrelated layers.", @@ -297,7 +359,8 @@ { "name": "y", "type": "integer", "description": "Y coordinate" }, { "name": "width", "type": "integer", "description": "Rectangle width" }, { "name": "height", "type": "integer", "description": "Rectangle height" }, - { "name": "coordinateSystem", "$ref": "CoordinateSystem", "description": "Indicates the coordinate system of the supplied rectangle." } + { "name": "coordinateSystem", "$ref": "CoordinateSystem", "description": "Indicates the coordinate system of the supplied rectangle." }, + { "name": "omitDeviceScaleFactor", "type": "boolean", "optional": true, "description": "By default, screenshot is inflated by device scale factor to avoid blurry image. This flag disables it." } ], "returns": [ { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } @@ -315,12 +378,54 @@ { "name": "setScreenSizeOverride", "description": "Overrides screen size exposed to DOM and used in media queries for testing with provided values.", - "condition": "!(defined(WTF_PLATFORM_COCOA) && WTF_PLATFORM_COCOA)", "targetTypes": ["page"], "parameters": [ { "name": "width", "type": "integer", "description": "Screen width", "optional": true }, { "name": "height", "type": "integer", "description": "Screen height", "optional": true } ] + }, + { + "name": "insertText", + "description": "Insert text into the current selection of the page.", + "parameters": [ + { "name": "text", "type": "string", "description": "Text to insert." } + ] + }, + { + "name": "setInterceptFileChooserDialog", + "description": "Intercepts file chooser dialog", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "True to enable." } + ] + }, + { + "name": "setDefaultBackgroundColorOverride", + "description": "Sets or clears an override of the default background color of the frame. This override is used if the content does not specify one.", + "parameters": [ + { "name": "color", "$ref": "DOM.RGBAColor", "optional": true, "description": "RGBA of the default background color. If not specified, any existing override will be cleared." } + ] + }, + { + "name": "createUserWorld", + "description": "Creates an user world for every loaded frame.", + "parameters": [ + { "name": "name", "type": "string", "description": "Isolated world name, will be used as an execution context name." } + ] + }, + { + "name": "setBypassCSP", + "description": "Enable page Content Security Policy by-passing.", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "Whether to bypass page CSP." } + ] + }, + { + "name": "crash", + "description": "Crashes the page process" + }, + { + "name": "updateScrollingState", + "description": "Ensures that the scroll regions are up to date." } ], "events": [ @@ -328,14 +433,16 @@ "name": "domContentEventFired", "targetTypes": ["page"], "parameters": [ - { "name": "timestamp", "type": "number" } + { "name": "timestamp", "type": "number" }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has fired DOMContentLoaded event." } ] }, { "name": "loadEventFired", "targetTypes": ["page"], "parameters": [ - { "name": "timestamp", "type": "number" } + { "name": "timestamp", "type": "number" }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has fired load event." } ] }, { @@ -345,6 +452,14 @@ { "name": "frame", "$ref": "Frame", "description": "Frame object." } ] }, + { + "name": "frameAttached", + "description": "Fired when frame has been attached to its parent.", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has been detached." }, + { "name": "parentFrameId", "$ref": "Network.FrameId", "optional": true, "description": "Parent frame id if non-root." } + ] + }, { "name": "frameDetached", "description": "Fired when frame has been detached from its parent.", @@ -353,6 +468,22 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has been detached." } ] }, + { + "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": "defaultUserPreferencesDidChange", "description": "Fired when the default value of a user preference changes at the system level.", @@ -360,6 +491,42 @@ "parameters": [ { "name": "preferences", "type": "array", "items": { "$ref": "UserPreference" }, "description": "List of user preferences that can be overriden and their new system (default) values." } ] + }, + { + "name": "willCheckNavigationPolicy", + "description": "Fired when page is about to check policy for newly triggered navigation.", + "parameters": [ + { + "name": "frameId", + "description": "Id of the frame.", + "$ref": "Network.FrameId" + } + ] + }, + { + "name": "didCheckNavigationPolicy", + "description": "Fired when page has received navigation policy decision.", + "parameters": [ + { + "name": "frameId", + "description": "Id of the frame.", + "$ref": "Network.FrameId" + }, + { + "name": "cancel", + "description": "True if the navigation will not continue in this frame.", + "type": "boolean", + "optional": true + } + ] + }, + { + "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/Playwright.json b/Source/JavaScriptCore/inspector/protocol/Playwright.json new file mode 100644 index 0000000000000000000000000000000000000000..ade3e257b614f210ba5dcc024df81642425f8d51 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Playwright.json @@ -0,0 +1,310 @@ +{ + "domain": "Playwright", + "availability": ["web"], + "types": [ + { + "id": "ContextID", + "type": "string", + "description": "Id of Browser context." + }, + { + "id": "PageProxyID", + "type": "string", + "description": "Id of WebPageProxy." + }, + { + "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." } + ] + }, + { + "id": "NameValue", + "type": "object", + "description": "Name-value pair", + "properties": [ + { "name": "name", "type": "string" }, + { "name": "value", "type": "string" } + ] + }, + { + "id": "OriginStorage", + "type": "object", + "description": "Origin object", + "properties": [ + { "name": "origin", "type": "string", "description": "Origin." }, + { "name": "items", "type": "array", "items": { "$ref": "NameValue" }, "description": "Storage entries." } + ] + }, + { + "id": "Geolocation", + "type": "object", + "description": "Geolocation", + "properties": [ + { "name": "timestamp", "type": "number", "description": "Mock latitude" }, + { "name": "latitude", "type": "number", "description": "Mock latitude" }, + { "name": "longitude", "type": "number", "description": "Mock longitude" }, + { "name": "accuracy", "type": "number", "description": "Mock accuracy" } + ] + } + ], + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "getInfo", + "returns": [ + { "name": "os", "type": "string", "description": "Name of the operating system where the browser is running (macOS, Linux or Windows)." } + ] + }, + { + "name": "close", + "async": true, + "description": "Close browser." + }, + { + "name": "createContext", + "description": "Creates new ephemeral browser context.", + "parameters": [ + { "name": "proxyServer", "type": "string", "optional": true, "description": "Proxy server, similar to the one passed to --proxy-server" }, + { "name": "proxyBypassList", "type": "string", "optional": true, "description": "Proxy bypass list, similar to the one passed to --proxy-bypass-list" }, + { "name": "enableStoragePartitioning", "type": "boolean", "optional": true, "description": "Wether to use storage partitioning. Be default Playwright disables the partitioning." } + ], + "returns": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." } + ] + }, + { + "name": "deleteContext", + "async": true, + "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": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." } + ] + }, + { + "name": "navigate", + "async": true, + "description": "Navigates current page to the given URL.", + "parameters": [ + { "name": "url", "type": "string", "description": "URL to navigate the page to." }, + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to navigate."}, + { "name": "referrer", "type": "string", "optional": true, "description": "Referrer URL." } + ], + "returns": [ + { "name": "loaderId", "$ref": "Network.LoaderId", "optional": true, "description": "Identifier of the loader associated with the navigation." } + ] + }, + { + "name": "grantFileReadAccess", + "description": "Grants read access for the specified files to the web process of the page.", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "paths", "type": "array", "items": { "type": "string" }, "description": "Id of the frame to navigate."} + ] + }, + { + "name": "takePageScreenshot", + "description": "Capture a snapshot of the page.", + "async": true, + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "x", "type": "integer", "description": "X coordinate" }, + { "name": "y", "type": "integer", "description": "Y coordinate" }, + { "name": "width", "type": "integer", "description": "Rectangle width" }, + { "name": "height", "type": "integer", "description": "Rectangle height" }, + { "name": "omitDeviceScaleFactor", "type": "boolean", "optional": true, "description": "By default, screenshot is inflated by device scale factor to avoid blurry image. This flag disables it." } + ], + "returns": [ + { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } + ] + }, + { + "name": "setIgnoreCertificateErrors", + "description": "Change whether all certificate errors should be ignored.", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }, + { "name": "ignore", "type": "boolean" } + ] + }, + { + "name": "setPageZoomFactor", + "description": "Changes page zoom factor.", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "zoomFactor", "type": "number" } + ] + }, + { + "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." } + ] + }, + { + "name": "setGeolocationOverride", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }, + { "name": "geolocation", "$ref": "Geolocation", "optional": true, "description": "Geolocation to set, if missing emulates position unavailable." } + ], + "description": "Overrides the geolocation position or error." + }, + { + "name": "setLanguages", + "description": "Allows to set locale language for context.", + "parameters": [ + { "name": "languages", "type": "array", "items": { "type": "string" } }, + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ] + }, + { + "name": "setDownloadBehavior", + "description": "Allows to override download behavior.", + "parameters": [ + { "name": "behavior", "optional": true, "type": "string", "enum": ["allow", "deny"] }, + { "name": "downloadPath", "optional": true, "type": "string" }, + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ] + }, + { + "name": "cancelDownload", + "parameters": [ + { "name": "uuid", "type": "string" } + ], + "description": "Cancels a current running download." + }, + { + "name": "clearMemoryCache", + "description": "Clears browser memory cache.", + "async": true, + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ] + } + ], + "events": [ + { + "name": "pageProxyCreated", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." }, + { "name": "pageProxyId", "$ref": "PageProxyID" }, + { "name": "openerId", "$ref": "PageProxyID", "optional": true, "description": "Unique identifier of the opening page. Only set for pages created by window.open()." } + ] + }, + { + "name": "pageProxyDestroyed", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID" } + ] + }, + { + "name": "provisionalLoadFailed", + "description": "Fired when provisional load fails.", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "loaderId", "$ref": "Network.LoaderId", "description": "Identifier of the loader associated with the navigation." }, + { "name": "error", "type": "string", "description": "Localized error string." } + ] + }, + { + "name": "windowOpen", + "description": "Fired when page opens a new window.", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "url", "type": "string" }, + { "name": "windowFeatures", "type": "array", "items": { "type": "string" } } + ] + }, + { + "name": "downloadCreated", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Unique identifier of the originating frame." }, + { "name": "uuid", "type": "string" }, + { "name": "url", "type": "string" } + ] + }, + { + "name": "downloadFilenameSuggested", + "parameters": [ + { "name": "uuid", "type": "string" }, + { "name": "suggestedFilename", "type": "string" } + ] + }, + { + "name": "downloadFinished", + "parameters": [ + { "name": "uuid", "type": "string" }, + { "name": "error", "type": "string" } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json index b8c2c5b7c4a4411affc4d928521f809bc468673c..b0134b3d794df05a6386ed012715bb47519248f2 100644 --- a/Source/JavaScriptCore/inspector/protocol/Runtime.json +++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json @@ -272,6 +272,13 @@ ], "async": true }, + { + "name": "addBinding", + "description": "Adds binding with the given name on the global objects of all inspected contexts. Each binding function call produces Runtime.bindingCalled event.", + "parameters": [ + { "name": "name", "type": "string", "description": "Name of the bound function." } + ] + }, { "name": "getPreview", "description": "Returns a preview for the given object.", @@ -408,6 +415,15 @@ "parameters": [ { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution context." } ] - } + }, + { + "name": "bindingCalled", + "description": "Issued when new execution context is created.", + "parameters": [ + { "name": "contextId", "$ref": "ExecutionContextId", "description": "Id of the execution context where the binding was called." }, + { "name": "name", "type": "string", "description": "Name of the bound function." }, + { "name": "argument", "type": "string", "description": "String argument passed to the function." } + ] + } ] } diff --git a/Source/JavaScriptCore/inspector/protocol/Screencast.json b/Source/JavaScriptCore/inspector/protocol/Screencast.json new file mode 100644 index 0000000000000000000000000000000000000000..8546676698ddb1e0606068dd99f66cc8cca6357f --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Screencast.json @@ -0,0 +1,47 @@ +{ + "domain": "Screencast", + "availability": ["web"], + "types": [ + { + "id": "ScreencastId", + "type": "string", + "description": "Unique identifier of the screencast." + } + ], + "commands": [ + { + "name": "startScreencast", + "description": "Starts screencast.", + "parameters": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" }, + { "name": "toolbarHeight", "type": "integer" }, + { "name": "quality", "type": "integer" } + ], + "returns": [ + { "name": "generation", "type": "integer", "description": "Screencast session generation." } + ] + }, + { + "name": "stopScreencast", + "description": "Stops screencast." + }, + { + "name": "screencastFrameAck", + "parameters": [ + { "name": "generation", "type": "integer", "description": "Screencast session generation" } + ] + } + ], + "events": [ + { + "name": "screencastFrame", + "parameters": [ + { "name": "data", "type": "string", "description": "Base64 data" }, + { "name": "timestamp", "type": "number" }, + { "name": "deviceWidth", "type": "integer" }, + { "name": "deviceHeight", "type": "integer" } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Target.json b/Source/JavaScriptCore/inspector/protocol/Target.json index a861a83b87e4e7752e547b7070ec1ef26e1cc3e5..16d6ec26034758e127dcb599f5cb170823182470 100644 --- a/Source/JavaScriptCore/inspector/protocol/Target.json +++ b/Source/JavaScriptCore/inspector/protocol/Target.json @@ -10,7 +10,7 @@ "properties": [ { "name": "targetId", "type": "string", "description": "Unique identifier for the target." }, { "name": "type", "type": "string", "enum": ["page", "frame", "service-worker", "worker"] }, - { "name": "isProvisional", "type": "boolean", "optional": true, "description": "Whether this is a provisional page target." }, + { "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": "isPaused", "type": "boolean", "optional": true, "description": "Whether the target is paused on start and has to be explicitely resumed by inspector." } ] } @@ -37,6 +37,21 @@ { "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" }, + { "name": "runBeforeUnload", "type": "boolean", "optional": true } + ] } ], "events": [ @@ -49,7 +64,8 @@ { "name": "targetDestroyed", "parameters": [ - { "name": "targetId", "type": "string" } + { "name": "targetId", "type": "string" }, + { "name": "crashed", "type": "boolean" } ] }, { diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.h b/Source/JavaScriptCore/runtime/ConsoleClient.h index 6af957ee69490bad4443e90161adc2230c329105..1270e77b913578ba8965fdd30c4bd44687d891ab 100644 --- a/Source/JavaScriptCore/runtime/ConsoleClient.h +++ b/Source/JavaScriptCore/runtime/ConsoleClient.h @@ -74,6 +74,7 @@ public: virtual void record(JSGlobalObject*, Ref&&) = 0; virtual void recordEnd(JSGlobalObject*, Ref&&) = 0; virtual void screenshot(JSGlobalObject*, Ref&&) = 0; + virtual void bindingCalled(JSGlobalObject*, const String& name, const String& arg) = 0; private: enum class ArgumentRequirement { No, Yes }; diff --git a/Source/ThirdParty/skia/CMakeLists.txt b/Source/ThirdParty/skia/CMakeLists.txt index 607a4b0f761b0aadd3ca8b83e080519ad6f97715..609f5b23e6ebd2629a1313673d9d8ea5d6fc57b7 100644 --- a/Source/ThirdParty/skia/CMakeLists.txt +++ b/Source/ThirdParty/skia/CMakeLists.txt @@ -10,6 +10,8 @@ if (USE_SKIA_ENCODERS) find_package(WebP REQUIRED COMPONENTS mux) endif () +find_package(Threads REQUIRED) + if (ANDROID) find_package(EXPAT REQUIRED) endif () @@ -970,6 +972,7 @@ endif () target_link_libraries(Skia PRIVATE JPEG::JPEG PNG::PNG + Threads::Threads ) WEBKIT_ADD_TARGET_CXX_FLAGS(Skia diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index 991cbe56d742a6cdd31d5a142754675272d4abd8..ce7e004a533d87765976b46e1d538799d2226af5 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml @@ -605,6 +605,7 @@ ApplePayEnabled: richJavaScript: true # FIXME: This is on by default in WebKit2 PLATFORM(COCOA). Perhaps we should consider turning it on for WebKitLegacy as well. +# Playwright: enable on all platforms to align with Safari. AsyncClipboardAPIEnabled: type: bool status: mature @@ -615,7 +616,7 @@ AsyncClipboardAPIEnabled: default: false WebKit: "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)" : true - default: false + default: true WebCore: default: false @@ -871,13 +872,10 @@ BlobFileAccessEnforcementEnabled: sharedPreferenceForWebProcess: true defaultValue: WebKitLegacy: - "PLATFORM(COCOA)": true default: false WebKit: - "PLATFORM(COCOA)": true default: false WebCore: - "PLATFORM(COCOA)": true default: false BlockIOKitInWebContentSandbox: @@ -2073,6 +2071,7 @@ CrossOriginEmbedderPolicyEnabled: WebCore: default: false +# Playwright: disable setting. CrossOriginOpenerPolicyEnabled: type: bool status: stable @@ -2146,6 +2145,7 @@ DOMAudioSessionFullEnabled: WebCore: default: false +# Playwright: enable on all platforms to align with Safari. DOMPasteAccessRequestsEnabled: type: bool status: internal @@ -2157,7 +2157,7 @@ DOMPasteAccessRequestsEnabled: default: false WebKit: "PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(VISION)": true - default: false + default: true WebCore: default: false @@ -2223,10 +2223,10 @@ DataListElementEnabled: WebKitLegacy: default: false WebKit: - "(PLATFORM(COCOA) && !PLATFORM(WATCHOS)) || PLATFORM(GTK)": true + "(PLATFORM(COCOA) && !PLATFORM(WATCHOS)) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true default: false WebCore: - "(PLATFORM(COCOA) && !PLATFORM(WATCHOS)) || PLATFORM(GTK)": true + "(PLATFORM(COCOA) && !PLATFORM(WATCHOS)) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true default: false sharedPreferenceForWebProcess: true @@ -2239,7 +2239,7 @@ DataTransferItemsEnabled: WebKitLegacy: default: true WebKit: - "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)": true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true default: false WebCore: default: false @@ -2482,7 +2482,7 @@ DirectoryUploadEnabled: WebKitLegacy: default: false WebKit: - "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)": true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true default: false WebCore: default: false @@ -3188,10 +3188,10 @@ FullScreenEnabled: WebKitLegacy: default: false WebKit: - "PLATFORM(GTK) || PLATFORM(WPE)": true + "PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(WPE)": true default: false WebCore: - "PLATFORM(GTK) || PLATFORM(WPE)": true + "PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(WPE)": true default: false sharedPreferenceForWebProcess: true @@ -3503,7 +3503,7 @@ HardwareAccelerationEnabled: status: internal humanReadableName: "Hardware acceleration" humanReadableDescription: "Enable hardware acceleration" - condition: PLATFORM(GTK) || ENABLE(WPE_PLATFORM) + condition: PLATFORM(GTK) || PLATFORM(WPE) defaultValue: WebKitLegacy: default: true @@ -3910,7 +3910,7 @@ InputTypeColorEnabled: WebKitLegacy: default: false WebKit: - "PLATFORM(COCOA) && !PLATFORM(WATCHOS) || PLATFORM(GTK)": true + "PLATFORM(COCOA) && !PLATFORM(WATCHOS) || PLATFORM(GTK) || PLATFORM(WPE)": true default: false WebCore: default: false @@ -3943,7 +3943,7 @@ InputTypeDateEnabled: "PLATFORM(IOS_FAMILY)": true default: false WebKit: - "PLATFORM(COCOA) || PLATFORM(GTK)": true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)": true default: false WebCore: default: false @@ -3959,7 +3959,7 @@ InputTypeDateTimeLocalEnabled: "PLATFORM(IOS_FAMILY)": true default: false WebKit: - "PLATFORM(COCOA) || PLATFORM(GTK)": true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)": true default: false WebCore: default: false @@ -3991,7 +3991,7 @@ InputTypeTimeEnabled: "PLATFORM(IOS_FAMILY)": true default: false WebKit: - "PLATFORM(COCOA) || PLATFORM(GTK)": true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)": true default: false WebCore: default: false @@ -4052,6 +4052,7 @@ InspectorMaximumResourcesContentSize: "PLATFORM(WPE)": 50 default: 200 +# Playwright: disable setting. InspectorStartsAttached: type: bool status: embedder @@ -4059,7 +4060,7 @@ InspectorStartsAttached: exposed: [ WebKit ] defaultValue: WebKit: - default: true + default: false InspectorSupportsShowingCertificate: type: bool @@ -6266,7 +6267,7 @@ PointerLockEnabled: "PLATFORM(IOS_FAMILY)": false default: true WebCore: - default: false + default: true PopoverAttributeEnabled: type: bool @@ -6896,7 +6897,7 @@ ScreenOrientationAPIEnabled: WebKitLegacy: default: false WebKit: - default: WebKit::defaultShouldEnableScreenOrientationAPI() + default: true WebCore: default: false sharedPreferenceForWebProcess: true diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h index 7219e25002712fb773a8dd1c7c601e60b63c5d14..3d3054fbce6dda47761e0a1c1533a51764bf79ba 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h @@ -455,7 +455,7 @@ // ORIENTATION_EVENTS should never get enabled on Desktop, only Mobile. #if !defined(ENABLE_ORIENTATION_EVENTS) -#define ENABLE_ORIENTATION_EVENTS 0 +#define ENABLE_ORIENTATION_EVENTS 1 #endif #if OS(WINDOWS) @@ -568,7 +568,7 @@ #endif #if !defined(ENABLE_TOUCH_EVENTS) -#define ENABLE_TOUCH_EVENTS 0 +#define ENABLE_TOUCH_EVENTS 1 #endif #if !defined(ENABLE_CSS_TAP_HIGHLIGHT_COLOR) && ENABLE(TOUCH_EVENTS) diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h index cfa2003ccb9464bbf804c4aa37a283110ac0fbfd..3db834d1a46023ed7a3cdffd64b012ab882aa8c9 100644 --- a/Source/WTF/wtf/PlatformEnableCocoa.h +++ b/Source/WTF/wtf/PlatformEnableCocoa.h @@ -822,7 +822,7 @@ #endif #if !defined(ENABLE_SEC_ITEM_SHIM) -#define ENABLE_SEC_ITEM_SHIM 1 +#define ENABLE_SEC_ITEM_SHIM 0 #endif #if !defined(ENABLE_SERVER_PRECONNECT) diff --git a/Source/WTF/wtf/StdLibExtras.h b/Source/WTF/wtf/StdLibExtras.h index ebdcb2707223f582f378d83ccbf31aa115724047..cc2d26b056618c847d6e184f73fff1701d5b921d 100644 --- a/Source/WTF/wtf/StdLibExtras.h +++ b/Source/WTF/wtf/StdLibExtras.h @@ -1607,6 +1607,39 @@ template constexpr auto forward_like(U&& value) -> detai template constexpr auto forward_like_preserving_const(U&& value) -> detail::forward_like_preserving_const_impl { return static_cast>(value); } } // namespace WTF +#if defined(__GLIBCXX__) && !defined(__cpp_lib_ranges_zip) +#include + +namespace std::ranges { + +struct _Zip { + template + requires (sizeof...(_Ts) <= 2) + constexpr auto + operator() [[nodiscard]] (_Ts&&... __ts) const { + if constexpr (!sizeof...(_Ts)) { + return views::empty>; + } else if constexpr (sizeof...(_Ts) == 1) { + return [](auto&& arg1, auto&&...) { + return std::forward(arg1); + }(std::forward<_Ts>(__ts)...); + } else { + return [](auto&& arg1, auto&& arg2, auto&&...) { + return zippedRange(std::forward(arg1), std::forward(arg2)); + }(std::forward<_Ts>(__ts)...); + } + } +}; + +namespace views { + inline constexpr _Zip zip; +} + +using WTF::zippedRange; + +} // namespace std::ranges +#endif // defined(__GLIBCXX__) && !defined(__cpp_lib_ranges_zip) + using WTF::GB; using WTF::KB; using WTF::MB; diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.h b/Source/WTF/wtf/unicode/UTF8Conversion.h index 8f551b2abcca06a623c432ac52db75de16849e8e..92bbd90bd032b9a9290ec741e7b38f9e9438f97e 100644 --- a/Source/WTF/wtf/unicode/UTF8Conversion.h +++ b/Source/WTF/wtf/unicode/UTF8Conversion.h @@ -30,6 +30,11 @@ #include #include +// Can be probably removed when we drop Debian 11. +#ifdef Success +#undef Success +#endif + namespace WTF { namespace Unicode { diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make index e98fccbdefe93270040e91cb9fef8e28879c7dec..5187df2924731e17a779a23e5fd51eafadd8bb0e 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make @@ -1257,6 +1257,10 @@ JS_BINDING_IDLS := \ $(WebCore)/dom/SubscriberCallback.idl \ $(WebCore)/dom/SubscriptionObserver.idl \ $(WebCore)/dom/SubscriptionObserverCallback.idl \ + $(WebCore)/dom/Document+Touch.idl \ + $(WebCore)/dom/Touch.idl \ + $(WebCore)/dom/TouchEvent.idl \ + $(WebCore)/dom/TouchList.idl \ $(WebCore)/dom/Text.idl \ $(WebCore)/dom/TextDecoder.idl \ $(WebCore)/dom/TextDecoderStream.idl \ @@ -1881,9 +1885,6 @@ JS_BINDING_IDLS := \ ADDITIONAL_BINDING_IDLS = \ DocumentTouch.idl \ GestureEvent.idl \ - Touch.idl \ - TouchEvent.idl \ - TouchList.idl \ # vpath %.in $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) diff --git a/Source/WebCore/Modules/geolocation/Geolocation.cpp b/Source/WebCore/Modules/geolocation/Geolocation.cpp index f468a12c6cae3ecc22fd9d7eacccb55c199f4dab..7fdb15208f24e4c91267c7d9fb776b774e5dfdda 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp @@ -365,8 +365,9 @@ bool Geolocation::shouldBlockGeolocationRequests() bool isSecure = SecurityOrigin::isSecure(document->url()) || document->isSecureContext(); bool isLocalOrigin = securityOrigin()->isLocal(); + bool isPotentiallyTrustworthy = securityOrigin()->isPotentiallyTrustworthy(); if (document->canAccessResource(ScriptExecutionContext::ResourceType::Geolocation) != ScriptExecutionContext::HasResourceAccess::No) { - if (isLocalOrigin || isSecure) + if (isLocalOrigin || isSecure || isPotentiallyTrustworthy) return false; } diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm index de8ce576a7e7156460680e5ea11f10a84cda83ec..3b502fa4663dc528cb892d28e5217c4ec8bb7ea4 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm @@ -198,6 +198,7 @@ - (void)sendEndIfNeeded - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available { + UNUSED_PARAM(speechRecognizer); ASSERT(isMainThread()); if (available || !_task) @@ -211,6 +212,7 @@ - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidC - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self sendSpeechStartIfNeeded]; @@ -219,6 +221,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTran - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult { + UNUSED_PARAM(task); ASSERT(isMainThread()); if (task.state == SFSpeechRecognitionTaskStateCanceling || (!_doMultipleRecognitions && task.state == SFSpeechRecognitionTaskStateCompleted)) @@ -232,6 +235,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecogniti - (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self sendSpeechEndIfNeeded]; diff --git a/Source/WebCore/PlatformWin.cmake b/Source/WebCore/PlatformWin.cmake index 72b2846f2c82818fc9a64fd90b7cba0c0601e15f..22277ab6c3233f040852d9daf9becf7ba81d12ca 100644 --- a/Source/WebCore/PlatformWin.cmake +++ b/Source/WebCore/PlatformWin.cmake @@ -217,6 +217,7 @@ if (USE_CAIRO) platform/graphics/win/cairo/MediaPlayerPrivateMediaFoundationCairo.cpp platform/win/cairo/DragImageWinCairo.cpp + platform/win/DragImageWin.cpp ) elseif (USE_SKIA) list(APPEND WebCore_SOURCES diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt index 0630227f46780e9af2a5442c8f6807f2e889b011..acb032704a3b778b9c184afb02f7cb70450de1b0 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt @@ -746,3 +746,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm @nonARC platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify platform/graphics/cocoa/GraphicsContextGLCocoa.mm @nonARC @no-unify platform/graphics/cv/GraphicsContextGLCVCocoa.mm @nonARC @no-unify + +// Playwright begin +JSTouch.cpp +JSTouchEvent.cpp +JSTouchList.cpp +// Playwright end diff --git a/Source/WebCore/SourcesGTK.txt b/Source/WebCore/SourcesGTK.txt index 8c4a4c5e75fc792adb0c0801b3e81fd220df777c..99da4150c59018176142f34ebfccd4053c55fc49 100644 --- a/Source/WebCore/SourcesGTK.txt +++ b/Source/WebCore/SourcesGTK.txt @@ -107,3 +107,10 @@ platform/unix/LoggingUnix.cpp platform/unix/SharedMemoryUnix.cpp platform/xdg/MIMETypeRegistryXdg.cpp + +// Playwright: begin. +JSSpeechSynthesisErrorCode.cpp +JSSpeechSynthesisErrorEvent.cpp +JSSpeechSynthesisErrorEventInit.cpp +JSSpeechSynthesisEventInit.cpp +// Playwright: end. diff --git a/Source/WebCore/SourcesWPE.txt b/Source/WebCore/SourcesWPE.txt index eb48da502311408b4772385e51b4143da28fc5d0..0cbc5941fa1c659f5a76f77cc4b22ee5842e77af 100644 --- a/Source/WebCore/SourcesWPE.txt +++ b/Source/WebCore/SourcesWPE.txt @@ -114,3 +114,8 @@ platform/wpe/PasteboardWPE.cpp platform/wpe/PlatformScreenWPE.cpp platform/xdg/MIMETypeRegistryXdg.cpp + +JSSpeechSynthesisErrorCode.cpp +JSSpeechSynthesisErrorEvent.cpp +JSSpeechSynthesisErrorEventInit.cpp +JSSpeechSynthesisEventInit.cpp diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj index 308d7803e73db4277cd404ddb1314d29d3dba836..9526210649e3d9f55ec524547be40f3087aaa9dd 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj @@ -6992,6 +6992,13 @@ EE6C530F2F8831FF00C7B706 /* RenderTreeOrder.h in Headers */ = {isa = PBXBuildFile; fileRef = EE6C530D2F8830BD00C7B706 /* RenderTreeOrder.h */; settings = {ATTRIBUTES = (Private, ); }; }; EEE349082DE0061C00A7D4BB /* StyleScopeIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = EEE349072DE005FC00A7D4BB /* StyleScopeIdentifier.h */; settings = {ATTRIBUTES = (Private, ); }; }; EFCC6C8F20FE914400A2321B /* CanvasActivityRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F050E16823AC9C080011CE47 /* PlatformTouchEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F050E16A23AD660C0011CE47 /* Touch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F050E16923AD660C0011CE47 /* Touch.cpp */; }; + F050E16D23AD66630011CE47 /* TouchList.h in Headers */ = {isa = PBXBuildFile; fileRef = F050E16B23AD66620011CE47 /* TouchList.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F050E16E23AD66630011CE47 /* TouchList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F050E16C23AD66630011CE47 /* TouchList.cpp */; }; + F050E17123AD669F0011CE47 /* TouchEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F050E16F23AD669E0011CE47 /* TouchEvent.cpp */; }; + F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F050E17323AD6A800011CE47 /* DocumentTouch.cpp */; }; + F050E17823AD70C50011CE47 /* PlatformTouchPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; }; F30EE46B2E721BA800935B60 /* FrameInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = F30EE46A2E721B9D00935B60 /* FrameInspectorController.h */; settings = {ATTRIBUTES = (Private, ); }; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; @@ -22710,6 +22717,14 @@ EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; sourceTree = ""; }; F088343F2E721B29001B2348 /* AXLocalFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AXLocalFrame.h; sourceTree = ""; }; F08834402E721B33001B2348 /* AXLocalFrame.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AXLocalFrame.cpp; sourceTree = ""; }; + F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformTouchEvent.h; sourceTree = ""; }; + F050E16923AD660C0011CE47 /* Touch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Touch.cpp; path = dom/Touch.cpp; sourceTree = SOURCE_ROOT; }; + F050E16B23AD66620011CE47 /* TouchList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TouchList.h; path = dom/TouchList.h; sourceTree = SOURCE_ROOT; }; + F050E16C23AD66630011CE47 /* TouchList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TouchList.cpp; path = dom/TouchList.cpp; sourceTree = SOURCE_ROOT; }; + F050E16F23AD669E0011CE47 /* TouchEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TouchEvent.cpp; path = dom/TouchEvent.cpp; sourceTree = SOURCE_ROOT; }; + F050E17023AD669F0011CE47 /* TouchEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TouchEvent.h; path = dom/TouchEvent.h; sourceTree = SOURCE_ROOT; }; + F050E17323AD6A800011CE47 /* DocumentTouch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentTouch.cpp; sourceTree = ""; }; + F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformTouchPoint.h; sourceTree = ""; }; F12171F316A8BC63000053CA /* WebVTTElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTElement.cpp; sourceTree = ""; }; F12171F416A8BC63000053CA /* WebVTTElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTElement.h; sourceTree = ""; }; F30EE46A2E721B9D00935B60 /* FrameInspectorController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FrameInspectorController.h; sourceTree = ""; }; @@ -30743,6 +30758,11 @@ BC4A5324256055590028C592 /* TextDirectionSubmenuInclusionBehavior.h */, 2D4F96F11A1ECC240098BF88 /* TextIndicator.cpp */, 2D4F96F21A1ECC240098BF88 /* TextIndicator.h */, + F050E16923AD660C0011CE47 /* Touch.cpp */, + F050E16F23AD669E0011CE47 /* TouchEvent.cpp */, + F050E17023AD669F0011CE47 /* TouchEvent.h */, + F050E16C23AD66630011CE47 /* TouchList.cpp */, + F050E16B23AD66620011CE47 /* TouchList.h */, F48570A42644C76D00C05F71 /* TranslationContextMenuInfo.h */, D640B24C2E3058C800EB6C49 /* UADataValues.h */, D640B24E2E3058C800EB6C49 /* UADataValues.idl */, @@ -38753,6 +38773,8 @@ 29E4D8DF16B0940F00C84704 /* PlatformSpeechSynthesizer.h */, 1AD8F81A11CAB9E900E93E54 /* PlatformStrategies.cpp */, 1AD8F81911CAB9E900E93E54 /* PlatformStrategies.h */, + F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */, + F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */, FE3DC9932D0C063C0021B6FC /* PlatformTZoneImpls.cpp */, 0FD7C21D23CE41E30096D102 /* PlatformWheelEvent.cpp */, 935C476A09AC4D4F00A6AAB4 /* PlatformWheelEvent.h */, @@ -41766,6 +41788,7 @@ AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, + F050E17323AD6A800011CE47 /* DocumentTouch.cpp */, 7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */, 7CE7FA591EF882300060C9D6 /* DocumentTouch.h */, A8185F3209765765005826D9 /* DocumentType.cpp */, @@ -46955,6 +46978,8 @@ F4E90A3C2B52038E002DA469 /* PlatformTextAlternatives.h in Headers */, 0F7D07331884C56C00B4AF86 /* PlatformTextTrack.h in Headers */, 074E82BB18A69F0E007EF54C /* PlatformTimeRanges.h in Headers */, + F050E16823AC9C080011CE47 /* PlatformTouchEvent.h in Headers */, + F050E17823AD70C50011CE47 /* PlatformTouchPoint.h in Headers */, CDD08ABD277E542600EA3755 /* PlatformTrackConfiguration.h in Headers */, CD1F9B022700323D00617EB6 /* PlatformVideoColorPrimaries.h in Headers */, CD1F9B01270020B700617EB6 /* PlatformVideoColorSpace.h in Headers */, @@ -48629,6 +48654,7 @@ 0F54DD081881D5F5003EEDBB /* Touch.h in Headers */, 71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */, 0F54DD091881D5F5003EEDBB /* TouchEvent.h in Headers */, + F050E16D23AD66630011CE47 /* TouchList.h in Headers */, 0F54DD0A1881D5F5003EEDBB /* TouchList.h in Headers */, 070334D71459FFD5008D8D45 /* TrackBase.h in Headers */, 513C7B6E2E7C2E7A00079881 /* TrackInfo.h in Headers */, @@ -49903,7 +49929,9 @@ 2D22830323A8470700364B7E /* CursorMac.mm in Sources */, 5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */, 07E4BDBF2A3A5FAB000D5509 /* DictationCaretAnimator.cpp in Sources */, + F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */, 0749E9512E275A23009B912B /* EditingHTMLConverter.mm in Sources */, + 329C0C2528BD96EB00F187D2 /* ElementName.cpp in Sources */, 7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */, 4667EA3E2968D9DA00BAB1E2 /* GameControllerHapticEffect.mm in Sources */, 46FE73D32968E52000B8064C /* GameControllerHapticEngines.mm in Sources */, @@ -50000,6 +50028,9 @@ 072F696F2E755BFA00281FC5 /* TextListParser.cpp in Sources */, BE39137129B267F500FA5D4F /* TextTransformCocoa.cpp in Sources */, 51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */, + F050E16A23AD660C0011CE47 /* Touch.cpp in Sources */, + F050E17123AD669F0011CE47 /* TouchEvent.cpp in Sources */, + F050E16E23AD66630011CE47 /* TouchList.cpp in Sources */, 0D0B4DA32EBD20E30053FB12 /* UnifiedSource1-ARC.mm in Sources */, 538EC8031F96AF81004D22A8 /* UnifiedSource1-nonARC.mm in Sources */, 538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */, diff --git a/Source/WebCore/css/query/MediaQueryFeatures.cpp b/Source/WebCore/css/query/MediaQueryFeatures.cpp index ab1b8b7d0e7baff7d7564609736a6145472c2e3a..00921097a9f2b5d96937785e62f5a3533afafe55 100644 --- a/Source/WebCore/css/query/MediaQueryFeatures.cpp +++ b/Source/WebCore/css/query/MediaQueryFeatures.cpp @@ -404,7 +404,11 @@ static const IdentifierSchema& forcedColorsFeatureSchema() "forced-colors"_s, FixedVector { CSSValueNone, CSSValueActive }, OptionSet(), - [](auto&) { + [](auto& context) { + auto* page = context.document->frame()->page(); + std::optional forcedColorsOverride = page->useForcedColorsOverride(); + if (forcedColorsOverride) + return forcedColorsOverride.value() ? MatchingIdentifiers { CSSValueActive } : MatchingIdentifiers { CSSValueNone }; return MatchingIdentifiers { CSSValueNone }; } }; @@ -592,6 +596,9 @@ static const IdentifierSchema& prefersReducedMotionFeatureSchema() [](auto& context) { bool userPrefersReducedMotion = [&] { Ref frame = *context.document->frame(); + std::optional reducedMotionOverride = frame->page()->useReducedMotionOverride(); + if (reducedMotionOverride) + return reducedMotionOverride.value(); switch (frame->settings().forcedPrefersReducedMotionAccessibilityValue()) { case ForcedAccessibilityValue::On: return true; diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp index 6fac2c209afa640cf7a305c9c322791c0cce2435..a609e0272959a42dec0e44cfd943ab6a8d78865a 100644 --- a/Source/WebCore/dom/DataTransfer.cpp +++ b/Source/WebCore/dom/DataTransfer.cpp @@ -531,6 +531,14 @@ Ref DataTransfer::createForDrag(const Document& document) return adoptRef(*new DataTransfer(StoreMode::ReadWrite, Pasteboard::createForDragAndDrop(PagePasteboardContext::create(document.pageID())), Type::DragAndDropData)); } +#if PLATFORM(MAC) +Ref DataTransfer::createForDrag(const Document& document, const String& pasteboardName) +{ + return adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique(PagePasteboardContext::create(document.pageID()), pasteboardName), Type::DragAndDropData)); +} +#endif + + Ref DataTransfer::createForDragStartEvent(const Document& document) { auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique(), Type::DragAndDropData)); diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h index 64a53ff58bf7bcd9e56ccc8b74cea8c9c75bf89e..10d52432373f02622328f32d3f665ed0fdd8bc24 100644 --- a/Source/WebCore/dom/DataTransfer.h +++ b/Source/WebCore/dom/DataTransfer.h @@ -92,6 +92,9 @@ public: #if ENABLE(DRAG_SUPPORT) static Ref createForDrag(const Document&); +#if PLATFORM(MAC) + static Ref createForDrag(const Document&, const String& pasteboardName); +#endif static Ref createForDragStartEvent(const Document&); static Ref createForDrop(const Document&, std::unique_ptr&&, OptionSet, bool draggingFiles); static Ref createForUpdatingDropTarget(const Document&, std::unique_ptr&&, OptionSet, bool draggingFiles); diff --git a/Source/WebCore/dom/DeviceMotionEvent.idl b/Source/WebCore/dom/DeviceMotionEvent.idl index a2e91e304c473d6c2de246e51539fac8e265e216..eb3f2a61f74a7d533fcdc5aedecb723be75ba105 100644 --- a/Source/WebCore/dom/DeviceMotionEvent.idl +++ b/Source/WebCore/dom/DeviceMotionEvent.idl @@ -20,12 +20,13 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // https://w3c.github.io/deviceorientation/#devicemotionevent [ Conditional=DEVICE_ORIENTATION, + EnabledBySetting=DeviceOrientationEventEnabled, Exposed=Window, SecureContext ] interface DeviceMotionEvent : Event { diff --git a/Source/WebCore/dom/DeviceOrientationEvent.idl b/Source/WebCore/dom/DeviceOrientationEvent.idl index 2feeeac677ee3f36cb13c2bac1afbc57fbe70e12..6ed92e45b7659c48b3bb1e24f7f0075117178332 100644 --- a/Source/WebCore/dom/DeviceOrientationEvent.idl +++ b/Source/WebCore/dom/DeviceOrientationEvent.idl @@ -25,6 +25,7 @@ [ Conditional=DEVICE_ORIENTATION, + EnabledBySetting=DeviceOrientationEventEnabled, Exposed=Window, SecureContext ] interface DeviceOrientationEvent : Event { diff --git a/Source/WebCore/dom/PointerEvent.cpp b/Source/WebCore/dom/PointerEvent.cpp index dd8c59fe17c70a72f03df3c884b5a92f8f655e61..9c2b847b15f4361ad8199729c2b808a0253b77c2 100644 --- a/Source/WebCore/dom/PointerEvent.cpp +++ b/Source/WebCore/dom/PointerEvent.cpp @@ -20,7 +20,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -28,7 +28,9 @@ #include "EventNames.h" #include "MouseEventTypes.h" +#include "MouseEvent.h" #include "Node.h" +#include "PlatformTouchEvent.h" #include "PointerEventTypeNames.h" #include #include @@ -380,4 +382,59 @@ double PointerEvent::offsetY() return adjustedCoordinateForType(offsetLocation().y()); } +#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) && !PLATFORM(WPE) && !PLATFORM(GTK) + +static const AtomString& pointerEventType(PlatformTouchPoint::State state) +{ + switch (state) { + case PlatformTouchPoint::State::TouchPressed: + return eventNames().pointerdownEvent; + case PlatformTouchPoint::State::TouchMoved: + return eventNames().pointermoveEvent; + case PlatformTouchPoint::State::TouchStationary: + return eventNames().pointermoveEvent; + case PlatformTouchPoint::State::TouchReleased: + return eventNames().pointerupEvent; + case PlatformTouchPoint::State::TouchCancelled: + return eventNames().pointercancelEvent; + case PlatformTouchPoint::State::TouchStateEnd: + break; + } + ASSERT_NOT_REACHED(); + return nullAtom(); +} + +Ref PointerEvent::create(const PlatformTouchEvent& event, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&& view, const DoublePoint& touchDelta) +{ + const auto& type = pointerEventType(event.touchPoints().at(touchIndex).state()); + return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, typeCanBubble(type), typeIsCancelable(type), touchIndex, isPrimary, WTF::move(view), touchDelta)); +} + +Ref PointerEvent::create(const PlatformTouchEvent& event, const Vector>& coalescedEvents, const Vector>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref&& view, const DoublePoint& touchDelta) +{ + const auto& type = pointerEventType(event.touchPoints().at(touchIndex).state()); + return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, canBubble, isCancelable, touchIndex, isPrimary, WTF::move(view), touchDelta)); +} + +Ref PointerEvent::create(const AtomString& type, const PlatformTouchEvent& event, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&& view, const DoublePoint& touchDelta) +{ + return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, typeCanBubble(type), typeIsCancelable(type), touchIndex, isPrimary, WTF::move(view), touchDelta)); +} + +PointerEvent::PointerEvent(const AtomString& type, const PlatformTouchEvent& event, const Vector>& coalescedEvents, const Vector>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref&& view, const DoublePoint& touchDelta) + : MouseEvent(EventInterfaceType::PointerEvent, type, canBubble, isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTF::move(view), 0, + event.touchPoints().at(touchIndex).pos(), event.touchPoints().at(touchIndex).pos(), touchDelta.x(), touchDelta.y(), event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, SyntheticClickType::NoTap, { }, { }, std::nullopt, IsSimulated::No, IsTrusted::Yes) + , m_pointerId(event.touchPoints().at(touchIndex).id()) + , m_width(2 * event.touchPoints().at(touchIndex).radius().width()) + , m_height(2 * event.touchPoints().at(touchIndex).radius().height()) + , m_pressure(event.touchPoints().at(touchIndex).force()) + , m_pointerType(touchPointerEventType()) + , m_isPrimary(isPrimary) + , m_coalescedEvents(coalescedEvents) + , m_predictedEvents(predictedEvents) +{ +} + +#endif // ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) && !PLATFORM(WPE) && !PLATFORM(GTK) + } // namespace WebCore diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h index a9ad0f77eedb629a360c8ec77257e84e59418dbf..3486cfaa73edb83300e597ab3fc8ab115e96ee54 100644 --- a/Source/WebCore/dom/PointerEvent.h +++ b/Source/WebCore/dom/PointerEvent.h @@ -41,8 +41,8 @@ #pragma clang diagnostic pop #endif -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(WPE) || PLATFORM(GTK)) -#include "PlatformTouchEvent.h" +#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) +#include #endif namespace WebCore { @@ -99,14 +99,18 @@ public: static Ref create(const AtomString& type, MouseButton, const MouseEvent&, PointerID, const String& pointerType, CanBubble, IsCancelable); static Ref create(const AtomString& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No); -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) static Ref create(const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&&, const DoublePoint& touchDelta = { }); static Ref create(const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, CanBubble, IsCancelable, unsigned touchIndex, bool isPrimary, Ref&& view, const DoublePoint& touchDelta = { }); static Ref create(const AtomString& type, const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&&, const DoublePoint& touchDelta = { }); #endif -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) +#if PLATFORM(WPE) || PLATFORM(GTK) static unsigned pointerIdForTouchPoint(const PlatformTouchPoint&); +#elif !ENABLE(IOS_TOUCH_EVENTS) + static unsigned pointerIdForTouchPoint(const PlatformTouchPoint& point) { return point.id(); } +#endif #endif virtual ~PointerEvent(); @@ -194,7 +198,7 @@ private: PointerEvent(); PointerEvent(const AtomString&, Init&&, IsTrusted); PointerEvent(const AtomString& type, PointerID, const String& pointerType, IsPrimary); -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) PointerEvent(const AtomString& type, const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref&&, const DoublePoint& touchDelta = { }); #endif diff --git a/Source/WebCore/dom/TouchList.h b/Source/WebCore/dom/TouchList.h index 25546b5bdf24a88141f2a968c07e9d424d61f7e1..980a173d056b6dd4f89ae394dee01b510def691e 100644 --- a/Source/WebCore/dom/TouchList.h +++ b/Source/WebCore/dom/TouchList.h @@ -28,8 +28,8 @@ #include #elif ENABLE(TOUCH_EVENTS) -#include "Node.h" -#include "Touch.h" +#include +#include #include #include #include diff --git a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp index d0a3d5c048647b07772e1581c76c4eb60ecf41b0..bec324636991079264e620c0dfdaf9842ff585cd 100644 --- a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp +++ b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp @@ -35,6 +35,7 @@ #include "Pasteboard.h" #include "Settings.h" #include "SimpleRange.h" +#include "WebContentReader.h" #include "markup.h" namespace WebCore { @@ -100,6 +101,14 @@ void Editor::platformPasteFont() { } +RefPtr Editor::webContentFromPasteboard(Pasteboard& pasteboard, const SimpleRange& context, bool allowPlainText, bool& chosePlainText) +{ + WebContentReader reader(*document().frame(), context, allowPlainText); + pasteboard.read(reader); + chosePlainText = reader.madeFragmentFromPlainText(); + return reader.takeFragment(); +} + } // namespace WebCore #endif // USE(LIBWPE) diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp index 70293a7486130c23eda9198e399f4fc7a998c2b3..1ff1dc564dbe7f2ed2d35000d82bac6e2fb2cad0 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp @@ -39,6 +39,7 @@ #include "HTMLNames.h" #include "Icon.h" #include "InputTypeNames.h" +#include "InspectorInstrumentation.h" #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MIMETypeRegistry.h" @@ -162,6 +163,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) if (element()->isDisabledFormControl()) return; + bool intercept = false; + InspectorInstrumentation::runOpenPanel(element()->document().frame(), element(), &intercept); + if (intercept) + return; + if (!UserGestureIndicator::processingUserGesture()) return; diff --git a/Source/WebCore/inspector/FrameInspectorController.cpp b/Source/WebCore/inspector/FrameInspectorController.cpp index 12650ec508ee1acef286c9b862e37a73f652409f..5721af8def5099347a80e7ad31c7551dbc0be0d5 100644 --- a/Source/WebCore/inspector/FrameInspectorController.cpp +++ b/Source/WebCore/inspector/FrameInspectorController.cpp @@ -170,6 +170,12 @@ void FrameInspectorController::connectFrontend(Inspector::FrontendChannel& front UNUSED_PARAM(isAutomaticInspection); UNUSED_PARAM(immediatelyPause); + // Playwright begin + // Child frames copy parent's frontend connection. + if (!m_frame->isMainFrame() && m_frontendRouter->hasFrontends()) + return; + // Playwright end + if (auto* page = m_frame->page()) page->settings().setDeveloperExtrasEnabled(true); @@ -184,6 +190,19 @@ void FrameInspectorController::connectFrontend(Inspector::FrontendChannel& front m_injectedScriptManager->addClient(); m_agents.didCreateFrontendAndBackend(); } + + // Playwright begin + // Auto attach/enable agents for subframes. + if (!m_frame->isMainFrame()) { + LocalFrame* localMainFrame = m_frame->page()->localMainFrame(); + if (localMainFrame) { + Ref mainFrameController = localMainFrame->inspectorController(); + auto* mainFrameConsoleAgent = mainFrameController->m_instrumentingAgents->webConsoleAgent(); + if (mainFrameConsoleAgent && mainFrameConsoleAgent->enabled()) + m_instrumentingAgents->webConsoleAgent()->enable(); + } + } + // Playwright end } void FrameInspectorController::disconnectFrontend(Inspector::FrontendChannel& frontendChannel) diff --git a/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp b/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp index 1585d249dafdc13f4258ff1dde95268eeb329f93..24d21908c7a79e744aadf37a6d8ba0918f2dd7b7 100644 --- a/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp +++ b/Source/WebCore/inspector/InspectorIdentifierRegistry.cpp @@ -48,20 +48,22 @@ Protocol::Network::FrameId LegacyIdentifierRegistry::frameId(const WebCore::Fram { if (!frame) return emptyString(); - return m_frameToIdentifier.ensure(*frame, [this, frame] { - auto identifier = IdentifiersFactory::createIdentifier(); - m_identifierToFrame.set(identifier, frame); - return identifier; - }).iterator->value; + + auto identifier = String::number(frame->frameID().toUInt64()); + m_identifierToFrame.set(identifier, frame); + return identifier; } Protocol::Network::LoaderId LegacyIdentifierRegistry::loaderId(WebCore::DocumentLoader* loader) { if (!loader) return emptyString(); - return m_loaderToIdentifier.ensure(loader, [] { - return IdentifiersFactory::createIdentifier(); - }).iterator->value; + + auto navigationID = loader->navigationID(); + if (!navigationID) + return emptyString(); + + return String::number(navigationID->toUInt64()); } WebCore::LocalFrame* LegacyIdentifierRegistry::assertFrame(Protocol::ErrorString& errorString, const Protocol::Network::FrameId& frameId) @@ -74,15 +76,19 @@ WebCore::LocalFrame* LegacyIdentifierRegistry::assertFrame(Protocol::ErrorString Protocol::Network::FrameId LegacyIdentifierRegistry::takeFrame(const WebCore::Frame& frame) { - auto identifier = m_frameToIdentifier.take(frame); - if (!identifier.isNull()) - m_identifierToFrame.remove(identifier); + auto identifier = String::number(frame.frameID().toUInt64()); + if (!m_identifierToFrame.take(identifier)) + return {}; return identifier; } Protocol::Network::LoaderId LegacyIdentifierRegistry::takeLoader(WebCore::DocumentLoader& loader) { - return m_loaderToIdentifier.take(&loader); + auto navigationID = loader.navigationID(); + if (!navigationID) + return {}; + + return String::number(navigationID->toUInt64()); } } // namespace Inspector diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp index 68b5996d7ae96ce0c3f5eda869e353b448823da7..5227faf95b488a3f67e2e63e30089ba9b9cd0d5c 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -617,6 +617,12 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i pageAgent->applyUserAgentOverride(userAgent); } +void InspectorInstrumentation::applyPlatformOverrideImpl(InstrumentingAgents& instrumentingAgents, String& platform) +{ + if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->applyPlatformOverride(platform); +} + void InspectorInstrumentation::applyEmulatedMediaImpl(InstrumentingAgents& instrumentingAgents, AtomString& media) { if (CheckedPtr pageAgent = instrumentingAgents.enabledPageAgent()) @@ -700,6 +706,12 @@ void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumen consoleAgent->didFailLoading(identifier, error); // This should come AFTER resource notification, front-end relies on this. } +void InspectorInstrumentation::didReceiveMainResourceErrorImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame, const ResourceError&) +{ + if (auto* pageRuntimeAgent = instrumentingAgents.enabledPageRuntimeAgent()) + pageRuntimeAgent->didReceiveMainResourceError(frame); +} + void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents) { if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) @@ -732,20 +744,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { - if (!frame.isMainFrame()) - return; - if (CheckedPtr pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->domContentEventFired(); + pageAgent->domContentEventFired(frame); } void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame* frame) { - if (!frame || !frame->isMainFrame()) + if (!frame) return; if (CheckedPtr pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->loadEventFired(); + pageAgent->loadEventFired(*frame); } void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) @@ -825,12 +834,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins pageDOMDebuggerAgent->frameDocumentUpdated(frame); } -void InspectorInstrumentation::loaderDetachedFromFrameImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader& loader) -{ - if (CheckedPtr inspectorPageAgent = instrumentingAgents.enabledPageAgent()) - inspectorPageAgent->loaderDetachedFromFrame(loader); -} - void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { if (frame.isMainFrame()) { @@ -861,6 +864,12 @@ void InspectorInstrumentation::accessibilitySettingsDidChangeImpl(InstrumentingA inspectorPageAgent->accessibilitySettingsDidChange(); } +void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) +{ + if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) + inspectorPageAgent->didNavigateWithinPage(frame); +} + #if ENABLE(DARK_MODE_CSS) void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents) { @@ -913,6 +922,12 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru networkAgent->interceptResponse(response, identifier, WTF::move(handler)); } +void InspectorInstrumentation::setStoppingLoadingDueToProcessSwapImpl(InstrumentingAgents& instrumentingAgents, bool value) +{ + if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) + networkAgent->setStoppingLoadingDueToProcessSwap(value); +} + // JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes. static bool NODELETE isConsoleAssertMessage(MessageSource source, MessageType type) { @@ -1050,6 +1065,12 @@ void InspectorInstrumentation::consoleStopRecordingCanvasImpl(InstrumentingAgent canvasAgent->consoleStopRecordingCanvas(context); } +void InspectorInstrumentation::bindingCalledImpl(InstrumentingAgents& instrumentingAgents, JSC::JSGlobalObject* globalObject, const String& name, const String& arg) +{ + if (auto* pageRuntimeAgent = instrumentingAgents.enabledPageRuntimeAgent()) + pageRuntimeAgent->bindingCalled(globalObject, name, arg); +} + void InspectorInstrumentation::didDispatchDOMStorageEventImpl(InstrumentingAgents& instrumentingAgents, const String& key, const String& oldValue, const String& newValue, StorageType storageType, const SecurityOrigin& securityOrigin) { if (auto* domStorageAgent = instrumentingAgents.enabledDOMStorageAgent()) @@ -1347,6 +1368,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins layerTreeAgent->renderLayerDestroyed(renderLayer); } +void InspectorInstrumentation::runOpenPanelImpl(InstrumentingAgents& instrumentingAgents, HTMLInputElement* element, bool* intercept) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->runOpenPanel(element, intercept); +} + +void InspectorInstrumentation::frameAttachedImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->frameAttached(frame); +} + +bool InspectorInstrumentation::shouldBypassCSPImpl(InstrumentingAgents& instrumentingAgents) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + return pageAgent->shouldBypassCSP(); + return false; +} + +void InspectorInstrumentation::willCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->willCheckNavigationPolicy(frame); +} + +void InspectorInstrumentation::didCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame, bool cancel) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->didCheckNavigationPolicy(frame, cancel); +} + InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(WorkerOrWorkletGlobalScope& globalScope) { return globalScope.inspectorController().m_instrumentingAgents; diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index d3c1a73fd1eaa95dad8e582f8e52ed894a53a8be..24791c5f62638513dd507ff0886ae4d593523919 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -45,6 +45,7 @@ #include "LocalFrame.h" #include "NodeDocument.h" #include "Page.h" +#include "ResourceError.h" #include "ResourceLoader.h" #include "ResourceLoaderIdentifier.h" #include "StorageArea.h" @@ -79,6 +80,7 @@ class Document; class DocumentLoader; class DocumentThreadableLoader; class EventListener; +class HTMLInputElement; class HTTPHeaderMap; class InspectorTimelineAgent; class InstrumentingAgents; @@ -203,6 +205,7 @@ public: static void didRecalculateStyle(Document&); static void didScheduleStyleRecalculation(Document&); static void applyUserAgentOverride(LocalFrame&, String&); + static void applyPlatformOverride(LocalFrame&, String&); static void applyEmulatedMedia(LocalFrame&, AtomString&); static void flexibleBoxRendererBeganLayout(const RenderObject&); @@ -215,6 +218,7 @@ public: static void didReceiveData(LocalFrame*, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength); static void didFinishLoading(LocalFrame*, DocumentLoader*, ResourceLoaderIdentifier, const NetworkLoadMetrics&, ResourceLoader*); static void didFailLoading(LocalFrame*, DocumentLoader*, ResourceLoaderIdentifier, const ResourceError&); + static void didReceiveMainResourceError(LocalFrame&, const ResourceError&); static void willSendRequest(ServiceWorkerGlobalScope&, ResourceLoaderIdentifier, ResourceRequest&); static void didReceiveResourceResponse(ServiceWorkerGlobalScope&, ResourceLoaderIdentifier, const ResourceResponse&); @@ -241,11 +245,11 @@ public: static void frameDetachedFromParent(LocalFrame&); static void didCommitLoad(LocalFrame&, DocumentLoader*); static void frameDocumentUpdated(LocalFrame&); - static void loaderDetachedFromFrame(LocalFrame&, DocumentLoader&); static void frameStartedLoading(LocalFrame&); static void frameStoppedLoading(LocalFrame&); static void didCompleteRenderingFrame(LocalFrame&); static void accessibilitySettingsDidChange(Page&); + static void didNavigateWithinPage(LocalFrame&); #if ENABLE(DARK_MODE_CSS) static void defaultAppearanceDidChange(Page&); #endif @@ -256,6 +260,7 @@ public: static bool shouldInterceptResponse(const LocalFrame&, const ResourceResponse&); static void interceptRequest(ResourceLoader&, Function&&); static void interceptResponse(const LocalFrame&, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler)>&&); + static void setStoppingLoadingDueToProcessSwap(Page*, bool); static void addMessageToConsole(LocalFrame&, std::unique_ptr); static void addMessageToConsole(WorkerOrWorkletGlobalScope&, std::unique_ptr); @@ -281,6 +286,7 @@ public: static void stopProfiling(WorkerOrWorkletGlobalScope&, const String& title); static void consoleStartRecordingCanvas(CanvasRenderingContext&, JSC::JSGlobalObject&, JSC::JSObject* options); static void consoleStopRecordingCanvas(CanvasRenderingContext&); + static void bindingCalled(Page& , JSC::JSGlobalObject*, const String& name, const String& arg); static void performanceMark(ScriptExecutionContext&, const String&, std::optional); @@ -337,6 +343,12 @@ public: static void layerTreeDidChange(Page*); static void renderLayerDestroyed(Page*, const RenderLayer&); + static void runOpenPanel(LocalFrame*, HTMLInputElement*, bool*); + static void frameAttached(LocalFrame*); + static bool shouldBypassCSP(ScriptExecutionContext*); + static void willCheckNavigationPolicy(LocalFrame&); + static void didCheckNavigationPolicy(LocalFrame&, bool cancel); + static void frontendCreated(); static void frontendDeleted(); static bool hasFrontends() { return InspectorInstrumentationPublic::hasFrontends(); } @@ -434,6 +446,7 @@ private: static void didRecalculateStyleImpl(InstrumentingAgents&); static void didScheduleStyleRecalculationImpl(InstrumentingAgents&, Document&); static void applyUserAgentOverrideImpl(InstrumentingAgents&, String&); + static void applyPlatformOverrideImpl(InstrumentingAgents&, String&); static void applyEmulatedMediaImpl(InstrumentingAgents&, AtomString&); static void flexibleBoxRendererBeganLayoutImpl(InstrumentingAgents&, const RenderObject&); @@ -448,6 +461,7 @@ private: static void didReceiveDataImpl(InstrumentingAgents&, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength); static void didFinishLoadingImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, const NetworkLoadMetrics&, ResourceLoader*); static void didFailLoadingImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, const ResourceError&); + static void didReceiveMainResourceErrorImpl(InstrumentingAgents&, LocalFrame&, const ResourceError&); static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&); static void didLoadXHRSynchronouslyImpl(InstrumentingAgents&); static void scriptImportedImpl(InstrumentingAgents&, ResourceLoaderIdentifier, const String& sourceString); @@ -458,11 +472,11 @@ private: static void frameDetachedFromParentImpl(InstrumentingAgents&, LocalFrame&); static void didCommitLoadImpl(InstrumentingAgents&, LocalFrame&, DocumentLoader*); static void frameDocumentUpdatedImpl(InstrumentingAgents&, LocalFrame&); - static void loaderDetachedFromFrameImpl(InstrumentingAgents&, DocumentLoader&); static void frameStartedLoadingImpl(InstrumentingAgents&, LocalFrame&); static void didCompleteRenderingFrameImpl(InstrumentingAgents&); static void frameStoppedLoadingImpl(InstrumentingAgents&, LocalFrame&); static void accessibilitySettingsDidChangeImpl(InstrumentingAgents&); + static void didNavigateWithinPageImpl(InstrumentingAgents&, LocalFrame&); #if ENABLE(DARK_MODE_CSS) static void defaultAppearanceDidChangeImpl(InstrumentingAgents&); #endif @@ -473,6 +487,7 @@ private: static bool shouldInterceptResponseImpl(InstrumentingAgents&, const ResourceResponse&); static void interceptRequestImpl(InstrumentingAgents&, ResourceLoader&, Function&&); static void interceptResponseImpl(InstrumentingAgents&, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler)>&&); + static void setStoppingLoadingDueToProcessSwapImpl(InstrumentingAgents&, bool); static void addMessageToConsoleImpl(InstrumentingAgents&, std::unique_ptr); @@ -487,6 +502,7 @@ private: static void stopProfilingImpl(InstrumentingAgents&, const String& title); static void consoleStartRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&, JSC::JSGlobalObject&, JSC::JSObject* options); static void consoleStopRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&); + static void bindingCalledImpl(InstrumentingAgents&, JSC::JSGlobalObject*, const String& name, const String& arg); static void performanceMarkImpl(InstrumentingAgents&, const String& label, std::optional); static void didEnqueueFirstContentfulPaintImpl(InstrumentingAgents&); @@ -542,6 +558,12 @@ private: static void layerTreeDidChangeImpl(InstrumentingAgents&); static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&); + static void runOpenPanelImpl(InstrumentingAgents&, HTMLInputElement*, bool*); + static void frameAttachedImpl(InstrumentingAgents&, LocalFrame&); + static bool shouldBypassCSPImpl(InstrumentingAgents&); + static void willCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&); + static void didCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&, bool cancel); + static InstrumentingAgents& NODELETE instrumentingAgents(Page&); static InstrumentingAgents& NODELETE instrumentingAgents(const LocalFrame&); static InstrumentingAgents& NODELETE instrumentingAgents(const LocalFrameView&); @@ -1078,6 +1100,12 @@ inline void InspectorInstrumentation::applyUserAgentOverride(LocalFrame& frame, applyUserAgentOverrideImpl(instrumentingAgents(frame), userAgent); } +inline void InspectorInstrumentation::applyPlatformOverride(LocalFrame& frame, String& platform) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + applyPlatformOverrideImpl(instrumentingAgents(frame), platform); +} + inline void InspectorInstrumentation::applyEmulatedMedia(LocalFrame& frame, AtomString& media) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1176,6 +1204,12 @@ inline void InspectorInstrumentation::didFailLoading(ServiceWorkerGlobalScope& g didFailLoadingImpl(instrumentingAgents(globalScope), identifier, nullptr, error); } +inline void InspectorInstrumentation::didReceiveMainResourceError(LocalFrame& frame, const ResourceError& error) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + didReceiveMainResourceErrorImpl(instrumentingAgents(frame), frame, error); +} + inline void InspectorInstrumentation::continueAfterXFrameOptionsDenied(LocalFrame& frame, ResourceLoaderIdentifier identifier, DocumentLoader& loader, const ResourceResponse& response) { // Treat the same as didReceiveResponse. @@ -1259,12 +1293,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(LocalFrame& frame) frameDocumentUpdatedImpl(instrumentingAgents(frame), frame); } -inline void InspectorInstrumentation::loaderDetachedFromFrame(LocalFrame& frame, DocumentLoader& loader) -{ - FAST_RETURN_IF_NO_FRONTENDS(void()); - loaderDetachedFromFrameImpl(instrumentingAgents(frame), loader); -} - inline void InspectorInstrumentation::frameStartedLoading(LocalFrame& frame) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1289,6 +1317,12 @@ inline void InspectorInstrumentation::accessibilitySettingsDidChange(Page& page) accessibilitySettingsDidChangeImpl(instrumentingAgents(page)); } +inline void InspectorInstrumentation::didNavigateWithinPage(LocalFrame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + didNavigateWithinPageImpl(instrumentingAgents(frame), frame); +} + #if ENABLE(DARK_MODE_CSS) inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page) { @@ -1338,6 +1372,13 @@ inline void InspectorInstrumentation::interceptResponse(const LocalFrame& frame, interceptResponseImpl(instrumentingAgents(frame), response, identifier, WTF::move(handler)); } +inline void InspectorInstrumentation::setStoppingLoadingDueToProcessSwap(Page* page, bool value) +{ + ASSERT(InspectorInstrumentationPublic::hasFrontends()); + if (auto* agents = instrumentingAgents(page)) + setStoppingLoadingDueToProcessSwapImpl(*agents, value); +} + inline void InspectorInstrumentation::didDispatchDOMStorageEvent(Page& page, const String& key, const String& oldValue, const String& newValue, StorageType storageType, const SecurityOrigin& securityOrigin) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1681,6 +1722,11 @@ inline void InspectorInstrumentation::didEnqueueLargestContentfulPaint(ScriptExe didEnqueueLargestContentfulPaintImpl(*agents, entry); } +inline void InspectorInstrumentation::bindingCalled(Page& page, JSC::JSGlobalObject* globalObject, const String& name, const String& arg) +{ + bindingCalledImpl(instrumentingAgents(page), globalObject, name, arg); +} + inline void InspectorInstrumentation::didRequestAnimationFrame(ScriptExecutionContext& scriptExecutionContext, int callbackId) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1737,6 +1783,39 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren renderLayerDestroyedImpl(*agents, renderLayer); } +inline void InspectorInstrumentation::runOpenPanel(LocalFrame* frame, HTMLInputElement* element, bool* intercept) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + runOpenPanelImpl(instrumentingAgents(*frame), element, intercept); +} + +inline void InspectorInstrumentation::frameAttached(LocalFrame* frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + frameAttachedImpl(*agents, *frame); +} + +inline bool InspectorInstrumentation::shouldBypassCSP(ScriptExecutionContext* context) +{ + FAST_RETURN_IF_NO_FRONTENDS(false); + if (auto* agents = instrumentingAgents(context)) + return shouldBypassCSPImpl(*agents); + return false; +} + +inline void InspectorInstrumentation::willCheckNavigationPolicy(LocalFrame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + willCheckNavigationPolicyImpl(instrumentingAgents(frame), frame); +} + +inline void InspectorInstrumentation::didCheckNavigationPolicy(LocalFrame& frame, bool cancel) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + didCheckNavigationPolicyImpl(instrumentingAgents(frame), frame, cancel); +} + inline InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext* context) { return context ? instrumentingAgents(*context) : nullptr; diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp index f866893f2d6d9748b5f58ad28db0bb06398c6f48..294f450025f595b44a3e130c738291e6b45de740 100644 --- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp @@ -50,4 +50,9 @@ void InspectorInstrumentationWebKit::interceptResponseInternal(const LocalFrame& InspectorInstrumentation::interceptResponse(frame, response, identifier, WTF::move(handler)); } +void InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwapInternal(Page* page, bool value) +{ + InspectorInstrumentation::setStoppingLoadingDueToProcessSwap(page, value); +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h index 01ad196099f09a89717830cd70dded3b495cf5f5..c9d2e97c6f5f5e6b0a8f70c31af947ef2e72af8a 100644 --- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h +++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h @@ -33,6 +33,7 @@ namespace WebCore { class LocalFrame; +class Page; class ResourceLoader; class ResourceRequest; class ResourceResponse; @@ -44,12 +45,14 @@ public: static bool shouldInterceptResponse(const LocalFrame*, const ResourceResponse&); static void interceptRequest(ResourceLoader&, Function&&); static void interceptResponse(const LocalFrame*, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler)>&&); + static void setStoppingLoadingDueToProcessSwap(Page*, bool); private: static bool shouldInterceptRequestInternal(const ResourceLoader&); static bool shouldInterceptResponseInternal(const LocalFrame&, const ResourceResponse&); static void interceptRequestInternal(ResourceLoader&, Function&&); static void interceptResponseInternal(const LocalFrame&, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler)>&&); + static void setStoppingLoadingDueToProcessSwapInternal(Page*, bool); }; inline bool InspectorInstrumentationWebKit::shouldInterceptRequest(const ResourceLoader& loader) @@ -79,4 +82,10 @@ inline void InspectorInstrumentationWebKit::interceptResponse(const LocalFrame* interceptResponseInternal(*frame, response, identifier, WTF::move(handler)); } +inline void InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(Page* page, bool value) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + setStoppingLoadingDueToProcessSwapInternal(page, value); +} + } diff --git a/Source/WebCore/inspector/PageInspectorController.cpp b/Source/WebCore/inspector/PageInspectorController.cpp index 4fa92ae7d7c2f6e501eecb90691c3dca65e4482e..21dbf683927dec650570a540f0fcd5be6538afa5 100644 --- a/Source/WebCore/inspector/PageInspectorController.cpp +++ b/Source/WebCore/inspector/PageInspectorController.cpp @@ -291,6 +291,8 @@ void PageInspectorController::disconnectFrontend(FrontendChannel& frontendChanne // Unplug all instrumentations since they aren't needed now. InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get()); + + m_pauseOnStart = PauseCondition::DONT_PAUSE; } m_inspectorBackendClient->frontendCountChanged(m_frontendRouter->frontendCount()); @@ -305,6 +307,8 @@ void PageInspectorController::disconnectAllFrontends() // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow(). ASSERT(!m_inspectorFrontendClient); + m_pauseOnStart = PauseCondition::DONT_PAUSE; + if (!m_frontendRouter->hasFrontends()) return; @@ -384,8 +388,8 @@ void PageInspectorController::inspect(Node* node) if (!enabled()) return; - if (!hasRemoteFrontend()) - show(); + // HACK: Always attempt to show inspector even if there is a remote connection. + show(); CheckedRef { ensureDOMAgent() }->inspect(node); } @@ -523,4 +527,34 @@ void PageInspectorController::didComposite(LocalFrame& frame) InspectorInstrumentation::didComposite(frame); } +void PageInspectorController::pauseOnStart(PauseCondition condition) +{ + m_pauseOnStart = condition; +} + +void PageInspectorController::resumeIfPausedInNewWindow() +{ + m_pauseOnStart = PauseCondition::DONT_PAUSE; +} + +void PageInspectorController::didFinishPageCreation() +{ + if (m_pauseOnStart == PauseCondition::WHEN_CREATION_FINISHED) + runLoopWhilePaused(); +} + +void PageInspectorController::didShowPage() +{ + if (m_pauseOnStart == PauseCondition::WHEN_SHOWN) + runLoopWhilePaused(); +} + +void PageInspectorController::runLoopWhilePaused() +{ + while (m_pauseOnStart != PauseCondition::DONT_PAUSE) { + if (RunLoop::cycle() == RunLoop::CycleResult::Stop) + break; + } +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/PageInspectorController.h b/Source/WebCore/inspector/PageInspectorController.h index 1418886b19d5310d76deef334ae994ff8afd0562..6217b778b6c0bd73d7da6f9b8ef1454dda156806 100644 --- a/Source/WebCore/inspector/PageInspectorController.h +++ b/Source/WebCore/inspector/PageInspectorController.h @@ -117,6 +117,12 @@ public: WEBCORE_EXPORT void willComposite(LocalFrame&); WEBCORE_EXPORT void didComposite(LocalFrame&); + enum class PauseCondition { DONT_PAUSE, WHEN_SHOWN, WHEN_CREATION_FINISHED }; + WEBCORE_EXPORT void pauseOnStart(PauseCondition); + WEBCORE_EXPORT void resumeIfPausedInNewWindow(); + WEBCORE_EXPORT void didShowPage(); + WEBCORE_EXPORT void didFinishPageCreation(); + // Testing support. bool isUnderTest() const { return m_isUnderTest; } void setIsUnderTest(bool isUnderTest) { m_isUnderTest = isUnderTest; } @@ -153,6 +159,7 @@ private: PageAgentContext pageAgentContext(); void createLazyAgents(); + void runLoopWhilePaused(); WeakRef m_page; const Ref m_instrumentingAgents; @@ -177,6 +184,7 @@ private: bool m_isAutomaticInspection { false }; bool m_pauseAfterInitialization = { false }; bool m_didCreateLazyAgents { false }; + PauseCondition m_pauseOnStart { PauseCondition::DONT_PAUSE }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp index aee336fcc014831222e12d1806ffc0052e0daed3..88d87a57acf14678214918c5c7a44063951f8b8f 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -54,6 +54,7 @@ #include "Cookie.h" #include "CookieJar.h" #include "CustomElementRegistry.h" +#include "DirectoryFileListCreator.h" #include "DOMEditor.h" #include "DOMException.h" #include "DOMPatchSupport.h" @@ -66,10 +67,15 @@ #include "Event.h" #include "EventListener.h" #include "EventNames.h" +#include +#include "File.h" +#include "FileList.h" +#include "FloatQuad.h" #include "FrameInlines.h" #include "FrameTree.h" #include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "HTMLScriptElement.h" @@ -107,12 +113,14 @@ #include "Pasteboard.h" #include "PseudoElement.h" #include "RenderGrid.h" +#include "RenderLayer.h" #include "RenderObject.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" #include "ScriptController.h" #include "SelectorChecker.h" #include "ShadowRoot.h" +#include "SharedBuffer.h" #include "StaticNodeList.h" #include "StyleProperties.h" #include "StyleResolver.h" @@ -156,7 +164,8 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const char16_t horizontalEllipsisUTF16[] = { horizontalEllipsis, 0 }; -static std::optional parseColor(RefPtr&& colorObject) +// static +std::optional InspectorDOMAgent::parseColor(RefPtr&& colorObject) { if (!colorObject) return std::nullopt; @@ -175,7 +184,7 @@ static std::optional parseColor(RefPtr&& colorObject) static std::optional parseRequiredConfigColor(const String& fieldName, JSON::Object& configObject) { - return parseColor(configObject.getObject(fieldName)); + return InspectorDOMAgent::parseColor(configObject.getObject(fieldName)); } static Color parseOptionalConfigColor(const String& fieldName, JSON::Object& configObject) @@ -202,6 +211,20 @@ static bool parseQuad(Ref&& quadArray, FloatQuad* quad) return true; } +static void CollectQuads(Node* node, Vector& quads) +{ + Element* element = dynamicDowncast(node); + if (element && element->hasDisplayContents()) { + // display:contents elements do not render themselves, so we look into children. + for (auto& child : composedTreeChildren(*element)) + CollectQuads(&child, quads); + return; + } + RenderObject* renderer = node->renderer(); + if (renderer) + renderer->absoluteQuads(quads); +} + class RevalidateStyleAttributeTask final : public CanMakeCheckedPtr { WTF_MAKE_TZONE_ALLOCATED(RevalidateStyleAttributeTask); WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(RevalidateStyleAttributeTask); @@ -485,6 +508,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin return node.unsafeGet(); } +Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorString, std::optional&& nodeId, const String& objectId) +{ + Node* node = nullptr; + if (nodeId) { + node = assertNode(errorString, *nodeId); + } else if (!!objectId) { + node = nodeForObjectId(objectId); + if (!node) + errorString = "Missing node for given objectId"_s; + } else + errorString = "Either nodeId or objectId must be specified"_s; + return node; +} + Document* InspectorDOMAgent::assertDocument(Inspector::Protocol::ErrorString& errorString, Inspector::Protocol::DOM::NodeId nodeId) { RefPtr node = assertNode(errorString, nodeId); @@ -1602,15 +1639,7 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::o { Inspector::Protocol::ErrorString errorString; - RefPtr node; - if (nodeId) - node = assertNode(errorString, *nodeId); - else if (!!objectId) { - node = nodeForObjectId(objectId); - errorString = "Missing node for given objectId"_s; - } else - errorString = "Either nodeId or objectId must be specified"_s; - + RefPtr node = assertNode(errorString, WTF::move(nodeId), objectId); if (!node) return makeUnexpected(errorString); @@ -1861,15 +1890,159 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::setInspectedNode(Ins return { }; } -Inspector::Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(Inspector::Protocol::DOM::NodeId nodeId, const String& objectGroup) +static FloatPoint contentsToRootView(LocalFrameView& containingView, const FloatPoint& point) +{ + return containingView.convertToRootView(point - toFloatSize(containingView.documentScrollPositionRelativeToViewOrigin())); +} + +static void frameQuadToViewport(LocalFrameView& containingView, FloatQuad& quad, Page& inspectedPage) +{ + float pageScaleFactor = inspectedPage.pageScaleFactor(); + auto mainFrame = inspectedPage.localMainFrame(); + float scale = pageScaleFactor * mainFrame->pageZoomFactor(); + + // Return css (not dip) coordinates by scaling back. + quad.setP1(contentsToRootView(containingView, quad.p1()).scaled(1 / scale)); + quad.setP2(contentsToRootView(containingView, quad.p2()).scaled(1 / scale)); + quad.setP3(contentsToRootView(containingView, quad.p3()).scaled(1 / scale)); + quad.setP4(contentsToRootView(containingView, quad.p4()).scaled(1 / scale)); +} + +static Ref 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 Ref> buildArrayOfQuads(const Vector& quads) +{ + auto result = JSON::ArrayOf::create(); + for (const auto& quad : quads) + result->addItem(buildObjectForQuad(quad)); + return result; +} + +Inspector::Protocol::ErrorStringOr> InspectorDOMAgent::describeNode(const String& objectId) +{ + Node* node = nodeForObjectId(objectId); + if (!node) + return makeUnexpected("Node not found"_s); + + auto* pageAgent = m_instrumentingAgents->enabledPageAgent(); + if (!pageAgent) + return makeUnexpected("Page agent must be enabled"_s); + + String ownerFrameId; + String frameId = pageAgent->frameId(node->document().frame()); + if (!frameId.isEmpty()) + ownerFrameId = frameId; + + String contentFrameId; + if (is(*node)) { + const auto& frameOwner = downcast(*node); + // TODO(playwright): Unnecessary downcast to LocalFrame? + String frameId = pageAgent->frameId(dynamicDowncast(frameOwner.contentFrame())); + if (!frameId.isEmpty()) + contentFrameId = frameId; + } + + return { { contentFrameId, ownerFrameId } }; +} + +Inspector::Protocol::ErrorStringOr InspectorDOMAgent::scrollIntoViewIfNeeded(const String& objectId, RefPtr&& rect) +{ + Node* node = nodeForObjectId(objectId); + if (!node) + return makeUnexpected("Node not found"_s); + + m_inspectedPage->isolatedUpdateRendering(); + if (!node->isConnected()) + return makeUnexpected("Node is detached from document"_s); + + RenderObject* renderer = node->renderer(); + auto* containerNode = dynamicDowncast(*node); + if (!renderer && containerNode) { + // Find the first descendant with a renderer, to account for + // containers without a renderer like display:contents elements. + for (auto& descendant : composedTreeDescendants(*containerNode)) { + renderer = descendant.renderer(); + if (renderer) + break; + } + } + if (!renderer) + return makeUnexpected("Node does not have a layout object"_s); + + bool insideFixed = false; + LayoutRect absoluteBounds = renderer->absoluteBoundingBoxRect(true, &insideFixed); + if (rect) { + std::optional x = rect->getDouble("x"_s); + std::optional y = rect->getDouble("y"_s); + std::optional width = rect->getDouble("width"_s); + std::optional height = rect->getDouble("height"_s); + if (!x || !y || !width || !height) + return makeUnexpected("Malformed rect"_s); + + absoluteBounds.setX(absoluteBounds.x() + LayoutUnit(*x)); + absoluteBounds.setY(absoluteBounds.y() + LayoutUnit(*y)); + absoluteBounds.setWidth(LayoutUnit(std::max(*width, 1.0))); + absoluteBounds.setHeight(LayoutUnit(std::max(*height, 1.0))); + } + ScrollAlignment alignment = ScrollAlignment::alignCenterIfNeeded; + alignment.m_enableLegacyHorizontalVisibilityThreshold = false; // Disable RenderLayer minium horizontal scroll threshold. + LocalFrameView::scrollRectToVisible(absoluteBounds, *renderer, insideFixed, { SelectionRevealMode::Reveal, alignment, alignment, ShouldAllowCrossOriginScrolling::Yes, ScrollBehavior::Instant }); + return { }; +} + +Inspector::Protocol::ErrorStringOr>> InspectorDOMAgent::getContentQuads(const String& objectId) +{ + Node* node = nodeForObjectId(objectId); + if (!node) + return makeUnexpected("Node not found"_s); + + // Ensure quads are up to date. + m_inspectedPage->isolatedUpdateRendering(); + + LocalFrameView* containingView = node->document().view(); + if (!containingView) + return makeUnexpected("Internal error: no containing view"_s); + + Vector quads; + CollectQuads(node, quads); + for (auto& quad : quads) + frameQuadToViewport(*containingView, quad, m_inspectedPage.get()); + return buildArrayOfQuads(quads); +} + +Inspector::Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(std::optional&& nodeId, const String& objectId, const Inspector::Protocol::Network::FrameId& frameId, std::optional&& contextId, const String& objectGroup) { Inspector::Protocol::ErrorString errorString; + RefPtr node = nullptr; + if (!!frameId) { + auto* pageAgent = m_instrumentingAgents->enabledPageAgent(); + if (!pageAgent) + return makeUnexpected("Page domain must be enabled"_s); - RefPtr node = assertNode(errorString, nodeId); + auto* frame = pageAgent->assertFrame(errorString, frameId); + if (!frame) + return makeUnexpected(errorString); + + node = frame->ownerElement(); + } else { + node = assertNode(errorString, WTF::move(nodeId), objectId); + } if (!node) return makeUnexpected(errorString); - auto object = resolveNode(node.get(), objectGroup); + auto object = resolveNode(node.get(), objectGroup, WTF::move(contextId)); if (!object) return makeUnexpected("Missing injected script for given nodeId"_s); @@ -3133,7 +3306,7 @@ Inspector::Protocol::ErrorStringOr InspectorDO return makeUnexpected("Missing node for given path"_s); } -RefPtr InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) +RefPtr InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup, std::optional&& contextId) { RefPtr document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) @@ -3142,12 +3315,18 @@ RefPtr InspectorDOMAgent::resolveNod if (!frame) return nullptr; - auto& globalObject = mainWorldGlobalObject(*frame); - auto injectedScript = m_injectedScriptManager->injectedScriptFor(&globalObject); + InjectedScript injectedScript; + if (contextId) { + injectedScript = m_injectedScriptManager->injectedScriptForId(*contextId); + } else { + auto& globalObject = mainWorldGlobalObject(*frame); + injectedScript = m_injectedScriptManager->injectedScriptFor(&globalObject); + } + if (injectedScript.hasNoValue()) return nullptr; - return injectedScript.wrapObject(nodeAsScriptValue(globalObject, node), objectGroup); + return injectedScript.wrapObject(nodeAsScriptValue(*injectedScript.globalObject(), node), objectGroup); } Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value) @@ -3301,4 +3480,53 @@ Inspector::Protocol::ErrorStringOr> In #endif } +void InspectorDOMAgent::setInputFiles(const String& objectId, Ref&& paths, Ref&& callback) { + InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) { + callback->sendFailure("Can not find element's context for given id"_s); + return; + } + + Node* node = scriptValueAsNode(injectedScript.findObjectById(objectId)); + if (!node) { + callback->sendFailure("Can not find element for given id"_s); + return; + } + + if (node->nodeType() != NodeType::Element || node->nodeName() != "INPUT"_s) { + callback->sendFailure("Not an input node"_s); + return; + } + + HTMLInputElement* element = static_cast(node); + Vector> fileObjects; + if (element->hasAttributeWithoutSynchronization(webkitdirectoryAttr)) { + auto directoryFileListCreator = DirectoryFileListCreator::create([element = RefPtr { element }, callback = WTF::move(callback)](Ref&& fileList) mutable { + ASSERT(isMainThread()); + element->setFiles(WTF::move(fileList)); + callback->sendSuccess(); + }); + Vector fileChooserFiles; + for (size_t i = 0; i < paths->length(); ++i) { + fileChooserFiles.append(FileChooserFileInfo { paths->get(i)->asString(), nullString(), { } }); + } + directoryFileListCreator->start(m_document.get(), fileChooserFiles); + } else { + for (unsigned i = 0; i < paths->length(); ++i) { + RefPtr item = paths->get(i); + String path = item->asString(); + if (path.isEmpty()) { + callback->sendFailure("Invalid file path"_s); + return; + } + + ScriptExecutionContext* context = element->scriptExecutionContext(); + fileObjects.append(File::create(context, path)); + } + RefPtr fileList = FileList::create(WTF::move(fileObjects)); + element->setFiles(WTF::move(fileList)); + callback->sendSuccess(); + } +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h index 8f83cc5eaca550bbcea167c98b944f704d9a9cb1..2f655b6534f1428a23907e1cada99c244a9a2c98 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -62,6 +62,7 @@ namespace WebCore { class AXCoreObject; class CharacterData; +class Color; class DOMEditor; class Document; class Element; @@ -98,6 +99,7 @@ public: static String toErrorString(Exception&&); static String documentURLString(Document*); + static std::optional parseColor(RefPtr&&); // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. @@ -143,7 +145,7 @@ public: Inspector::Protocol::ErrorStringOr> performSearch(const String& query, RefPtr&& nodeIds, std::optional&& caseSensitive); Inspector::Protocol::ErrorStringOr>> getSearchResults(const String& searchId, int fromIndex, int toIndex); Inspector::Protocol::ErrorStringOr discardSearchResults(const String& searchId); - Inspector::Protocol::ErrorStringOr> resolveNode(Inspector::Protocol::DOM::NodeId, const String& objectGroup); + Inspector::Protocol::ErrorStringOr> resolveNode(std::optional&& nodeId, const String& objectId, const Inspector::Protocol::Network::FrameId& frameId, std::optional&& contextId, const String& objectGroup); Inspector::Protocol::ErrorStringOr>> getAttributes(Inspector::Protocol::DOM::NodeId); #if PLATFORM(IOS_FAMILY) Inspector::Protocol::ErrorStringOr setInspectModeEnabled(bool, RefPtr&& highlightConfig, RefPtr&& gridOverlayConfig, RefPtr&& flexOverlayConfig); @@ -180,6 +182,10 @@ public: Inspector::Protocol::ErrorStringOr setInspectedNode(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::ErrorStringOr setAllowEditingUserAgentShadowTrees(bool); Inspector::Protocol::ErrorStringOr> getMediaStats(Inspector::Protocol::DOM::NodeId); + Inspector::Protocol::ErrorStringOr> describeNode(const String& objectId); + Inspector::Protocol::ErrorStringOr scrollIntoViewIfNeeded(const String& objectId, RefPtr&& rect); + Inspector::Protocol::ErrorStringOr>> getContentQuads(const String& objectId); + void setInputFiles(const String& objectId, Ref&& paths, Ref&& callback); // InspectorInstrumentation Inspector::Protocol::DOM::NodeId identifierForNode(Node&); @@ -221,7 +227,7 @@ public: Node* nodeForId(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::DOM::NodeId boundNodeId(const Node*); - RefPtr resolveNode(Node*, const String& objectGroup); + RefPtr resolveNode(Node*, const String& objectGroup, std::optional&& contextId); bool handleMousePress(); void mouseDidMoveOverElement(const HitTestResult&, OptionSet); void inspect(Node*); @@ -233,12 +239,15 @@ public: void reset(); Node* assertNode(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); + Node* assertNode(Inspector::Protocol::ErrorString&, std::optional&& nodeId, const String& objectId); Element* assertElement(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); Document* assertDocument(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); RefPtr breakpointForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture); Inspector::Protocol::DOM::EventListenerId idForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture); + Node* nodeForObjectId(const Inspector::Protocol::Runtime::RemoteObjectId&); + private: #if ENABLE(VIDEO) void mediaMetricsTimerFired(); @@ -268,7 +277,6 @@ private: void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf&); RefPtr nodeForPath(const String& path); - Node* nodeForObjectId(const Inspector::Protocol::Runtime::RemoteObjectId&); void discardBindings(); diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp index dd164a0c7161396ee21bc3e1e4f7889f5ddbb770..58a528c6ac0efea4b383688d5369606013282075 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp @@ -62,6 +62,7 @@ #include "LocalFrame.h" #include "MIMETypeRegistry.h" #include "MemoryCache.h" +#include "NetworkStateNotifier.h" #include "Page.h" #include "PlatformStrategies.h" #include "ProgressTracker.h" @@ -275,8 +276,8 @@ static Ref buildObjectForResourceRequest( .release(); if (request.httpBody() && !request.httpBody()->isEmpty()) { - auto bytes = request.httpBody()->flatten(); - requestObject->setPostData(String::fromUTF8WithLatin1Fallback(bytes.span())); + Vector bytes = request.httpBody()->flatten(); + requestObject->setPostData(base64EncodeToString(bytes)); } if (resourceLoader) { @@ -328,6 +329,8 @@ RefPtr InspectorNetworkAgent::buildObjec .setSource(responseSource(response.source())) .release(); + responseObject->setRequestHeaders(buildObjectForHeaders(response.m_httpRequestHeaderFields)); + if (resourceLoader) { auto* metrics = response.deprecatedNetworkLoadMetricsOrNull(); responseObject->setTiming(buildObjectForTiming(metrics ? *metrics : NetworkLoadMetrics::emptyMetrics(), *resourceLoader)); @@ -522,7 +525,7 @@ void InspectorNetworkAgent::didReceiveResponse(ResourceLoaderIdentifier identifi // 'Raw' is used for loading worker scripts, and those should stay as 'Script' and not change to 'XHR' type. if (type != newType && newType != ResourceType::XHR && newType != ResourceType::Other) type = newType; - + // FIXME: 304 Not Modified responses for XHR/Fetch do not have all their information from the cache. if (isNotModified && (type == ResourceType::XHR || type == ResourceType::Fetch) && (!cachedResource || !cachedResource->encodedSize())) { if (auto previousResourceData = m_resourcesData->dataForURL(response.url().string())) { @@ -533,12 +536,12 @@ void InspectorNetworkAgent::didReceiveResponse(ResourceLoaderIdentifier identifi m_resourcesData->maybeAddResourceData(requestId, buffer); }); } - + resourceResponse->setString("mimeType"_s, previousResourceData->mimeType()); - + resourceResponse->setInteger("status"_s, previousResourceData->httpStatusCode()); resourceResponse->setString("statusText"_s, previousResourceData->httpStatusText()); - + resourceResponse->setString("source"_s, Inspector::Protocol::Helpers::getEnumConstantValue(Inspector::Protocol::Network::Response::Source::DiskCache)); } } @@ -617,6 +620,9 @@ void InspectorNetworkAgent::didFailLoading(ResourceLoaderIdentifier identifier, String requestId = IdentifiersFactory::requestId(identifier.toUInt64()); if (loader && m_resourcesData->resourceType(requestId) == ResourceType::Document) { + if (m_stoppingLoadingDueToProcessSwap) + return; + auto* frame = loader->frame(); if (frame && frame->loader().documentLoader() && frame->document()) { m_resourcesData->addResourceSharedBuffer(requestId, @@ -846,6 +852,7 @@ Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::disable() Ref { m_instrumentingAgents.get() }->setEnabledNetworkAgent(nullptr); m_resourcesData->clear(); m_extraRequestHeaders.clear(); + m_stoppingLoadingDueToProcessSwap = false; continuePendingRequests(); continuePendingResponses(); @@ -904,6 +911,7 @@ void InspectorNetworkAgent::continuePendingResponses() Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::setExtraHTTPHeaders(Ref&& headers) { + m_extraRequestHeaders.clear(); for (auto& entry : headers.get()) { auto stringValue = entry.value->asString(); if (!!stringValue) @@ -1158,6 +1166,11 @@ void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response, m_frontendDispatcher->responseIntercepted(requestId, resourceResponse.releaseNonNull()); } +void InspectorNetworkAgent::setStoppingLoadingDueToProcessSwap(bool stopping) +{ + m_stoppingLoadingDueToProcessSwap = stopping; +} + Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::interceptContinue(const Inspector::Protocol::Network::RequestId& requestId, Inspector::Protocol::Network::NetworkStage networkStage) { switch (networkStage) { @@ -1187,6 +1200,9 @@ Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::interceptWithReq return makeUnexpected("Missing pending intercept request for given requestId"_s); auto& loader = *pendingRequest->m_loader; + if (loader.reachedTerminalState()) + return makeUnexpected("Unable to intercept request, it has already been processed"_s); + ResourceRequest request = loader.request(); if (!!url) request.setURL(URL({ }, url)); @@ -1282,13 +1298,22 @@ Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::interceptRequest response.setHTTPStatusCode(status); response.setHTTPStatusText(String { statusText }); HTTPHeaderMap explicitHeaders; + String setCookieValue; for (auto& header : headers.get()) { auto headerValue = header.value->asString(); - if (!!headerValue) + if (equalIgnoringASCIICase(header.key, "Set-Cookie"_s)) + setCookieValue = headerValue; + else if (!!headerValue) explicitHeaders.add(header.key, headerValue); + } response.setHTTPHeaderFields(WTF::move(explicitHeaders)); response.setHTTPHeaderField(HTTPHeaderName::ContentType, response.mimeType()); + + auto* frame = loader->frame(); + if (!setCookieValue.isEmpty() && frame && frame->page()) + frame->page()->cookieJar().setCookieFromResponse(*loader.get(), setCookieValue); + loader->didReceiveResponse(WTF::move(response), [loader, buffer = data.releaseNonNull()]() { if (loader->reachedTerminalState()) return; @@ -1352,6 +1377,12 @@ Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::setEmulatedCondi #endif // ENABLE(INSPECTOR_NETWORK_THROTTLING) +Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::setEmulateOfflineState(bool offline) +{ + platformStrategies()->loaderStrategy()->setEmulateOfflineState(offline); + return { }; +} + static Ref buildObjectForSearchResult(const Inspector::Protocol::Network::RequestId& requestId, const Inspector::Protocol::Network::FrameId& frameId, const String& url, int matchesCount) { auto searchResult = Inspector::Protocol::Page::SearchResult::create() diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h index 5875ac43836d8cbd9b40e82ebf964a34eb65254f..175bd8649c496232fed546ccbb12102722d8608b 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h @@ -35,6 +35,8 @@ #include "InspectorPageAgent.h" #include "InspectorWebAgentBase.h" #include "NetworkResourcesData.h" +#include "ResourceError.h" +#include "SharedBuffer.h" #include "WebSocket.h" #include #include @@ -105,6 +107,7 @@ public: #if ENABLE(INSPECTOR_NETWORK_THROTTLING) Inspector::Protocol::ErrorStringOr setEmulatedConditions(std::optional&& bytesPerSecondLimit) final; #endif + Inspector::Protocol::ErrorStringOr setEmulateOfflineState(bool offline) final; // InspectorInstrumentation void NODELETE willRecalculateStyle(); @@ -136,6 +139,7 @@ public: bool shouldInterceptResponse(const ResourceResponse&); void interceptResponse(const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler)>&&); void interceptRequest(ResourceLoader&, Function&&); + void setStoppingLoadingDueToProcessSwap(bool); void searchOtherRequests(const JSC::Yarr::RegularExpression&, Ref>&); void searchInRequest(Inspector::Protocol::ErrorString&, const Inspector::Protocol::Network::RequestId&, const String& query, bool caseSensitive, bool isRegex, RefPtr>&); @@ -192,6 +196,7 @@ private: bool m_loadingXHRSynchronously { false }; bool m_interceptionEnabled { false }; bool m_clearResourceDataOnNavigate { true }; + bool m_stoppingLoadingDueToProcessSwap { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp index 6bb8dd192ae2fedac06e2b35bb9c6711950d5b23..5fb689a1a62b8fd687b73c590236ac11d5e1fb03 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 "BackForwardController.h" #include "CachedResource.h" #include "Cookie.h" #include "CookieJar.h" @@ -39,14 +40,17 @@ #include "DocumentLoader.h" #include "DocumentResourceLoader.h" #include "DocumentView.h" +#include "Editor.h" #include "ElementInlines.h" #include "EventTargetInlines.h" +#include "FocusController.h" #include "ForcedAccessibilityValue.h" #include "FrameInlines.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" #include "FrameSnapshotting.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" #include "ImageUtilities.h" @@ -57,30 +61,38 @@ #include "InspectorOverlay.h" #include "InspectorResourceUtilities.h" #include "InstrumentingAgents.h" +#include "JSDOMWindowCustom.h" #include "LocalFrame.h" #include "LocalFrameView.h" #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "Page.h" #include "PageInspectorController.h" +#include "PlatformScreen.h" #include "RenderObjectInlines.h" #include "RenderTheme.h" #include "ScriptController.h" #include "ScriptSourceCode.h" +#include "ScrollingCoordinator.h" #include "SecurityOrigin.h" #include "Settings.h" #include "ShouldPartitionCookie.h" #include "StyleScope.h" #include "Theme.h" +#include "TypingCommand.h" #include #include "UserGestureIndicator.h" #include #include +#include #include +#include #include +#include #include #include #include +#include #include #if ENABLE(APPLICATION_MANIFEST) @@ -102,6 +114,11 @@ using namespace Inspector; WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorPageAgent); +static UncheckedKeyHashMap>& createdUserWorlds() { + static NeverDestroyed>> nameToWorld; + return nameToWorld; +} + InspectorOverlay& InspectorPageAgent::overlay() const { return m_overlay.get(); @@ -112,6 +129,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorBacke , m_frontendDispatcher(makeUniqueRef(context.frontendRouter)) , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this)) , m_inspectedPage(context.inspectedPage) + , m_injectedScriptManager(context.injectedScriptManager) , m_client(client) , m_overlay(overlay) { @@ -142,12 +160,20 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::enable() defaultUserPreferencesDidChange(); + if (!createdUserWorlds().isEmpty()) { + Vector worlds; + for (const auto& world : createdUserWorlds().values()) + worlds.append(world.ptr()); + ensureUserWorldsExistInAllFrames(worlds); + } return { }; } Inspector::Protocol::ErrorStringOr InspectorPageAgent::disable() { Ref { m_instrumentingAgents.get() }->setEnabledPageAgent(nullptr); + m_interceptFileChooserDialog = false; + m_bypassCSP = false; std::ignore = setShowPaintRects(false); #if !PLATFORM(IOS_FAMILY) @@ -200,6 +226,22 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::reload(std::optiona return { }; } +Inspector::Protocol::ErrorStringOr InspectorPageAgent::goBack() +{ + if (!m_inspectedPage->backForward().goBack()) + return makeUnexpected("Failed to go back"_s); + + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::goForward() +{ + if (!m_inspectedPage->backForward().goForward()) + return makeUnexpected("Failed to go forward"_s); + + return { }; +} + Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideUserAgent(const String& value) { m_userAgentOverride = value; @@ -207,6 +249,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideUserAgent(c return { }; } +Inspector::Protocol::ErrorStringOr InspectorPageAgent::overridePlatform(const String& value) +{ + m_platformOverride = value; + + return { }; +} + Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Inspector::Protocol::Page::Setting setting, std::optional&& value) { auto& inspectedPageSettings = m_inspectedPage->settings(); @@ -220,6 +269,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value); return { }; +#if ENABLE(DEVICE_ORIENTATION) + case Inspector::Protocol::Page::Setting::DeviceOrientationEventEnabled: + inspectedPageSettings.setDeviceOrientationEventEnabled(value.value_or(false)); + return { }; +#endif + case Inspector::Protocol::Page::Setting::ICECandidateFilteringEnabled: inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value); return { }; @@ -246,6 +301,39 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins m_client->setDeveloperPreferenceOverride(InspectorBackendClient::DeveloperPreference::NeedsSiteSpecificQuirks, value); return { }; +#if ENABLE(NOTIFICATIONS) + case Inspector::Protocol::Page::Setting::NotificationsEnabled: + inspectedPageSettings.setNotificationsEnabled(value.value_or(false)); + return { }; +#endif + +#if ENABLE(FULLSCREEN_API) + case Inspector::Protocol::Page::Setting::FullScreenEnabled: + inspectedPageSettings.setFullScreenEnabled(value.value_or(false)); + return { }; +#endif + + case Inspector::Protocol::Page::Setting::InputTypeMonthEnabled: + inspectedPageSettings.setInputTypeMonthEnabled(value.value_or(false)); + return { }; + + case Inspector::Protocol::Page::Setting::InputTypeWeekEnabled: + inspectedPageSettings.setInputTypeWeekEnabled(value.value_or(false)); + return { }; + + case Inspector::Protocol::Page::Setting::FixedBackgroundsPaintRelativeToDocument: + // Enable this setting similar to iOS to ensure scrolling works with + // `background-attachment: fixed`. + // See https://github.com/microsoft/playwright/issues/31551. + inspectedPageSettings.setFixedBackgroundsPaintRelativeToDocument(value.value_or(false)); + return { }; + +#if ENABLE(POINTER_LOCK) + case Inspector::Protocol::Page::Setting::PointerLockEnabled: + inspectedPageSettings.setPointerLockEnabled(value.value_or(false)); + return { }; +#endif + case Inspector::Protocol::Page::Setting::ScriptEnabled: inspectedPageSettings.setScriptEnabledInspectorOverride(value); return { }; @@ -258,6 +346,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setShowRepaintCounterInspectorOverride(value); return { }; +#if ENABLE(MEDIA_STREAM) + case Inspector::Protocol::Page::Setting::SpeechRecognitionEnabled: + inspectedPageSettings.setSpeechRecognitionEnabled(value.value_or(false)); + return { }; +#endif + case Inspector::Protocol::Page::Setting::WebSecurityEnabled: inspectedPageSettings.setWebSecurityEnabledInspectorOverride(value); return { }; @@ -670,15 +764,16 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setShowPaintRects(b return { }; } -void InspectorPageAgent::domContentEventFired() +void InspectorPageAgent::domContentEventFired(LocalFrame& frame) { - m_isFirstLayoutAfterOnLoad = true; - m_frontendDispatcher->domContentEventFired(timestamp()); + if (frame.isMainFrame()) + m_isFirstLayoutAfterOnLoad = true; + m_frontendDispatcher->domContentEventFired(timestamp(), frameId(&frame)); } -void InspectorPageAgent::loadEventFired() +void InspectorPageAgent::loadEventFired(LocalFrame& frame) { - m_frontendDispatcher->loadEventFired(timestamp()); + m_frontendDispatcher->loadEventFired(timestamp(), frameId(&frame)); } void InspectorPageAgent::frameNavigated(LocalFrame& frame) @@ -686,6 +781,22 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame) m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } +String InspectorPageAgent::serializeFrameID(FrameIdentifier frameID) +{ + return makeString(frameID.toUInt64()); +} + +std::optional InspectorPageAgent::parseFrameID(String frameID) +{ + if (!frameID.containsOnlyASCII()) + return std::nullopt; + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + uint64_t frameIDNumber = strtoull(frameID.ascii().data(), 0, 10); +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + return WebCore::FrameIdentifier(frameIDNumber); +} + void InspectorPageAgent::frameDetached(LocalFrame& frame) { auto identifier = m_inspectedPage->inspectorController().identifierRegistry().takeFrame(frame); @@ -758,6 +869,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() m_frontendDispatcher->defaultUserPreferencesDidChange(WTF::move(defaultUserPreferences)); } +void InspectorPageAgent::didNavigateWithinPage(LocalFrame& frame) +{ + String url = frame.document()->url().string(); + m_frontendDispatcher->navigatedWithinDocument(frameId(&frame), url); +} + #if ENABLE(DARK_MODE_CSS) void InspectorPageAgent::defaultAppearanceDidChange() { @@ -771,6 +888,9 @@ void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapp return; if (m_bootstrapScript.isEmpty()) + return; + + if (m_ignoreDidClearWindowObject) return; frame.script().evaluateIgnoringException(ScriptSourceCode(m_bootstrapScript, JSC::SourceTaintedOrigin::Untainted, URL { "web-inspector://bootstrap.js"_str })); @@ -818,6 +938,51 @@ void InspectorPageAgent::didRecalculateStyle() protect(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& globalObject = mainWorldGlobalObject(*frame); + auto injectedScript = m_injectedScriptManager.injectedScriptFor(&globalObject); + if (injectedScript.hasNoValue()) + return; + + auto object = injectedScript.wrapObject(InspectorDOMAgent::nodeAsScriptValue(globalObject, element), WTF::String()); + if (!object) + return; + + m_frontendDispatcher->fileChooserOpened(frameId(frame), object.releaseNonNull()); +} + +void InspectorPageAgent::frameAttached(LocalFrame& frame) +{ + String parentFrameId = frameId(dynamicDowncast(frame.tree().parent())); + m_frontendDispatcher->frameAttached(frameId(&frame), parentFrameId); +} + +bool InspectorPageAgent::shouldBypassCSP() +{ + return m_bypassCSP; +} + +void InspectorPageAgent::willCheckNavigationPolicy(LocalFrame& frame) +{ + m_frontendDispatcher->willCheckNavigationPolicy(frameId(&frame)); +} + +void InspectorPageAgent::didCheckNavigationPolicy(LocalFrame& frame, bool cancel) +{ + m_frontendDispatcher->didCheckNavigationPolicy(frameId(&frame), cancel); +} + Ref InspectorPageAgent::buildObjectForFrame(LocalFrame* frame) { ASSERT_ARG(frame, frame); @@ -911,6 +1076,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent) userAgent = m_userAgentOverride; } +void InspectorPageAgent::applyPlatformOverride(String& platform) +{ + if (!m_platformOverride.isEmpty()) + platform = m_platformOverride; +} + void InspectorPageAgent::applyEmulatedMedia(AtomString& media) { if (!m_emulatedMedia.isEmpty()) @@ -926,7 +1097,7 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Insp RefPtr node = domAgent->assertNode(errorString, nodeId); if (!node) return makeUnexpected(errorString); - + RefPtr localMainFrame = m_inspectedPage->localMainFrame(); if (!localMainFrame) return makeUnexpected("Main frame isn't local"_s); @@ -937,11 +1108,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Insp return encodeDataURL(WTF::move(snapshot), "image/png"_s); } -Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem coordinateSystem) +Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem coordinateSystem, std::optional&& omitDeviceScaleFactor) { SnapshotOptions options { { }, PixelFormat::BGRA8, DestinationColorSpace::SRGB() }; if (coordinateSystem == Inspector::Protocol::Page::CoordinateSystem::Viewport) options.flags.add(SnapshotFlags::InViewCoordinates); + if (omitDeviceScaleFactor.has_value() && *omitDeviceScaleFactor) + options.flags.add(SnapshotFlags::OmitDeviceScaleFactor); IntRect rectangle(x, y, width, height); RefPtr localMainFrame = m_inspectedPage->localMainFrame(); @@ -954,6 +1127,43 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int return encodeDataURL(WTF::move(snapshot), "image/png"_s); } +Inspector::Protocol::ErrorStringOr InspectorPageAgent::setForcedColors(std::optional&& forcedColors) +{ + if (!forcedColors) { + m_inspectedPage->setUseForcedColorsOverride(std::nullopt); + return { }; + } + + switch (*forcedColors) { + case Inspector::Protocol::Page::ForcedColors::Active: + m_inspectedPage->setUseForcedColorsOverride(true); + return { }; + case Inspector::Protocol::Page::ForcedColors::None: + m_inspectedPage->setUseForcedColorsOverride(false); + return { }; + } + + ASSERT_NOT_REACHED(); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::setTimeZone(const String& timeZone) +{ + bool success = WTF::setTimeZoneOverride(timeZone); + if (!success) + return makeUnexpected(makeString("Invalid time zone "_s, timeZone)); + + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::setTouchEmulationEnabled(bool enabled) +{ + setScreenHasTouchDeviceOverride(enabled); + m_inspectedPage->settings().setTouchEventDOMAttributesEnabled(enabled); + return { }; +} + + #if ENABLE(WEB_ARCHIVE) && USE(CF) Inspector::Protocol::ErrorStringOr InspectorPageAgent::archive() { @@ -970,7 +1180,6 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::archive() } #endif -#if !PLATFORM(COCOA) Inspector::Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::optional&& width, std::optional&& height) { if (width.has_value() != height.has_value()) @@ -988,6 +1197,86 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverri localMainFrame->setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); return { }; } -#endif + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::insertText(const String& text) +{ + UserGestureIndicator indicator { IsProcessingUserGesture::Yes }; + RefPtr frame = m_inspectedPage->focusController().focusedOrMainFrame(); + if (!frame) + return { }; + + if (frame->editor().hasComposition()) { + frame->editor().confirmComposition(text); + } else { + Document* focusedDocument = frame->document(); + TypingCommand::insertText(*focusedDocument, text, nullptr, { }); + } + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::setInterceptFileChooserDialog(bool enabled) +{ + m_interceptFileChooserDialog = enabled; + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::setDefaultBackgroundColorOverride(RefPtr&& color) +{ + auto* localFrame = dynamicDowncast(m_inspectedPage->mainFrame()); + LocalFrameView* view = localFrame ? localFrame->view() : nullptr; + if (!view) + return makeUnexpected("Internal error: No frame view to set color two"_s); + + if (!color) { + view->updateBackgroundRecursively(std::optional()); + return { }; + } + + view->updateBackgroundRecursively(InspectorDOMAgent::parseColor(WTF::move(color))); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::createUserWorld(const String& name) +{ + if (createdUserWorlds().contains(name)) + return makeUnexpected("World with the given name already exists"_s); + + Ref world = ScriptController::createWorld(name, ScriptController::WorldType::User); + ensureUserWorldsExistInAllFrames({world.ptr()}); + createdUserWorlds().set(name, WTF::move(world)); + return { }; +} + +void InspectorPageAgent::ensureUserWorldsExistInAllFrames(const Vector& worlds) +{ + for (Frame* frame = &m_inspectedPage->mainFrame(); frame; frame = frame->tree().traverseNext()) { + auto* localFrame = dynamicDowncast(frame); + if (!localFrame) + continue; + for (auto* world : worlds) + localFrame->windowProxy().jsWindowProxy(*world)->window(); + } +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::setBypassCSP(bool enabled) +{ + m_bypassCSP = enabled; + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::crash() +{ + WTFCrash(); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPageAgent::updateScrollingState() +{ + auto* scrollingCoordinator = m_inspectedPage->scrollingCoordinator(); + if (!scrollingCoordinator) + return {}; + scrollingCoordinator->commitTreeStateIfNeeded(); + return {}; +} } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h index 97c3cf09961f5c5ea7ede70d35755639fc66a3df..d5aabfbb3062f6037415bb3e136d3d7cebdfbbfd 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h @@ -43,10 +43,12 @@ #include #include #include +#include #include namespace Inspector { enum class ResourceType; +class InjectedScriptManager; } namespace WebCore { @@ -54,6 +56,7 @@ namespace WebCore { class DOMWrapperWorld; class DocumentLoader; class Frame; +class HTMLInputElement; class InspectorOverlay; class LocalFrame; class Page; @@ -68,6 +71,9 @@ public: InspectorPageAgent(PageAgentContext&, InspectorBackendClient*, InspectorOverlay&); ~InspectorPageAgent(); + WEBCORE_EXPORT static String serializeFrameID(FrameIdentifier frameID); + WEBCORE_EXPORT static std::optional parseFrameID(String frameID); + // InspectorAgentBase void didCreateFrontendAndBackend(); void willDestroyFrontendAndBackend(Inspector::DisconnectReason); @@ -76,7 +82,10 @@ public: Inspector::Protocol::ErrorStringOr enable(); Inspector::Protocol::ErrorStringOr disable(); Inspector::Protocol::ErrorStringOr reload(std::optional&& ignoreCache, std::optional&& revalidateAllResources); + Inspector::Protocol::ErrorStringOr goBack(); + Inspector::Protocol::ErrorStringOr goForward(); Inspector::Protocol::ErrorStringOr overrideUserAgent(const String&); + Inspector::Protocol::ErrorStringOr overridePlatform(const String&); Inspector::Protocol::ErrorStringOr overrideSetting(Inspector::Protocol::Page::Setting, std::optional&& value); Inspector::Protocol::ErrorStringOr overrideUserPreference(Inspector::Protocol::Page::UserPreferenceName, std::optional&&); Inspector::Protocol::ErrorStringOr>> getCookies(); @@ -92,41 +101,60 @@ public: #endif Inspector::Protocol::ErrorStringOr setShowPaintRects(bool); Inspector::Protocol::ErrorStringOr setEmulatedMedia(const String&); + Inspector::Protocol::ErrorStringOr setForcedColors(std::optional&&); + Inspector::Protocol::ErrorStringOr setTimeZone(const String&); + Inspector::Protocol::ErrorStringOr setTouchEmulationEnabled(bool); Inspector::Protocol::ErrorStringOr snapshotNode(Inspector::Protocol::DOM::NodeId); - Inspector::Protocol::ErrorStringOr snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem); + Inspector::Protocol::ErrorStringOr snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem, std::optional&& omitDeviceScaleFactor); #if ENABLE(WEB_ARCHIVE) && USE(CF) Inspector::Protocol::ErrorStringOr archive(); #endif -#if !PLATFORM(COCOA) Inspector::Protocol::ErrorStringOr setScreenSizeOverride(std::optional&& width, std::optional&& height); -#endif + + Inspector::Protocol::ErrorStringOr insertText(const String& text); + Inspector::Protocol::ErrorStringOr setInterceptFileChooserDialog(bool enabled); + Inspector::Protocol::ErrorStringOr setDefaultBackgroundColorOverride(RefPtr&&); + Inspector::Protocol::ErrorStringOr createUserWorld(const String&); + Inspector::Protocol::ErrorStringOr setBypassCSP(bool); + Inspector::Protocol::ErrorStringOr crash(); + Inspector::Protocol::ErrorStringOr updateScrollingState(); // InspectorInstrumentation - void domContentEventFired(); - void loadEventFired(); + void domContentEventFired(LocalFrame&); + void loadEventFired(LocalFrame&); void frameNavigated(LocalFrame&); void frameDetached(LocalFrame&); void loaderDetachedFromFrame(DocumentLoader&); void accessibilitySettingsDidChange(); void defaultUserPreferencesDidChange(); + void didNavigateWithinPage(LocalFrame&); #if ENABLE(DARK_MODE_CSS) void defaultAppearanceDidChange(); #endif void applyUserAgentOverride(String&); + void applyPlatformOverride(String&); void applyEmulatedMedia(AtomString&); void didClearWindowObjectInWorld(LocalFrame&, DOMWrapperWorld&); void didPaint(RenderObject&, const LayoutRect&); void didLayout(); void didScroll(); void didRecalculateStyle(); + void runOpenPanel(HTMLInputElement* element, bool* intercept); + void frameAttached(LocalFrame&); + bool shouldBypassCSP(); + void willCheckNavigationPolicy(LocalFrame&); + void didCheckNavigationPolicy(LocalFrame&, bool cancel); Frame* frameForId(const Inspector::Protocol::Network::FrameId&); WEBCORE_EXPORT String frameId(Frame*); String loaderId(DocumentLoader*); LocalFrame* assertFrame(Inspector::Protocol::ErrorString&, const Inspector::Protocol::Network::FrameId&); + void setIgnoreDidClearWindowObject(bool ignore) { m_ignoreDidClearWindowObject = ignore; } + bool ignoreDidClearWindowObject() const { return m_ignoreDidClearWindowObject; } private: double timestamp(); + void ensureUserWorldsExistInAllFrames(const Vector&); InspectorOverlay& NODELETE overlay() const; @@ -141,14 +169,19 @@ private: const Ref m_backendDispatcher; WeakRef m_inspectedPage; + Inspector::InjectedScriptManager& m_injectedScriptManager; InspectorBackendClient* m_client { nullptr }; WeakRef m_overlay; String m_userAgentOverride; + String m_platformOverride; AtomString m_emulatedMedia; String m_bootstrapScript; bool m_isFirstLayoutAfterOnLoad { false }; bool m_showPaintRects { false }; + bool m_interceptFileChooserDialog { false }; + bool m_bypassCSP { false }; + bool m_ignoreDidClearWindowObject { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp index e93e93df33a77cf1995340ff1375488efee0a9df..002c160eec98597f97d547f6f2722b7edb58be72 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp @@ -35,7 +35,9 @@ #include "DOMWrapperWorld.h" #include "Document.h" #include "FrameConsoleClient.h" +#include "FrameLoader.h" #include "InspectorIdentifierRegistry.h" +#include "InspectorPageAgent.h" #include "InstrumentingAgents.h" #include "JSDOMWindowCustom.h" #include "JSExecState.h" @@ -43,6 +45,7 @@ #include "Page.h" #include "PageInspectorController.h" #include "ScriptController.h" +#include "ScriptSourceCode.h" #include "SecurityOrigin.h" #include "UserGestureEmulationScope.h" #include @@ -90,13 +93,74 @@ Inspector::Protocol::ErrorStringOr PageRuntimeAgent::disable() { Ref { m_instrumentingAgents.get() }->setEnabledPageRuntimeAgent(nullptr); + m_bindingNames.clear(); + return InspectorRuntimeAgent::disable(); } void PageRuntimeAgent::frameNavigated(LocalFrame& frame) { + auto* pageAgent = Ref { m_instrumentingAgents.get() }->enabledPageAgent(); + if (pageAgent) + pageAgent->setIgnoreDidClearWindowObject(true); // Ensure execution context is created for the frame even if it doesn't have scripts. mainWorldGlobalObject(frame); + if (pageAgent) + pageAgent->setIgnoreDidClearWindowObject(false); +} + +static JSC_DECLARE_HOST_FUNCTION(bindingCallback); + +JSC_DEFINE_HOST_FUNCTION(bindingCallback, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) +{ + auto result = JSC::JSValue::encode(JSC::jsUndefined()); + if (!callFrame->jsCallee()) + return result; + String bindingName; + if (auto* function = dynamicDowncast(callFrame->jsCallee())) + bindingName = function->name(globalObject->vm()); + auto client = globalObject->consoleClient(); + if (!client) + return result; + if (callFrame->argumentCount() < 1) + return result; + auto value = callFrame->argument(0); + if (value.isUndefined()) + return result; + String stringArg = value.toWTFString(globalObject); + client->bindingCalled(globalObject, bindingName, stringArg); + return result; +} + +static void addBindingToFrame(LocalFrame& frame, const String& name) +{ + JSC::JSGlobalObject* globalObject = frame.script().globalObject(mainThreadNormalWorldSingleton()); + auto& vm = globalObject->vm(); + JSC::JSLockHolder lock(vm); + globalObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, name), 1, bindingCallback, JSC::ImplementationVisibility::Public, JSC::NoIntrinsic, JSC::attributesForStructure(static_cast(JSC::PropertyAttribute::Function))); +} + +Inspector::Protocol::ErrorStringOr PageRuntimeAgent::addBinding(const String& name) +{ + if (!m_bindingNames.add(name).isNewEntry) + return {}; + + m_inspectedPage->forEachLocalFrame([&](LocalFrame& frame) { + if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) + return; + + addBindingToFrame(frame, name); + }); + + return {}; +} + +void PageRuntimeAgent::bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg) +{ + auto injectedScript = injectedScriptManager().injectedScriptFor(globalObject); + if (injectedScript.hasNoValue()) + return; + m_frontendDispatcher->bindingCalled(injectedScriptManager().injectedScriptIdFor(globalObject), name, arg); } void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapperWorld& world) @@ -105,7 +169,29 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper if (frameId.isEmpty()) return; + auto* pageAgent = Ref { m_instrumentingAgents.get() }->enabledPageAgent(); + if (pageAgent && pageAgent->ignoreDidClearWindowObject()) + return; + + if (world.isNormal()) { + for (const auto& name : m_bindingNames) + addBindingToFrame(frame, name); + } + + if (pageAgent) + pageAgent->setIgnoreDidClearWindowObject(true); notifyContextCreated(frameId, frame.script().globalObject(world), world); + if (pageAgent) + pageAgent->setIgnoreDidClearWindowObject(false); +} + +void PageRuntimeAgent::didReceiveMainResourceError(LocalFrame& frame) +{ + if (frame.loader().stateMachine().isDisplayingInitialEmptyDocument()) { + // Ensure execution context is created for the empty docment to make + // it usable in case loading failed. + mainWorldGlobalObject(frame); + } } InjectedScript PageRuntimeAgent::injectedScriptForEval(Inspector::Protocol::ErrorString& errorString, std::optional&& executionContextId) @@ -142,9 +228,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() Ref identifierRegistry = m_inspectedPage->inspectorController().identifierRegistry(); m_inspectedPage->forEachLocalFrame([&](LocalFrame& frame) { - if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) - return; - auto frameId = identifierRegistry->frameId(&frame); // Always send the main world first. diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h index db4e1b7cd5ba1c46f962c07fa6e23cb13092832c..f7fb1503fc42b4b5fd21f76a893c84030e8af8c2 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h @@ -39,6 +39,7 @@ namespace JSC { class CallFrame; +class JSGlobalObject; } namespace WebCore { @@ -60,10 +61,13 @@ public: Inspector::Protocol::ErrorStringOr disable(); Inspector::Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture); void callFunctionOn(const Inspector::Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture, std::optional&& awaitPromise, Ref&&); + Inspector::Protocol::ErrorStringOr addBinding(const String& name); // InspectorInstrumentation void frameNavigated(LocalFrame&); void didClearWindowObjectInWorld(LocalFrame&, DOMWrapperWorld&); + void didReceiveMainResourceError(LocalFrame&); + void bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg); private: Inspector::InjectedScript injectedScriptForEval(Inspector::Protocol::ErrorString&, std::optional&&); @@ -78,6 +82,7 @@ private: WeakRef m_instrumentingAgents; WeakRef m_inspectedPage; + HashSet m_bindingNames; }; } // namespace WebCore diff --git a/Source/WebCore/loader/CookieJar.h b/Source/WebCore/loader/CookieJar.h index c2f9d5d90ff590154ef39132453194c162be0cc5..ff36e34f9e5963f1deaa41341174a7fd312ae25f 100644 --- a/Source/WebCore/loader/CookieJar.h +++ b/Source/WebCore/loader/CookieJar.h @@ -48,6 +48,7 @@ class NetworkStorageSession; class StorageSessionProvider; struct SameSiteInfo; enum class ShouldPartitionCookie : bool; +class ResourceLoader; class WEBCORE_EXPORT CookieJar : public RefCountedAndCanMakeWeakPtr { public: @@ -82,6 +83,9 @@ public: virtual void clearCache() { } virtual void clearCacheForHost(const String&) { } + // Playwright. + virtual void setCookieFromResponse(ResourceLoader&, const String&) { } + virtual ~CookieJar(); protected: static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess = IsForDOMCookieAccess::No); diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp index a060ef80b1c658b388324d5c3f724097fb5c3787..70a1c51d4e2b6e396afd5e5dbf9ad00cf88d42e8 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp @@ -787,8 +787,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc if (!didReceiveRedirectResponse) return completionHandler(WTF::move(newRequest)); + InspectorInstrumentation::willCheckNavigationPolicy(*frame); auto navigationPolicyCompletionHandler = [this, protectedThis = Ref { *this }, frame, completionHandler = WTF::move(completionHandler)] (ResourceRequest&& request, WeakPtr&&, NavigationPolicyDecision navigationPolicyDecision) mutable { m_waitingForNavigationPolicy = false; + InspectorInstrumentation::didCheckNavigationPolicy(*frame, navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad); switch (navigationPolicyDecision) { case NavigationPolicyDecision::IgnoreLoad: case NavigationPolicyDecision::LoadWillContinueInAnotherProcess: @@ -1590,11 +1592,17 @@ void DocumentLoader::detachFromFrame(LoadWillContinueInAnotherProcess loadWillCo if (auto navigationID = std::exchange(m_navigationID, { })) frame->loader().client().documentLoaderDetached(*navigationID, loadWillContinueInAnotherProcess); - InspectorInstrumentation::loaderDetachedFromFrame(*frame, *this); - observeFrame(nullptr); } +void DocumentLoader::replacedByFragmentNavigation(LocalFrame& frame) +{ + ASSERT(!this->frame()); + // Notify WebPageProxy that the navigation has been converted into same page navigation. + if (auto navigationID = std::exchange(m_navigationID, { })) + frame.loader().client().documentLoaderDetached(*navigationID, LoadWillContinueInAnotherProcess::No); +} + void DocumentLoader::setNavigationID(NavigationIdentifier navigationID) { m_navigationID = navigationID; diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h index ffebadc8882ffd9a519fdaec8d42ac2909c5fe65..145e7ee21440d14da048d59f7c177c8d334e0ee3 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h @@ -209,6 +209,8 @@ public: WEBCORE_EXPORT virtual void detachFromFrame(LoadWillContinueInAnotherProcess); + void replacedByFragmentNavigation(LocalFrame&); + WEBCORE_EXPORT FrameLoader* NODELETE frameLoader() const; WEBCORE_EXPORT SubresourceLoader* NODELETE mainResourceLoader() const; WEBCORE_EXPORT RefPtr mainResourceData() const; diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 994f22fa6190e271f9f9927caa6a331c355cc43e..3f469ef6abebeea6f7df6b9406c8c0e9cd5fe386 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -1385,6 +1385,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr stat } m_client->dispatchDidNavigateWithinPage(); + InspectorInstrumentation::didNavigateWithinPage(m_frame); document->statePopped(stateObject ? stateObject.releaseNonNull() : SerializedScriptValue::nullValue()); m_client->dispatchDidPopStateWithinPage(); @@ -1938,6 +1939,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t const String& httpMethod = loader->request().httpMethod(); if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL) && !loader->substituteData().isValid()) { + loader->replacedByFragmentNavigation(m_frame); RefPtr oldDocumentLoader = m_documentLoader; NavigationAction action { protect(frame->document()).releaseNonNull(), loader->request(), InitiatedByMainFrame::Unknown, loader->isRequestFromClientOrUserInput(), policyChecker().loadType(), isFormSubmission }; @@ -1977,7 +1979,9 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t auto policyDecisionMode = loader->triggeringAction().isFromNavigationAPI() ? PolicyDecisionMode::Synchronous : PolicyDecisionMode::Asynchronous; RELEASE_ASSERT(!isBackForwardLoadType(policyChecker().loadType()) || history().provisionalItem()); + InspectorInstrumentation::willCheckNavigationPolicy(m_frame); policyChecker().checkNavigationPolicy(ResourceRequest(loader->request()), ResourceResponse { } /* redirectResponse */, loader, WTF::move(formSubmission), [this, protectedThis = Ref { *this }, allowNavigationToInvalidURL, completionHandler = completionHandlerCaller.release()] (const ResourceRequest& request, WeakPtr&& weakFormSubmission, NavigationPolicyDecision navigationPolicyDecision) mutable { + InspectorInstrumentation::didCheckNavigationPolicy(m_frame, navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad); continueLoadAfterNavigationPolicy(request, RefPtr { weakFormSubmission.get() }.get(), navigationPolicyDecision, allowNavigationToInvalidURL); completionHandler(); }, policyDecisionMode, determineNavigationType(type, NavigationHistoryBehavior::Auto)); @@ -3324,10 +3328,15 @@ String FrameLoader::userAgent(const URL& url) const String FrameLoader::navigatorPlatform() const { + String platform; + auto customNavigatorPlatform = protect(m_frame->mainFrame())->customNavigatorPlatform(); if (!customNavigatorPlatform.isEmpty()) - return customNavigatorPlatform; - return String(); + platform = customNavigatorPlatform; + + InspectorInstrumentation::applyPlatformOverride(m_frame, platform); + + return platform; } void FrameLoader::dispatchOnloadEvents() @@ -3785,6 +3794,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill } if (frame->page()) checkLoadComplete(loadWillContinueInAnotherProcess); + + InspectorInstrumentation::didReceiveMainResourceError(m_frame, error); } void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, const SecurityOrigin* requesterOrigin, bool shouldContinue, NavigationHistoryBehavior historyHandling) @@ -4789,9 +4800,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { - if (!protect(m_frame->script())->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) - return; - Vector> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) @@ -4801,13 +4809,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { Ref frame = m_frame.get(); - if (!protect(frame->script())->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript) || !protect(frame->windowProxy())->existingJSWindowProxy(world)) - return; - - m_client->dispatchDidClearWindowObjectInWorld(world); - - if (RefPtr page = frame->page()) - page->inspectorController().didClearWindowObjectInWorld(frame, world); + if (frame->windowProxy().existingJSWindowProxy(world)) { + if (protect(frame->script())->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) + m_client->dispatchDidClearWindowObjectInWorld(world); + if (RefPtr page = frame->page()) + page->inspectorController().didClearWindowObjectInWorld(m_frame, world); + } InspectorInstrumentation::didClearWindowObjectInWorld(frame, world); } diff --git a/Source/WebCore/loader/LoaderStrategy.h b/Source/WebCore/loader/LoaderStrategy.h index 9a5561ea2fa43baab02c7f8d43d29cf4a5543411..4b1c8dfd6be705aa3560685bb2453dd4e309372f 100644 --- a/Source/WebCore/loader/LoaderStrategy.h +++ b/Source/WebCore/loader/LoaderStrategy.h @@ -89,6 +89,7 @@ public: virtual bool isOnLine() const = 0; virtual void addOnlineStateChangeListener(Function&&) = 0; + virtual void setEmulateOfflineState(bool) {}; virtual bool shouldPerformSecurityChecks() const { return false; } virtual bool havePerformedSecurityChecks(const ResourceResponse&) const { return false; } diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp index 3acb026789c46395be3f8cd6b837ebf207e215f7..a4e3c1e69fbbb108badd23f32e879423c0ec72e6 100644 --- a/Source/WebCore/loader/ProgressTracker.cpp +++ b/Source/WebCore/loader/ProgressTracker.cpp @@ -158,6 +158,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame) if (!m_numProgressTrackedFrames || originatingProgressFrame == &frame) finalProgressComplete(); + InspectorInstrumentation::frameStoppedLoading(frame); + m_client->didChangeEstimatedProgress(); } @@ -184,8 +186,6 @@ void ProgressTracker::finalProgressComplete() m_client->progressFinished(*frame); protect(m_page)->progressFinished(*frame); frame->loader().loadProgressingStatusChanged(); - - InspectorInstrumentation::frameStoppedLoading(*frame); } } diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp index 01466dae0f43c53e7e50dad34c73731fbc8240d6..f37b4130add559d50a869ab494a3f7fb99b275d1 100644 --- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp +++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp @@ -1159,8 +1159,11 @@ ResourceErrorOr> CachedResourceLoader::requestResource(Cache request.updateReferrerPolicy(document ? document->referrerPolicy() : ReferrerPolicy::Default); - if (InspectorInstrumentation::willIntercept(frame.ptr(), request.resourceRequest())) - request.setCachingPolicy(CachingPolicy::DisallowCaching); + if (InspectorInstrumentation::willIntercept(frame.ptr(), request.resourceRequest())) { + // Playwright: we don't disable such caching in other browsers and it breaks css resource downloads, + // see https://github.com/microsoft/playwright/issues/19158 + // request.setCachingPolicy(CachingPolicy::DisallowCaching); + } if (RefPtr documentLoader = m_documentLoader) { bool madeHTTPS { request.resourceRequest().wasSchemeOptimisticallyUpgraded() }; @@ -1817,8 +1820,9 @@ Vector> CachedResourceLoader::allCachedSVGImages() const ResourceErrorOr> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request) { - if (InspectorInstrumentation::willIntercept(protect(frame()).get(), request.resourceRequest())) - return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); + // Playwright: requests are intercepted (see https://github.com/microsoft/playwright/issues/16745) + // if (InspectorInstrumentation::willIntercept(protect(frame()).get(), request.resourceRequest())) + // return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); RefPtr document = m_document; ASSERT(document); diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h index 1a4fae919b725be107c91cde64f8ccfa30b1e839..2687ebc237823715ebfa06440d54e9dd6dbddd8e 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h @@ -408,7 +408,7 @@ public: #endif #if ENABLE(ORIENTATION_EVENTS) - virtual IntDegrees deviceOrientation() const = 0; + virtual IntDegrees deviceOrientation() const { return 0; } #endif virtual RefPtr createColorChooser(ColorChooserClient&, const Color&) = 0; diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp index d425f52413eba85996fc0a1fae3a0af0974a1d5d..4fa3846cd38402a61676be5330e354ed7d96f92b 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -4823,6 +4823,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr if (!document) return false; +#if PLATFORM(MAC) + auto* page = m_frame->page(); + if (page && !page->overrideDragPasteboardName().isEmpty()) + dragState().dataTransfer = DataTransfer::createForDrag(*document, page->overrideDragPasteboardName()); + else +#endif dragState().dataTransfer = DataTransfer::createForDrag(*document); auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No; @@ -5427,6 +5433,7 @@ static HitTestResult hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& return result; } +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN Expected EventHandler::handleTouchEvent(const PlatformTouchEvent& event) { Ref frame = m_frame.get(); @@ -5558,7 +5565,7 @@ Expected EventHandler::handleTouchEvent(co if (!targetFrame) continue; -#if PLATFORM(WPE) || PLATFORM(GTK) +#if !ENABLE(IOS_TOUCH_EVENTS) RefPtr pointerTarget = touchTarget; if (pointState != PlatformTouchPoint::TouchPressed) { @@ -5654,6 +5661,7 @@ Expected EventHandler::handleTouchEvent(co return swallowedEvent; } +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) #if ENABLE(TOUCH_EVENTS) diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp index 1862c8160a30a39f04c64819ab4be917fba219ca..b1877c40f4111f02d448ed9d5df2a2c5723f3a5b 100644 --- a/Source/WebCore/page/FocusController.cpp +++ b/Source/WebCore/page/FocusController.cpp @@ -708,13 +708,14 @@ bool FocusController::relinquishFocusToChrome(FocusDirection direction) return false; Ref page = m_page.get(); - if (!page->chrome().canTakeFocus(direction) || page->isControlledByAutomation()) + if (!page->chrome().canTakeFocus(direction)) return false; clearSelectionIfNeeded(frame.get(), nullptr, nullptr); document->setFocusedElement(nullptr); setFocusedFrame(nullptr); - page->chrome().takeFocus(direction); + if (!page->isControlledByAutomation()) + page->chrome().takeFocus(direction); return true; } diff --git a/Source/WebCore/page/FrameConsoleClient.cpp b/Source/WebCore/page/FrameConsoleClient.cpp index 23e6d8380ec1e3488bc746887ea06be8eed79fb9..7a1b91c923530472bf1bd613a237dd5a8739b88f 100644 --- a/Source/WebCore/page/FrameConsoleClient.cpp +++ b/Source/WebCore/page/FrameConsoleClient.cpp @@ -478,4 +478,12 @@ void FrameConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, Re addMessage(makeUnique(MessageSource::ConsoleAPI, MessageType::Image, MessageLevel::Log, dataURL, ScriptArguments::create(lexicalGlobalObject, WTF::move(adjustedArguments)), lexicalGlobalObject, /* requestIdentifier */ 0, timestamp)); } +void FrameConsoleClient::bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg) +{ + RefPtr frame = m_frame.get(); + if (!frame) + return; + InspectorInstrumentation::bindingCalled(*frame->page(), globalObject, name, arg); +} + } // namespace WebCore diff --git a/Source/WebCore/page/FrameConsoleClient.h b/Source/WebCore/page/FrameConsoleClient.h index 7a6671ff0da0bbec833318a1c37e6280ad9f4255..5a16fa04c515f0c3842d1187eeacc487a7491080 100644 --- a/Source/WebCore/page/FrameConsoleClient.h +++ b/Source/WebCore/page/FrameConsoleClient.h @@ -92,6 +92,7 @@ private: void record(JSC::JSGlobalObject*, Ref&&) override; void recordEnd(JSC::JSGlobalObject*, Ref&&) override; void screenshot(JSC::JSGlobalObject*, Ref&&) override; + void bindingCalled(JSC::JSGlobalObject*, const String& name, const String& arg) override; WeakRef m_frame; }; diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp index dd21eb7cd8958c99a153769d26e03a8eb5bed0fb..a94d8b5d2eced11e03f963d3848159914d554ae3 100644 --- a/Source/WebCore/page/FrameSnapshotting.cpp +++ b/Source/WebCore/page/FrameSnapshotting.cpp @@ -121,7 +121,7 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& // Other paint behaviors are set by paintContentsForSnapshot. frame.view()->setPaintBehavior(paintBehavior); - float scaleFactor = frame.page()->deviceScaleFactor(); + float scaleFactor = options.flags.contains(SnapshotFlags::OmitDeviceScaleFactor) ? 1 : frame.page()->deviceScaleFactor(); if (options.flags.contains(SnapshotFlags::PaintWith3xBaseScale)) scaleFactor = 3; @@ -140,6 +140,8 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& return nullptr; buffer->context().translate(-imageRect.location()); + if (coordinateSpace != LocalFrameView::ViewCoordinates) + buffer->context().scale(1 / frame.page()->pageScaleFactor()); if (!clipRects.isEmpty()) { Path clipPath; @@ -148,7 +150,10 @@ RefPtr snapshotFrameRectWithClip(LocalFrame& frame, const IntRect& buffer->context().clipPath(clipPath); } - frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace); + FloatRect fr = imageRect; + if (coordinateSpace != LocalFrameView::ViewCoordinates) + fr.scale(frame.page()->pageScaleFactor()); + frame.view()->paintContentsForSnapshot(buffer->context(), enclosingIntRect(fr), shouldIncludeSelection, coordinateSpace); return buffer; } diff --git a/Source/WebCore/page/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h index c34982712f798dff6c484e4a4b6b6a9b23905d4a..52da92d68344cd4d734db4565f174bbd05e26ad9 100644 --- a/Source/WebCore/page/FrameSnapshotting.h +++ b/Source/WebCore/page/FrameSnapshotting.h @@ -60,6 +60,7 @@ enum class SnapshotFlags : uint16_t { FixedAndStickyLayersOnly = 1 << 12, DraggableElement = 1 << 13, IncludeDocumentMarkers = 1 << 14, + OmitDeviceScaleFactor = 1 << 15, }; struct SnapshotOptions { diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index 6cde8d25af42de8e96f6aa23dbeedb5abaa7feab..bef6092300de6f6d33c5a9e2a9354e00c200d9ef 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -35,6 +35,7 @@ #include "FrameLoader.h" #include "HistoryController.h" #include "HistoryItem.h" +#include "InspectorInstrumentation.h" #include "LocalFrame.h" #include "LocalFrameInlines.h" #include "LocalFrameLoaderClient.h" @@ -97,7 +98,7 @@ ExceptionOr History::scrollRestoration() const RefPtr historyItem = frame->loader().history().currentItem(); if (!historyItem) return ScrollRestoration::Auto; - + return historyItem->shouldRestoreScrollPosition() ? ScrollRestoration::Auto : ScrollRestoration::Manual; } @@ -315,6 +316,8 @@ ExceptionOr History::stateObjectAdded(RefPtr&& data } frame->loader().updateURLAndHistory(fullURL, WTF::move(data), historyBehavior); + InspectorInstrumentation::didNavigateWithinPage(*frame); + return { }; } diff --git a/Source/WebCore/page/LocalFrame.cpp b/Source/WebCore/page/LocalFrame.cpp index 50342738fed8b72c737e834caa6517b3a642687f..3bf5c788d2a2091c521ae83a211de701d57bce4d 100644 --- a/Source/WebCore/page/LocalFrame.cpp +++ b/Source/WebCore/page/LocalFrame.cpp @@ -41,6 +41,7 @@ #include "CachedCSSStyleSheet.h" #include "Chrome.h" #include "ChromeClient.h" +#include "ComposedTreeIterator.h" #include "DiagnosticLoggingClient.h" #include "DiagnosticLoggingKeys.h" #include "DocumentLoader.h" @@ -92,6 +93,7 @@ #include "MixedContentChecker.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeRenderStyle.h" #include "NodeTraversal.h" #include "Page.h" #include "PaymentSession.h" @@ -226,6 +228,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie void LocalFrame::init() { + InspectorInstrumentation::frameAttached(this); loader().init(); } @@ -462,7 +465,7 @@ void LocalFrame::orientationChanged() IntDegrees LocalFrame::orientation() const { if (RefPtr page = this->page()) - return page->chrome().client().deviceOrientation(); + return page->orientation(); return 0; } #endif // ENABLE(ORIENTATION_EVENTS) @@ -1672,7 +1675,6 @@ String LocalFrame::frameURLProtocol() const return ""_s; } -#if PLATFORM(COCOA) static bool nodeIsMouseFocusable(Node& node) { @@ -1908,7 +1910,7 @@ RefPtr LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& view for (; node && node != terminationNode; node = node->parentInComposedTree()) { if (!node->hasEventListeners(eventNames().dblclickEvent)) continue; -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(TWO_PHASE_CLICKS) if (!node->allowsDoubleTapGesture()) continue; #endif @@ -1922,7 +1924,6 @@ RefPtr LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& view return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTF::move(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes); } -#endif // PLATFORM(COCOA) } // namespace WebCore diff --git a/Source/WebCore/page/LocalFrame.h b/Source/WebCore/page/LocalFrame.h index 8f81b0ea3fc343e6c214ad566ab4a6d9b95f5c3b..53ac6ea36a6fb13debd0f029f78c4dc4037d24f2 100644 --- a/Source/WebCore/page/LocalFrame.h +++ b/Source/WebCore/page/LocalFrame.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -129,9 +130,7 @@ enum { enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll }; #endif -#if PLATFORM(COCOA) using NodeQualifier = Function (const HitTestResult&, Node* terminationNode, IntRect* nodeBounds)>; -#endif class LocalFrame final : public Frame { public: @@ -232,7 +231,6 @@ public: WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults() LIFETIME_BOUND; #endif -#if PLATFORM(COCOA) RefPtr betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node* best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect); WEBCORE_EXPORT RefPtr nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); @@ -246,7 +244,6 @@ public: WEBCORE_EXPORT RefPtr nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); static bool nodeWillRespondToMouseEvents(Node&); -#endif // PLATFORM(COCOA) #if PLATFORM(IOS_FAMILY) const ViewportArguments& viewportArguments() const LIFETIME_BOUND; @@ -324,6 +321,7 @@ public: WEBCORE_EXPORT FloatSize screenSize() const; void setOverrideScreenSize(FloatSize&&); + bool hasScreenSizeOverride() const { return !!m_overrideScreenSize; } void NODELETE selfOnlyRef(); void selfOnlyDeref(); diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index 52c005d8cf66917c42f05c5cd478b3d2e2b1cac3..13ba48bae2d135b620fd80a642c060a906e3b38c 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -697,6 +697,44 @@ void Page::setOverrideViewportArguments(const std::optional& localTopDocument->updateViewportArguments(); } +FloatSize Page::screenSize() +{ + RefPtr localMainFrame = this->localMainFrame(); + RefPtr frameView = localMainFrame ? localMainFrame->view() : nullptr; + if (!frameView) + return { }; + return m_overrideScreenSize.value_or(screenRect(frameView.get()).size()); +} + +void Page::setOverrideScreenSize(std::optional size) +{ + if (size == m_overrideScreenSize) + return; + + m_overrideScreenSize = size; + RefPtr localMainFrame = this->localMainFrame(); + if (auto* document = localMainFrame ? localMainFrame->document() : nullptr) + document->updateViewportArguments(); +} + +#if ENABLE(ORIENTATION_EVENTS) +int Page::orientation() const +{ + return m_overrideOrientation.value_or(chrome().client().deviceOrientation()); +} + +void Page::setOverrideOrientation(std::optional orientation) +{ + if (orientation == m_overrideOrientation) + return; + + m_overrideOrientation = orientation; + + if (RefPtr localMainFrame = this->localMainFrame()) + localMainFrame->orientationChanged(); +} +#endif + ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { @@ -4417,6 +4455,26 @@ void Page::setUseDarkAppearanceOverride(std::optional valueOverride) appearanceDidChange(); } +void Page::setUseReducedMotionOverride(std::optional valueOverride) +{ + if (valueOverride == m_useReducedMotionOverride) + return; + + m_useReducedMotionOverride = valueOverride; + + appearanceDidChange(); +} + +void Page::setUseForcedColorsOverride(std::optional valueOverride) +{ + if (valueOverride == m_useForcedColorsOverride) + return; + + m_useForcedColorsOverride = valueOverride; + + appearanceDidChange(); +} + void Page::setFullscreenInsets(const FloatBoxExtent& insets) { if (insets == m_fullscreenInsets) diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h index 5bfae7e81b70cbd14f12e307bebd5b551f10c18b..ef95a268fd4aeb4ff5a325517386716ab17f257c 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h @@ -413,6 +413,9 @@ public: const ViewportArguments* overrideViewportArguments() const LIFETIME_BOUND { return m_overrideViewportArguments.get(); } WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional&); + WEBCORE_EXPORT FloatSize screenSize(); + void setOverrideScreenSize(std::optional size); + static void refreshPlugins(bool reload); WEBCORE_EXPORT PluginData& pluginData(); void clearPluginData(); @@ -498,6 +501,10 @@ public: #if ENABLE(DRAG_SUPPORT) DragController& dragController() LIFETIME_BOUND { return m_dragController.get(); } const DragController& dragController() const LIFETIME_BOUND { return m_dragController.get(); } +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_overrideDragPasteboardName = pasteboardName; } + const String& overrideDragPasteboardName() { return m_overrideDragPasteboardName; } +#endif #endif FocusController& focusController() const { return m_focusController; } #if ENABLE(CONTEXT_MENUS) @@ -687,6 +694,10 @@ public: WEBCORE_EXPORT void setUseColorAppearance(bool useDarkAppearance, bool useElevatedUserInterfaceLevel); bool defaultUseDarkAppearance() const { return m_useDarkAppearance; } void setUseDarkAppearanceOverride(std::optional); + std::optional useReducedMotionOverride() const { return m_useReducedMotionOverride; } + void setUseReducedMotionOverride(std::optional); + std::optional useForcedColorsOverride() const { return m_useForcedColorsOverride; } + void setUseForcedColorsOverride(std::optional); #if ENABLE(TEXT_AUTOSIZING) float textAutosizingWidth() const { return m_textAutosizingWidth; } @@ -1150,6 +1161,11 @@ public: WEBCORE_EXPORT void setInteractionRegionsEnabled(bool); #endif +#if ENABLE(ORIENTATION_EVENTS) + int orientation() const; + WEBCORE_EXPORT void setOverrideOrientation(std::optional); +#endif + #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); } #endif @@ -1484,6 +1500,9 @@ private: #if ENABLE(DRAG_SUPPORT) const UniqueRef m_dragController; +#if PLATFORM(MAC) + String m_overrideDragPasteboardName; +#endif #endif const UniqueRef m_focusController; #if ENABLE(CONTEXT_MENUS) @@ -1562,6 +1581,8 @@ private: bool m_useElevatedUserInterfaceLevel { false }; bool m_useDarkAppearance { false }; std::optional m_useDarkAppearanceOverride; + std::optional m_useReducedMotionOverride; + std::optional m_useForcedColorsOverride; #if ENABLE(TEXT_AUTOSIZING) float m_textAutosizingWidth { 0 }; @@ -1739,6 +1760,11 @@ private: #endif std::unique_ptr m_overrideViewportArguments; + std::optional m_overrideScreenSize; + +#if ENABLE(ORIENTATION_EVENTS) + std::optional m_overrideOrientation; +#endif #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) RefPtr m_deviceOrientationUpdateProvider; diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp index e9fa28ab43ecb4f3139791eca2bbb7bd82cfd6e0..8bbb8c76d913c37b60472972eb1647c58622c5a7 100644 --- a/Source/WebCore/page/PointerCaptureController.cpp +++ b/Source/WebCore/page/PointerCaptureController.cpp @@ -213,7 +213,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi return capturingData && capturingData->preventsCompatibilityMouseEvents; } -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName) { for (RefPtr currentNode = target; currentNode; currentNode = currentNode->parentInComposedTree()) { @@ -574,7 +574,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint capturingData->pendingTargetOverride = nullptr; capturingData->state = CapturingData::State::Cancelled; -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) capturingData->previousTarget = nullptr; #endif diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h index bafa2e9995a142e1bc07d506204ff5f14cbeab9c..d06922b691b02699ca89483c6e4e5c43bb49303c 100644 --- a/Source/WebCore/page/PointerCaptureController.h +++ b/Source/WebCore/page/PointerCaptureController.h @@ -63,7 +63,7 @@ public: RefPtr pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType); -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&, const DoublePoint&); #endif @@ -91,12 +91,12 @@ private: WeakPtr activeDocument; RefPtr pendingTargetOverride; RefPtr targetOverride; -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) RefPtr previousTarget; #endif bool hasAnyElement() const { return pendingTargetOverride || targetOverride -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE) || PLATFORM(GTK)) +#if ENABLE(TOUCH_EVENTS) || previousTarget #endif ; diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp index cd1f3ce09ba0ab6e414bfcb12f38918404946700..f78cd1f89fb32ce4b9109c80f1f7c303c351b4fc 100644 --- a/Source/WebCore/page/Screen.cpp +++ b/Source/WebCore/page/Screen.cpp @@ -125,6 +125,9 @@ int Screen::availLeft() const if (shouldApplyScreenFingerprintingProtections(*frame)) return 0; + if (frame->hasScreenSizeOverride()) + return 0; + return static_cast(screenAvailableRect(protect(frame->view()).get()).x()); } @@ -140,6 +143,9 @@ int Screen::availTop() const if (shouldApplyScreenFingerprintingProtections(*frame)) return 0; + if (frame->hasScreenSizeOverride()) + return 0; + return static_cast(screenAvailableRect(protect(frame->view()).get()).y()); } @@ -155,6 +161,9 @@ int Screen::availHeight() const if (shouldApplyScreenFingerprintingProtections(*frame)) return static_cast(frame->screenSize().height()); + if (frame->hasScreenSizeOverride()) + return static_cast(frame->screenSize().height()); + return static_cast(screenAvailableRect(protect(frame->view()).get()).height()); } @@ -170,6 +179,9 @@ int Screen::availWidth() const if (shouldApplyScreenFingerprintingProtections(*frame)) return static_cast(frame->screenSize().width()); + if (frame->hasScreenSizeOverride()) + return static_cast(frame->screenSize().width()); + return static_cast(screenAvailableRect(protect(frame->view()).get()).width()); } diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp index cb4f081221a783cb05b6f65dba5cf338600148d5..88c4adcd84270f24bc4394125d44f34d7b2011c6 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp @@ -352,6 +352,8 @@ template bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, Predicate&& predicate, Args&&... args) const requires (!std::is_convertible_v) { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get())) + return true; bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; for (auto& policy : m_policies) { if (policy->isReportOnly() != isReportOnly) @@ -365,6 +367,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit template bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get())) + return true; bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; bool isAllowed = true; for (auto& policy : m_policies) { @@ -381,6 +385,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit template bool ContentSecurityPolicy::allPoliciesAllow(NOESCAPE const ViolatedDirectiveCallback& callback, Predicate&& predicate, Args&&... args) const { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get())) + return true; bool isAllowed = true; for (auto& policy : m_policies) { if (const ContentSecurityPolicyDirective* violatedDirective = (policy.get()->*predicate)(args...)) { diff --git a/Source/WebCore/page/wpe/DragControllerWPE.cpp b/Source/WebCore/page/wpe/DragControllerWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7bea08826a16de4774a55c81ccba0d81f7d72472 --- /dev/null +++ b/Source/WebCore/page/wpe/DragControllerWPE.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007-20 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DragController.h" + +#include "DataTransfer.h" +#include "Document.h" +#include "DragData.h" +#include "Editor.h" +#include "Element.h" +#include "Frame.h" +#include "FrameDestructionObserverInlines.h" +#include "LocalFrameInlines.h" +#include "NodeInlines.h" +#include "Pasteboard.h" +#include "markup.h" + +namespace WebCore { + +// FIXME: These values are straight out of DragControllerMac, so probably have +// little correlation with Gdk standards... +const int DragController::MaxOriginalImageArea = 1500 * 1500; +const int DragController::DragIconRightInset = 7; +const int DragController::DragIconBottomInset = 3; + +const float DragController::DragImageAlpha = 0.75f; + +bool DragController::isCopyKeyDown(const DragData& dragData) +{ + return dragData.flags().contains(DragApplicationFlags::IsCopyKeyDown); +} + +std::optional DragController::dragOperation(const DragData& dragData) +{ + // FIXME: This logic is incomplete + if (dragData.containsURL()) + return DragOperation::Copy; + + return std::nullopt; +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(200, 200); + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{ +} + +void DragController::declareAndWriteDragImage(DataTransfer& dataTransfer, Element& element, const URL& url, const String& label) +{ + auto* frame = element.document().frame(); + ASSERT(frame); + frame->editor().writeImageToPasteboard(dataTransfer.pasteboard(), element, url, label); +} + +} diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h index 9e2964b6e5f27f3a9c9f39e95b37de574cd52b1b..20e211ebc0217e6f4e66118fd98a7eb42f0edc5d 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -93,8 +93,8 @@ public: // is initialized by the decoder and not in the constructor. DragData() = default; #if PLATFORM(WIN) - WEBCORE_EXPORT DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet = { }, std::optional pageID = std::nullopt); - const DragDataMap& dragDataMap(); + WEBCORE_EXPORT DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet = { }, OptionSet = anyDragDestinationAction(), std::optional pageID = std::nullopt); + WEBCORE_EXPORT const DragDataMap& dragDataMap() const; void getDragFileDescriptorData(int& size, String& pathname); void getDragFileContentData(int size, void* dataBlob); #endif @@ -147,7 +147,7 @@ private: String m_pasteboardName; #endif #if PLATFORM(WIN) - DragDataMap m_dragDataMap; + mutable DragDataMap m_dragDataMap; #endif bool m_disallowFileAccess { false }; }; diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h index 18569a97050f6711699829d52a3177a4a48e3cca..7e7c7d74edb2f7b9c5769ffd15bf7eb97a7cd396 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -322,6 +322,7 @@ public: COMPtr dataObject() const { return m_dataObject; } WEBCORE_EXPORT void setExternalDataObject(IDataObject*); const DragDataMap& dragDataMap() const LIFETIME_BOUND { return m_dragDataMap; } + WEBCORE_EXPORT DragDataMap createDragDataMap(); void writeURLToWritableDataObject(const URL&, const String&); COMPtr writableDataObject() const { return m_writableDataObject; } void writeImageToDataObject(Element&, const URL&); // FIXME: Layering violation. @@ -393,6 +394,7 @@ private: COMPtr m_dataObject; COMPtr m_writableDataObject; DragDataMap m_dragDataMap; + bool m_forDrag = false; #endif }; diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h index 071f9fa0e6cfaa84d9b077e39a64bec9361ead9a..fdd0ec667cc7e2f59bd2d21c5c381ae54dde06d9 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -134,6 +134,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/PlatformScreen.cpp b/Source/WebCore/platform/PlatformScreen.cpp index eac5bf40c150dba990c13775db0ae9e10f883574..563106c0d9fb259c2171aedd5d57efbf81049cc9 100644 --- a/Source/WebCore/platform/PlatformScreen.cpp +++ b/Source/WebCore/platform/PlatformScreen.cpp @@ -85,3 +85,24 @@ OptionSet screenContentsFormatsForTesting() } // namespace WebCore #endif // PLATFORM(COCOA) || PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) + +#if ENABLE(TOUCH_EVENTS) +namespace WebCore { + +static std::optional _screenHasTouchDeviceOverride = std::nullopt; + +void setScreenHasTouchDeviceOverride(bool value) { + _screenHasTouchDeviceOverride = value; +} +std::optional screenHasTouchDeviceOverride() { + return _screenHasTouchDeviceOverride; +} + +bool screenHasTouchDevice() { + if (screenHasTouchDeviceOverride()) + return screenHasTouchDeviceOverride().value(); + return platformScreenHasTouchDevice(); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h index 2a80049e6065880ac2e9d1a42784fc69659f889d..a804d1251cccef36547551344e9ebf838aec1e18 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h @@ -162,10 +162,14 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); #endif #if ENABLE(TOUCH_EVENTS) -#if PLATFORM(GTK) +WEBCORE_EXPORT void setScreenHasTouchDeviceOverride(bool); +WEBCORE_EXPORT std::optional screenHasTouchDeviceOverride(); + WEBCORE_EXPORT bool screenHasTouchDevice(); +#if PLATFORM(GTK) +bool platformScreenHasTouchDevice(); #else -constexpr bool screenHasTouchDevice() { return true; } +constexpr bool platformScreenHasTouchDevice() { return true; } #endif #endif diff --git a/Source/WebCore/platform/PlatformTouchEvent.h b/Source/WebCore/platform/PlatformTouchEvent.h index 8de9b7ed5c5c92eb9700105e5ae186755b13423a..91a007843f7539a2c61121217d393048877a8dc3 100644 --- a/Source/WebCore/platform/PlatformTouchEvent.h +++ b/Source/WebCore/platform/PlatformTouchEvent.h @@ -20,8 +20,8 @@ #ifndef PlatformTouchEvent_h #define PlatformTouchEvent_h -#include "PlatformEvent.h" -#include "PlatformTouchPoint.h" +#include +#include #include #if ENABLE(TOUCH_EVENTS) @@ -42,7 +42,7 @@ public: const Vector& predictedEvents() const LIFETIME_BOUND { return m_predictedEvents; } -#if PLATFORM(WPE) +#if !ENABLE(IOS_TOUCH_EVENTS) // FIXME: since WPE currently does not send touch stationary events, we need to be able to set // TouchCancelled touchPoints subsequently void setTouchPoints(Vector& touchPoints) { m_touchPoints = touchPoints; } diff --git a/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h b/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h index a251b8f6a5e05997594a2962e7fcb3fab49a27b2..fd95b909650098869d44c8860a525051fc6996f8 100644 --- a/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h +++ b/Source/WebCore/platform/adwaita/AdwaitaScrollbarPainter.h @@ -36,7 +36,7 @@ class GraphicsContext; namespace AdwaitaScrollbarPainter { -static const unsigned scrollbarSize = 21; +static const unsigned scrollbarSize = 0; static const unsigned scrollbarBorderSize = 1; static const unsigned thumbBorderSize = 1; static const unsigned overlayThumbSize = 3; diff --git a/Source/WebCore/platform/graphics/ImageUtilities.h b/Source/WebCore/platform/graphics/ImageUtilities.h index 2848aea78c6f4e7c75b2896428e4d5f6d32f4273..c1add6e2c65f702c056380a3744cc2af0ab05d7a 100644 --- a/Source/WebCore/platform/graphics/ImageUtilities.h +++ b/Source/WebCore/platform/graphics/ImageUtilities.h @@ -81,7 +81,7 @@ WEBCORE_EXPORT void createBitmapsFromImageData(std::span data, st WEBCORE_EXPORT RefPtr createIconDataFromBitmaps(Vector>&&); WEBCORE_EXPORT void decodeImageWithSize(std::span data, std::optional, CompletionHandler&&)>&&); -Vector encodeData(CGImageRef, const String& mimeType, std::optional quality = std::nullopt); +WEBCORE_EXPORT Vector encodeData(CGImageRef, const String& mimeType, std::optional quality = std::nullopt); WEBCORE_EXPORT String encodeDataURL(CGImageRef, const String& mimeType, std::optional quality = std::nullopt); WEBCORE_EXPORT uint8_t NODELETE verifyImageBufferIsBigEnough(std::span buffer); RetainPtr utiFromImageBufferMIMEType(const String& mimeType); diff --git a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h b/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h index 515ddea3cd42796efa9f41ad74be07a7447c337e..36db42e2a0822d5609b39046191f05a1f8d2b54b 100644 --- a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h +++ b/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h @@ -23,6 +23,7 @@ #pragma once #include "FilterEffectApplier.h" +#include "PixelBuffer.h" #include namespace WebCore { diff --git a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp index 775df102268b397e6c96e8b93296a7dbe6afcd26..cdbb7b79bde8ba30bc2b0f6bb579b44de72d7fc7 100644 --- a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp +++ b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp @@ -168,6 +168,33 @@ static Vector stringIndicesFromClusters(const Vector& clusters, return stringIndices; } +static int compactScriptItemsIfNeeded(std::span cp, Vector& items, int numItems, const Font* font) +{ + // https://bugs.webkit.org/show_bug.cgi?id=201214 + // Uniscribe is overly aggressive in separating the runs. It'll split "3d_rotation" into "3", "d", "_" and "rotation" and we + // will ScriptShape them separately. As a result, a ligature for "3d_rotation" in the Material icon set + // (https://www.materialui.co/icon/3d-rotation) will not be used. A quick and dirty hack is to glue them back here, only making + // this apply to the readable characters, digits and _. + + if (!numItems) + return numItems; + + if (font->platformData().hasVariations()) + return numItems; + + bool allGoodCharacters = true; + for (unsigned i = 0; allGoodCharacters && i < cp.size(); ++i) { + const UChar c = cp[i]; + allGoodCharacters = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; + } + if (!allGoodCharacters) + return numItems; + + // Consume entire string into a single run. |items| is at least numItems + 1 long. + items[1] = items[numItems]; + return 1; +} + void ComplexTextController::collectComplexTextRunsForCharacters(std::span cp, unsigned stringLocation, const Font* font) { if (!font) { @@ -197,6 +224,8 @@ void ComplexTextController::collectComplexTextRunsForCharacters(std::span +#include #include #include #include +#include #endif namespace WebCore { @@ -1304,6 +1306,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(unsigned keycode) return 0; } +static const UncheckedKeyHashMap& WPEToWindowsKeyCodeMap() +{ + static UncheckedKeyHashMap* 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 UncheckedKeyHashMap(); + 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/libwpe/PlatformPasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp index e47f5bade7c0a27e8a27f8dc95b51174f025b4a6..016efe9bc0898bb648a33973e771b49ed4be5624 100644 --- a/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp @@ -31,10 +31,18 @@ #include "Pasteboard.h" #include #include +#include +#include #include namespace WebCore { +static UncheckedKeyHashMap& sharedPasteboard() +{ + static NeverDestroyed> pasteboard; + return pasteboard.get(); +} + PlatformPasteboard::PlatformPasteboard(const String&) : m_pasteboard(wpe_pasteboard_get_singleton()) { @@ -59,76 +67,26 @@ int64_t PlatformPasteboard::changeCount() const void PlatformPasteboard::getTypes(Vector& types) const { - struct wpe_pasteboard_string_vector pasteboardTypes = { nullptr, 0 }; - wpe_pasteboard_get_types(m_pasteboard, &pasteboardTypes); - for (auto& typeString : unsafeMakeSpan(pasteboardTypes.strings, pasteboardTypes.length)) { - const auto length = std::min(static_cast(typeString.length), std::numeric_limits::max()); - types.append(String(unsafeMakeSpan(typeString.data, length))); - } - - wpe_pasteboard_string_vector_free(&pasteboardTypes); + for (const auto& type : sharedPasteboard().keys()) + types.append(type); } String PlatformPasteboard::readString(size_t, const String& type) const { - struct wpe_pasteboard_string string = { nullptr, 0 }; - wpe_pasteboard_get_string(m_pasteboard, type.utf8().data(), &string); - if (!string.length) - return String(); - - const auto length = std::min(static_cast(string.length), std::numeric_limits::max()); - String returnValue(unsafeMakeSpan(string.data, length)); - - wpe_pasteboard_string_free(&string); - return returnValue; + return sharedPasteboard().get(type); } void PlatformPasteboard::write(const PasteboardWebContent& content) { - static constexpr auto plainText = "text/plain;charset=utf-8"_s; - static constexpr auto htmlText = "text/html"_s; - - CString textString = content.text.utf8(); - CString markupString = content.markup.utf8(); - - IGNORE_CLANG_WARNINGS_BEGIN("unsafe-buffer-usage-in-libc-call") - std::array pairs = { { - { { nullptr, 0 }, { nullptr, 0 } }, - { { nullptr, 0 }, { nullptr, 0 } }, - } }; - wpe_pasteboard_string_initialize(&pairs[0].type, plainText, strlen(plainText)); - wpe_pasteboard_string_initialize(&pairs[0].string, textString.data(), textString.length()); - wpe_pasteboard_string_initialize(&pairs[1].type, htmlText, strlen(htmlText)); - wpe_pasteboard_string_initialize(&pairs[1].string, markupString.data(), markupString.length()); - struct wpe_pasteboard_string_map map = { pairs.data(), pairs.size() }; - IGNORE_CLANG_WARNINGS_END - - wpe_pasteboard_write(m_pasteboard, &map); - m_changeCount++; - - wpe_pasteboard_string_free(&pairs[0].type); - wpe_pasteboard_string_free(&pairs[0].string); - wpe_pasteboard_string_free(&pairs[1].type); - wpe_pasteboard_string_free(&pairs[1].string); + String plainText = "text/plain;charset=utf-8"_s; + String htmlText = "text/html;charset=utf-8"_s; + sharedPasteboard().set(plainText, content.text); + sharedPasteboard().set(htmlText, content.markup); } void PlatformPasteboard::write(const String& type, const String& string) { - struct wpe_pasteboard_string_pair pairs[] = { - { { nullptr, 0 }, { nullptr, 0 } }, - }; - - auto typeUTF8 = type.utf8(); - auto stringUTF8 = string.utf8(); - wpe_pasteboard_string_initialize(&pairs[0].type, typeUTF8.data(), typeUTF8.length()); - wpe_pasteboard_string_initialize(&pairs[0].string, stringUTF8.data(), stringUTF8.length()); - struct wpe_pasteboard_string_map map = { pairs, 1 }; - - wpe_pasteboard_write(m_pasteboard, &map); - m_changeCount++; - - wpe_pasteboard_string_free(&pairs[0].type); - wpe_pasteboard_string_free(&pairs[0].string); + sharedPasteboard().set(type, string); } Vector PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String&) const diff --git a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp index 6a5b3325d2aae3c4769332fa7488e2ca7dd55ef5..3065482616cb5fbc61913f71822262bcbbbd43cf 100644 --- a/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp +++ b/Source/WebCore/platform/mediastream/libwebrtc/gstreamer/GStreamerVideoDecoderFactory.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/Source/WebCore/platform/network/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp index df27a094a0b2239892c96b4f5835826bcf8d7540..3bbea5c96110c0ae70d944b7f6fb018e438cf8c4 100644 --- a/Source/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/Source/WebCore/platform/network/HTTPHeaderMap.cpp @@ -237,8 +237,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value) auto index = m_commonHeaders.findIf([&](auto& header) { return header.key == name; }); + // Align with Chromium and Firefox, but just for SetCookies where it is critical: + // https://bit.ly/2HCa0iq + String separator = name == HTTPHeaderName::SetCookie ? "playwright-set-cookie-separator"_s : ", "_s; if (index != notFound) - m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, ", "_s, value); + m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, separator, value); else m_commonHeaders.append(CommonHeader { name, value }); } diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h index 0640345cf5f133b7f84d3e32b272871d9beff519..320dce768def18327ee25e889109cd6d75ba4cac 100644 --- a/Source/WebCore/platform/network/NetworkStorageSession.h +++ b/Source/WebCore/platform/network/NetworkStorageSession.h @@ -201,6 +201,7 @@ public: NetworkingContext* context() const; #endif + WEBCORE_EXPORT void setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL&, const String& setCookieValue); WEBCORE_EXPORT HTTPCookieAcceptPolicy cookieAcceptPolicy() const; WEBCORE_EXPORT void setCookie(const Cookie&); diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp index e413db463376bcf31da4cd0f8e2f869f4b6a0a95..6d43a62553f3e82968964a89608a121a72bc3d74 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.cpp +++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp @@ -21,7 +21,7 @@ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -77,6 +77,7 @@ ResourceResponseBase::ResourceResponseBase(std::optional&& , m_httpStatusText(data ? WTF::move(data->httpStatusText) : String { }) , m_httpVersion(data ? WTF::move(data->httpVersion) : String { }) , m_httpHeaderFields(data ? WTF::move(data->httpHeaderFields) : HTTPHeaderMap { }) + , m_httpRequestHeaderFields(data ? data->httpRequestHeaderFields : HTTPHeaderMap { }) , m_networkLoadMetrics(data && data->networkLoadMetrics ? Box::create(WTF::move(*data->networkLoadMetrics)) : Box { }) , m_certificateInfo(data ? WTF::move(data->certificateInfo) : std::nullopt) , m_httpStatusCode(data ? data->httpStatusCode : 0) @@ -277,7 +278,7 @@ const String& ResourceResponseBase::mimeType() const { lazyInit(CommonFieldsOnly); - return m_mimeType; + return m_mimeType; } void ResourceResponseBase::setMimeType(String&& mimeType) @@ -291,7 +292,7 @@ void ResourceResponseBase::setMimeType(String&& mimeType) // FIXME: Should invalidate or update platform response if present. } -long long ResourceResponseBase::expectedContentLength() const +long long ResourceResponseBase::expectedContentLength() const { lazyInit(CommonFieldsOnly); @@ -304,7 +305,7 @@ void ResourceResponseBase::setExpectedContentLength(long long expectedContentLen m_isNull = false; // FIXME: Content length is determined by HTTP Content-Length header. We should update the header, so that it doesn't disagree with m_expectedContentLength. - m_expectedContentLength = expectedContentLength; + m_expectedContentLength = expectedContentLength; // FIXME: Should invalidate or update platform response if present. } @@ -395,7 +396,7 @@ const String& ResourceResponseBase::httpStatusText() const { lazyInit(AllFields); - return m_httpStatusText; + return m_httpStatusText; } void ResourceResponseBase::setHTTPStatusText(String&& statusText) @@ -410,16 +411,16 @@ void ResourceResponseBase::setHTTPStatusText(String&& statusText) const String& ResourceResponseBase::httpVersion() const { lazyInit(AllFields); - + return m_httpVersion; } void ResourceResponseBase::setHTTPVersion(String&& versionText) { lazyInit(AllFields); - + m_httpVersion = versionText; - + // FIXME: Should invalidate or update platform response if present. } @@ -557,12 +558,12 @@ String ResourceResponseBase::httpHeaderField(StringView name) const // If we already have the header, just return it instead of consuming memory by grabing all headers. String value = m_httpHeaderFields.get(name); - if (!value.isEmpty()) + if (!value.isEmpty()) return value; lazyInit(AllFields); - return m_httpHeaderFields.get(name); + return m_httpHeaderFields.get(name); } String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const @@ -576,7 +577,7 @@ String ResourceResponseBase::httpHeaderField(HTTPHeaderName name) const lazyInit(AllFields); - return m_httpHeaderFields.get(name); + return m_httpHeaderFields.get(name); } void ResourceResponseBase::updateHeaderParsedState(HTTPHeaderName name) @@ -686,7 +687,7 @@ void ResourceResponseBase::parseCacheControlDirectives() const m_cacheControlDirectives = WebCore::parseCacheControlDirectives(m_httpHeaderFields); m_haveParsedCacheControlHeader = true; } - + bool ResourceResponseBase::cacheControlContainsNoCache() const { if (!m_haveParsedCacheControlHeader) @@ -707,7 +708,7 @@ bool ResourceResponseBase::cacheControlContainsMustRevalidate() const parseCacheControlDirectives(); return m_cacheControlDirectives.mustRevalidate; } - + bool ResourceResponseBase::cacheControlContainsImmutable() const { if (!m_haveParsedCacheControlHeader) @@ -862,7 +863,7 @@ void ResourceResponseBase::lazyInit(InitLevel initLevel) const bool ResourceResponseBase::equalForWebKitLegacyChallengeComparison(const ResourceResponse& a, const ResourceResponse& b) { if (a.isNull() != b.isNull()) - return false; + return false; if (a.url() != b.url()) return false; if (a.mimeType() != b.mimeType()) @@ -896,7 +897,7 @@ std::optional ResourceResponseBase::getResponseData() cons if (m_isNull) return std::nullopt; lazyInit(AllFields); - + return { ResourceResponseData { URL { m_url }, String { m_mimeType }, @@ -906,6 +907,7 @@ std::optional ResourceResponseBase::getResponseData() cons String { m_httpStatusText }, String { m_httpVersion }, HTTPHeaderMap { m_httpHeaderFields }, + HTTPHeaderMap { m_httpRequestHeaderFields }, m_networkLoadMetrics ? std::optional(*m_networkLoadMetrics) : std::nullopt, m_source, m_type, @@ -982,6 +984,11 @@ std::optional Coder httpRequestHeaderFields; + decoder >> httpRequestHeaderFields; + if (!httpRequestHeaderFields) + return std::nullopt; + std::optional httpStatusCode; decoder >> httpStatusCode; if (!httpStatusCode) @@ -1041,6 +1048,7 @@ std::optional Coder&&); - + WEBCORE_EXPORT std::optional getResponseData() const; protected: @@ -265,6 +265,11 @@ protected: String m_httpStatusText; String m_httpVersion; HTTPHeaderMap m_httpHeaderFields; + +public: + HTTPHeaderMap m_httpRequestHeaderFields; + +protected: Box m_networkLoadMetrics; mutable std::optional m_certificateInfo; @@ -308,7 +313,7 @@ struct ResourceResponseData { ResourceResponseData() = default; ResourceResponseData(ResourceResponseData&&) = default; ResourceResponseData& operator=(ResourceResponseData&&) = default; - ResourceResponseData(URL&& url, String&& mimeType, long long expectedContentLength, String&& textEncodingName, int httpStatusCode, String&& httpStatusText, String&& httpVersion, HTTPHeaderMap&& httpHeaderFields, std::optional&& networkLoadMetrics, ResourceResponseSource source, ResourceResponseBaseType type, ResourceResponseBaseTainting tainting, bool isRedirected, UsedLegacyTLS usedLegacyTLS, WasPrivateRelayed wasPrivateRelayed, String&& proxyName, bool isRangeRequested, std::optional certificateInfo, IPAddressSpace ipAddressSpace) + ResourceResponseData(URL&& url, String&& mimeType, long long expectedContentLength, String&& textEncodingName, int httpStatusCode, String&& httpStatusText, String&& httpVersion, HTTPHeaderMap&& httpHeaderFields, HTTPHeaderMap&& httpRequestHeaderFields, std::optional&& networkLoadMetrics, ResourceResponseSource source, ResourceResponseBaseType type, ResourceResponseBaseTainting tainting, bool isRedirected, UsedLegacyTLS usedLegacyTLS, WasPrivateRelayed wasPrivateRelayed, String&& proxyName, bool isRangeRequested, std::optional certificateInfo, IPAddressSpace ipAddressSpace) : url(WTF::move(url)) , mimeType(WTF::move(mimeType)) , expectedContentLength(expectedContentLength) @@ -317,6 +322,7 @@ struct ResourceResponseData { , httpStatusText(WTF::move(httpStatusText)) , httpVersion(WTF::move(httpVersion)) , httpHeaderFields(WTF::move(httpHeaderFields)) + , httpRequestHeaderFields(WTF::move(httpRequestHeaderFields)) , networkLoadMetrics(WTF::move(networkLoadMetrics)) , source(source) , type(type) @@ -341,6 +347,7 @@ struct ResourceResponseData { String httpStatusText; String httpVersion; HTTPHeaderMap httpHeaderFields; + HTTPHeaderMap httpRequestHeaderFields; std::optional networkLoadMetrics; ResourceResponseBase::Source source; ResourceResponseBase::Type type; diff --git a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm index 3ed98966972014b88f2a4ca24ea615717a9a812c..7b75b20a84474ac8f227666d2d8305a60c1923f5 100644 --- a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm +++ b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm @@ -582,6 +582,27 @@ bool NetworkStorageSession::setCookieFromDOM(const URL& firstParty, const SameSi return false; } +void NetworkStorageSession::setCookiesFromResponse(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& setCookieValue) +{ + auto thirdPartyCookieBlockingDecision = ThirdPartyCookieBlockingDecision::None; + Vector cookieValues = setCookieValue.split('\n'); + size_t count = cookieValues.size(); + auto* cookies = [NSMutableArray arrayWithCapacity:count]; + for (const auto& cookieValue : cookieValues) { + NSString* cookieString = cookieValue.createNSString().autorelease(); + NSString* cookieKey = @"Set-Cookie"; + NSDictionary* headers = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObject:cookieString] forKeys:[NSArray arrayWithObject:cookieKey]]; + NSArray* parsedCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:url.createNSURL().get()]; + [cookies addObject:parsedCookies[0]]; + } +#if ENABLE(OPT_IN_PARTITIONED_COOKIES) && defined(CFN_COOKIE_ACCEPTS_POLICY_PARTITION) && CFN_COOKIE_ACCEPTS_POLICY_PARTITION + String partitionKey = isOptInCookiePartitioningEnabled() ? cookiePartitionIdentifier(firstParty) : String { }; +#else + String partitionKey; +#endif + setHTTPCookiesForURL(cookieStorage().get(), cookies, url.createNSURL().get(), firstParty.createNSURL().get(), nsStringNilIfEmpty(partitionKey).get(), sameSiteInfo, thirdPartyCookieBlockingDecision); +} + static NSHTTPCookieAcceptPolicy httpCookieAcceptPolicy(CFHTTPCookieStorageRef cookieStorage) { ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies)); diff --git a/Source/WebCore/platform/network/curl/CookieJarDB.h b/Source/WebCore/platform/network/curl/CookieJarDB.h index 96e0a63b347c170c963bc7e851f383b91665c5c8..2f0afc26bcc87e9440e201728778892b3fe35543 100644 --- a/Source/WebCore/platform/network/curl/CookieJarDB.h +++ b/Source/WebCore/platform/network/curl/CookieJarDB.h @@ -73,7 +73,7 @@ public: WEBCORE_EXPORT ~CookieJarDB(); private: - CookieAcceptPolicy m_acceptPolicy { CookieAcceptPolicy::Always }; + CookieAcceptPolicy m_acceptPolicy { CookieAcceptPolicy::OnlyFromMainDocumentDomain }; String m_databasePath; bool m_detectedDatabaseCorruption { false }; diff --git a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp index 5a78d6c775542cd62d3b192dc60972fdbea92270..5dab0edfef83cc1672012d94bcb4d6390b91bc97 100644 --- a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp +++ b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp @@ -136,6 +136,12 @@ void NetworkStorageSession::setCookieAcceptPolicy(CookieAcceptPolicy policy) con cookieDatabase().setAcceptPolicy(policy); } +void NetworkStorageSession::setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL& url, const String& setCookieValue) +{ + for (auto& cookieString : setCookieValue.split('\n')) + cookieDatabase().setCookie(firstParty, url, cookieString, CookieJarDB::Source::Network); +} + HTTPCookieAcceptPolicy NetworkStorageSession::cookieAcceptPolicy() const { switch (cookieDatabase().acceptPolicy()) { diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp index f3c07eb9e056bf031d37b1d2d30a2ebcbe4ba42e..c6b732f75b4e3e823d8c3ebc0b825e389e1d175a 100644 --- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp +++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp @@ -531,6 +531,26 @@ void NetworkStorageSession::replaceCookies(const Vector& cookies) g_signal_emit(jar, signalId, 0, nullptr, nullptr); } +void NetworkStorageSession::setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL& url, const String& setCookieValue) +{ + auto origin = urlToSoupURI(url); + if (!origin) + return; + + auto firstPartyURI = urlToSoupURI(firstParty); + if (!firstPartyURI) + return; + + for (auto& cookieString : setCookieValue.split('\n')) { + GUniquePtr cookie(soup_cookie_parse(cookieString.utf8().data(), origin.get())); + + if (!cookie) + continue; + + soup_cookie_jar_add_cookie_full(cookieStorage(), cookie.release(), origin.get(), firstPartyURI.get()); + } +} + void NetworkStorageSession::deleteCookie(const Cookie& cookie, CompletionHandler&& completionHandler) { GUniquePtr targetCookie(cookie.toSoupCookie()); diff --git a/Source/WebCore/platform/text/LocaleICU.cpp b/Source/WebCore/platform/text/LocaleICU.cpp index 2eaf11c3c0739754768810694c0016d7a21a7951..f25e84fe43e2590829146a1d134776ec549de810 100644 --- a/Source/WebCore/platform/text/LocaleICU.cpp +++ b/Source/WebCore/platform/text/LocaleICU.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #if USE(HARFBUZZ) diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp index 8e6023c5f1200884723bd0871bf602ba4a37ad04..582365cfb1c9a109308d0133922ee4d2bc0ae7db 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -39,6 +39,7 @@ #include #include #include +#include "Pasteboard.h" namespace WebCore { @@ -690,7 +691,10 @@ template void getStringData(IDataObject* data, FORMATETC* format, Ve STGMEDIUM store; if (FAILED(data->GetData(format, &store))) return; - dataStrings.append(String({ static_cast(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T) })); + // The string here should be null terminated, but it could come from another app so lets lock it + // to the size to prevent an overflow. + String rawString = String({ static_cast(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T) }); + dataStrings.append(String::fromUTF8(rawString.utf8().data())); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.h b/Source/WebCore/platform/win/ClipboardUtilitiesWin.h index 61624f0c555886e11a82e933aa89a093b5273693..4471b458941d3394d99f85e983cf0d86e1a562d3 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.h +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.h @@ -34,6 +34,7 @@ namespace WebCore { class Document; class DocumentFragment; +class Pasteboard; HGLOBAL createGlobalData(const String&); HGLOBAL createGlobalData(const Vector&); diff --git a/Source/WebCore/platform/win/DragDataWin.cpp b/Source/WebCore/platform/win/DragDataWin.cpp index 0379437d84807e4a8d3846afac5ec8a70e743e70..5b0461bf12535d4900ffaddc2a87826280505233 100644 --- a/Source/WebCore/platform/win/DragDataWin.cpp +++ b/Source/WebCore/platform/win/DragDataWin.cpp @@ -40,12 +40,13 @@ namespace WebCore { -DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet flags, std::optional pageID) +DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet sourceOperationMask, OptionSet flags, OptionSet dragDestinationAction, std::optional pageID) : m_clientPosition(clientPosition) , m_globalPosition(globalPosition) , m_platformDragData(0) , m_draggingSourceOperationMask(sourceOperationMask) , m_applicationFlags(flags) + , m_dragDestinationActionMask(dragDestinationAction) , m_pageID(pageID) , m_dragDataMap(data) { @@ -63,7 +64,7 @@ bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const || (filenamePolicy == ConvertFilenames && (m_dragDataMap.contains(filenameWFormat()->cfFormat) || m_dragDataMap.contains(filenameFormat()->cfFormat))); } -const DragDataMap& DragData::dragDataMap() +const DragDataMap& DragData::dragDataMap() const { if (!m_dragDataMap.isEmpty() || !m_platformDragData) return m_dragDataMap; diff --git a/Source/WebCore/platform/win/KeyEventWin.cpp b/Source/WebCore/platform/win/KeyEventWin.cpp index f6c0cc49e9c39686bb5a5b36c29762173f2b4d1f..f396b564ee4aa7203d1728ff8460837337e31fdd 100644 --- a/Source/WebCore/platform/win/KeyEventWin.cpp +++ b/Source/WebCore/platform/win/KeyEventWin.cpp @@ -41,10 +41,16 @@ namespace WebCore { static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000; -void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type, bool) +void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool) { - // No KeyDown events on Windows to disambiguate. - ASSERT_NOT_REACHED(); + m_type = type; + if (type == PlatformEvent::Type::RawKeyDown) { + m_text = String(); + m_unmodifiedText = String(); + } else { + m_keyIdentifier = String(); + m_windowsVirtualKeyCode = 0; + } } OptionSet PlatformKeyboardEvent::currentStateOfModifierKeys() diff --git a/Source/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp index 89eb26e07f1bc8174ed50f088a1a9e61e227c627..5949b188bf03caa7c35af1966b3879465f2a92f6 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp @@ -1145,7 +1145,21 @@ void Pasteboard::writeCustomData(const Vector& data) } clear(); + if (m_dataObject) { + const auto& customData = data.first(); + customData.forEachPlatformString([&](auto& type, auto& string) { + writeString(type, string); + }); + if (customData.hasSameOriginCustomData() || !customData.origin().isEmpty()) { + customData.forEachCustomString([&](auto& type, auto& string) { + writeString(type, string); + }); + } + return; + } + + // this is the real real clipboard. Prbaobly need to be doing drag data stuff. if (::OpenClipboard(m_owner)) { const auto& customData = data.first(); customData.forEachPlatformStringOrBuffer([](auto& type, auto& stringOrBuffer) { @@ -1184,4 +1198,25 @@ void Pasteboard::write(const Color&) { } +DragDataMap Pasteboard::createDragDataMap() { + DragDataMap dragDataMap; + auto dragObject = dataObject(); + if (!dragObject) + return dragDataMap; + // Enumerate clipboard content and load it in the map. + COMPtr itr; + + if (FAILED(dragObject->EnumFormatEtc(DATADIR_GET, &itr)) || !itr) + return dragDataMap; + + FORMATETC dataFormat; + while (itr->Next(1, &dataFormat, 0) == S_OK) { + Vector dataStrings; + getClipboardData(dragObject.get(), &dataFormat, dataStrings); + if (!dataStrings.isEmpty()) + dragDataMap.set(dataFormat.cfFormat, dataStrings); + } + return dragDataMap; +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 7cf7bbc03d7824b38b097427587367b50978c2c0..00f87e2b8155d18385cd2aae8461c442266634ef 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -1065,8 +1065,10 @@ bool RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update return false; } +#if !PLATFORM(GTK) // Temporal workaround until https://bugs.webkit.org/show_bug.cgi?id=307077 is fixed if (!m_compositing && (m_forceCompositingMode || (isRootFrameCompositor() && page().pageOverlayController().overlayCount()))) enableCompositingMode(true); +#endif bool isPageScroll = !updateRootArg || updateRootArg == &rootRenderLayer(); CheckedPtr updateRoot = &rootRenderLayer(); diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index 7b1911e2444250e1b87bb9fd9b2d6e1e56fa43f0..fdbb83e5ac55b35390f2bf5f383cff5f7bbcf0ae 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -244,13 +244,13 @@ void RenderTextControl::layoutExcludedChildren(RelayoutChildren relayoutChildren } } -#if PLATFORM(IOS_FAMILY) bool RenderTextControl::canScroll() const { auto innerText = innerTextElement(); return innerText && innerText->renderer() && innerText->renderer()->hasNonVisibleOverflow(); } +#if PLATFORM(IOS_FAMILY) int RenderTextControl::innerLineHeight() const { if (auto innerTextElement = this->innerTextElement(); innerTextElement && innerTextElement->renderer()) diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h index 00011d61c20cf7509b03407ecbcc29ce2da0ccca..d939e62c37573487cf4df7a16cf6201b5400cf0c 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -38,8 +38,8 @@ public: WEBCORE_EXPORT HTMLTextFormControlElement& NODELETE textFormControlElement() const; -#if PLATFORM(IOS_FAMILY) bool canScroll() const; +#if PLATFORM(IOS_FAMILY) WEBCORE_EXPORT int innerLineHeight() const; #endif diff --git a/Source/WebCore/workers/WorkerConsoleClient.cpp b/Source/WebCore/workers/WorkerConsoleClient.cpp index fe03d2c8d0625725e07a2aa0eef3a0d9127cf211..9c661ee5f91766bb6d903cfd25f3c7a43d9f3538 100644 --- a/Source/WebCore/workers/WorkerConsoleClient.cpp +++ b/Source/WebCore/workers/WorkerConsoleClient.cpp @@ -257,4 +257,6 @@ void WorkerConsoleClient::screenshot(JSC::JSGlobalObject* lexicalGlobalObject, R InspectorInstrumentation::addMessageToConsole(protect(globalScope()), makeUnique(MessageSource::ConsoleAPI, MessageType::Image, MessageLevel::Log, dataURL, ScriptArguments::create(lexicalGlobalObject, WTF::move(adjustedArguments)), lexicalGlobalObject, /* requestIdentifier */ 0, timestamp)); } +void WorkerConsoleClient::bindingCalled(JSC::JSGlobalObject*, const String&, const String&) { } + } // namespace WebCore diff --git a/Source/WebCore/workers/WorkerConsoleClient.h b/Source/WebCore/workers/WorkerConsoleClient.h index 60e744703647b7593426c59814975bf12dc4ebaa..d5156a30396fb2ad7e73c5c5429a07d56df0c928 100644 --- a/Source/WebCore/workers/WorkerConsoleClient.h +++ b/Source/WebCore/workers/WorkerConsoleClient.h @@ -59,6 +59,7 @@ private: void record(JSC::JSGlobalObject*, Ref&&) override; void recordEnd(JSC::JSGlobalObject*, Ref&&) override; void screenshot(JSC::JSGlobalObject*, Ref&&) override; + void bindingCalled(JSC::JSGlobalObject*, const String& name, const String& arg) override; WorkerOrWorkletGlobalScope& globalScope() { return m_globalScope; } diff --git a/Source/WebGPU/WGSL/UniformityAnalysis.cpp b/Source/WebGPU/WGSL/UniformityAnalysis.cpp index 85806067d986a7f9047708500e1c510fd0df1834..39e066e5882c4fbe8f7b31bfa5d62e3188761709 100644 --- a/Source/WebGPU/WGSL/UniformityAnalysis.cpp +++ b/Source/WebGPU/WGSL/UniformityAnalysis.cpp @@ -118,8 +118,10 @@ struct FunctionInfo { { switch (severity) { case SeverityControl::Error: return requiredToBeUniform[0]; +IGNORE_CLANG_WARNINGS_BEGIN("unsafe-buffer-usage") case SeverityControl::Warning: return requiredToBeUniform[1]; case SeverityControl::Info: return requiredToBeUniform[2]; +IGNORE_CLANG_WARNINGS_END case SeverityControl::Off: return nullptr; } RELEASE_ASSERT_NOT_REACHED(); @@ -311,8 +313,10 @@ std::optional UniformityGraph::processFunction(AST::Function& function) m_currentFunction = &info; info.requiredToBeUniform[0] = info.createNode(); +IGNORE_CLANG_WARNINGS_BEGIN("unsafe-buffer-usage") info.requiredToBeUniform[1] = info.createNode(); info.requiredToBeUniform[2] = info.createNode(); +IGNORE_CLANG_WARNINGS_END info.mayBeNonUniform = info.createNode(); info.cfStart = info.createNode(); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp index dfc334dff3edea4f775d8f59ba3dd303af861735..de87609382fb0de678b10e8ea77a8c5a6f3acbe9 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp @@ -99,6 +99,8 @@ #if PLATFORM(COCOA) #include +#include "NetworkDataTaskCocoa.h" +#include "NetworkSessionCocoa.h" #include #include #endif @@ -1318,6 +1320,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) storageSession->clearPageSpecificDataForResourceLoadStatistics(pageID); } +void NetworkConnectionToWebProcess::setCookieFromResponse(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& setCookieValue) +{ + auto* networkStorageSession = storageSession(); + if (!networkStorageSession) + return; + networkStorageSession->setCookiesFromResponse(firstParty, sameSiteInfo, url, setCookieValue); +} + void NetworkConnectionToWebProcess::removeStorageAccessForFrame(FrameIdentifier frameID, PageIdentifier pageID) { if (CheckedPtr storageSession = m_networkProcess->storageSession(m_sessionID)) diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h index 5d24c2e36dcdbee25a0bb005bf0a20963d442a31..aff9bb1a0a64d689e15f7be57bed9e5bec80be6a 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h @@ -399,6 +399,8 @@ private: void clearPageSpecificData(WebCore::PageIdentifier); + void setCookieFromResponse(const URL& firstParty, const WebCore::SameSiteInfo&, const URL& url, const String& setCookieValue); + void removeStorageAccessForFrame(WebCore::FrameIdentifier, WebCore::PageIdentifier); void logUserInteraction(RegistrableDomain&&); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in index 6f43a9c68ee5c247184e327bdda83ce65df444f5..b34971ca9e296106dda574f165c4f28d157ecdc6 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in @@ -83,6 +83,8 @@ messages -> NetworkConnectionToWebProcess WantsDispatchMessage { ClearPageSpecificData(WebCore::PageIdentifier pageID); + SetCookieFromResponse(URL firstParty, struct WebCore::SameSiteInfo sameSiteInfo, URL url, String setCookieValue); + [EnabledBy=StorageAccessAPIEnabled] RemoveStorageAccessForFrame(WebCore::FrameIdentifier frameID, WebCore::PageIdentifier pageID); LogUserInteraction(WebCore::RegistrableDomain domain) ResourceLoadStatisticsUpdated(Vector statistics) -> () diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm index 446f6d91016132ceb2a28122990e844e4576ed4c..0886e0642ac2353de9184b12b8a0d23d6f0f0fd3 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm @@ -894,6 +894,14 @@ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)data resourceResponse.setDeprecatedNetworkLoadMetrics(WebCore::copyTimingData(taskMetrics.get(), networkDataTask->networkLoadMetrics())); resourceResponse.setProxyName(WTF::move(proxyName)); + + __block WebCore::HTTPHeaderMap requestHeaders; + NSURLSessionTaskTransactionMetrics *m = dataTask._incompleteTaskMetrics.transactionMetrics.lastObject; + [m.request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *) { + requestHeaders.set(String(name), String(value)); + }]; + resourceResponse.m_httpRequestHeaderFields = WTF::move(requestHeaders); + networkDataTask->didReceiveResponse(WTF::move(resourceResponse), negotiatedLegacyTLS, privateRelayed, [completionHandler = makeBlockPtr(completionHandler), taskIdentifier](WebCore::PolicyAction policyAction) { #if !LOG_DISABLED LOG(NetworkSession, "%zu didReceiveResponse completionHandler (%s)", taskIdentifier, toString(policyAction).characters()); diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp index 0a2c25f815f594b2de6168ffd8b083c625e42e1f..682c4584f34d6fab8b576b331561102d34a3751a 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp @@ -166,6 +166,7 @@ void NetworkDataTaskCurl::curlDidReceiveResponse(CurlRequest& request, CurlRespo updateNetworkLoadMetrics(receivedResponse.networkLoadMetrics); m_response.setDeprecatedNetworkLoadMetrics(Box::create(WTF::move(receivedResponse.networkLoadMetrics))); + m_response.m_httpRequestHeaderFields = request.resourceRequest().httpHeaderFields(); handleCookieHeaders(request.resourceRequest(), receivedResponse); diff --git a/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in b/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in index 38aee06c97b6c7d20e0569295bde4192999d9c6e..eb7159615e69a275fe0b52790311209e698458a3 100644 --- a/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in +++ b/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in @@ -455,9 +455,11 @@ ;; FIXME: This should be removed when is fixed. ;; Restrict AppSandboxed processes from creating /Library/Keychains, but allow access to the contents of /Library/Keychains: -(allow file-read-data file-read-metadata - (subpath "/Library/Keychains") - (home-subpath "/Library/Keychains")) +;; Playwright begin +;; (allow file-read-data file-read-metadata +;; (subpath "/Library/Keychains") +;; (home-subpath "/Library/Keychains")) +;; Playwright end ;; Except deny access to new-style iOS Keychain folders which are UUIDs. (deny file-read* file-write* diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp index f7edb09dfd0bcee4b60f4bf8ce16f8cbeea937f8..1c10fb6ea21b897015a5c0092fc8f6cd4fb34c0c 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp @@ -427,6 +427,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr&& inputStream) else m_inputStream = WTF::move(inputStream); + auto& additionalMetrics = additionalNetworkLoadMetricsForWebInspector(); + m_response.m_httpRequestHeaderFields = additionalMetrics.requestHeaders; dispatchDidReceiveResponse(); } diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index f98ae19e9c5fa4b0601572de46b1e0a1c62e92d8..747157cb6b47441ed2c1ca89465c81a89acc7f2a 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -227,6 +227,7 @@ set(WPE_API_HEADER_TEMPLATES ${WEBKIT_DIR}/UIProcess/API/glib/WebKitWebsitePolicies.h.in ${WEBKIT_DIR}/UIProcess/API/glib/WebKitXRPermissionRequest.h.in ${WEBKIT_DIR}/UIProcess/API/glib/webkit.h.in + ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in ) if (ENABLE_2022_GLIB_API) diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake index 86a1febedca9fcbe7203db8cec94e8db1ef25a43..efdc87688149706c783906b643489fbe695d61d2 100644 --- a/Source/WebKit/PlatformWin.cmake +++ b/Source/WebKit/PlatformWin.cmake @@ -54,8 +54,13 @@ list(APPEND WebKit_SOURCES UIProcess/win/AutomationClientWin.cpp UIProcess/win/AutomationSessionClientWin.cpp + + UIProcess/win/InspectorPlaywrightAgentClientWin.cpp UIProcess/win/PageClientImpl.cpp + UIProcess/win/PageInspectorTargetProxyWin.cpp UIProcess/win/WebContextMenuProxyWin.cpp + UIProcess/win/WebPageInspectorEmulationAgentWin.cpp + UIProcess/win/WebPageInspectorInputAgentWin.cpp UIProcess/win/WebPageProxyWin.cpp UIProcess/win/WebPopupMenuProxyWin.cpp UIProcess/win/WebProcessPoolWin.cpp @@ -71,6 +76,7 @@ list(APPEND WebKit_SOURCES WebProcess/MediaCache/WebMediaKeyStorageManager.cpp WebProcess/WebCoreSupport/win/WebPopupMenuWin.cpp + WebProcess/WebCoreSupport/win/WebDragClientWin.cpp WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp diff --git a/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h b/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h index 5c7a6999176357ad21ca673db75363f27cf33790..faa9a55d561a185a659519bcaa5a1026fa3b1921 100644 --- a/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h +++ b/Source/WebKit/Shared/API/Cocoa/WebKitPrivate.h @@ -45,6 +45,7 @@ #import #import #import +#import #import #import #import diff --git a/Source/WebKit/Shared/AuxiliaryProcess.h b/Source/WebKit/Shared/AuxiliaryProcess.h index 04ffbae16bdfe24465e635afce7f5042073158a0..9c87adff05fcdc47fb15cc4bcac86c26882c6e3e 100644 --- a/Source/WebKit/Shared/AuxiliaryProcess.h +++ b/Source/WebKit/Shared/AuxiliaryProcess.h @@ -216,6 +216,11 @@ struct AuxiliaryProcessInitializationParameters { IPC::Connection::Identifier connectionIdentifier; HashMap extraInitializationData; WTF::AuxiliaryProcessType processType; +// Playwright begin +#if !PLATFORM(COCOA) + bool shouldEnableSharedArrayBuffer { false }; +#endif +// Playwright end }; } // namespace WebKit diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h index 63cfe7fc9385af4f17293ad0e43997e688401cd8..e22b7ee6001ee06a731f01c4ca3ab2d3e2e525a8 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h +++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -33,6 +33,7 @@ #if USE(APPKIT) #include OBJC_CLASS NSView; +OBJC_CLASS NSEvent; #endif #if PLATFORM(GTK) @@ -70,11 +71,19 @@ public: #if USE(APPKIT) // FIXME: Share iOS's HandledByInputMethod enum here instead of passing a boolean. NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector&); + NativeWebKeyboardEvent(WebEventType 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, MonotonicTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTF::move(commands)) + { + } #elif PLATFORM(GTK) NativeWebKeyboardEvent(const NativeWebKeyboardEvent&); NativeWebKeyboardEvent(GdkEvent*, const String&, bool isAutoRepeat, Vector&& commands); NativeWebKeyboardEvent(const String&, std::optional>&&, std::optional&&); NativeWebKeyboardEvent(WebEventType, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector&& commands, bool isAutoRepeat, bool isKeypad, OptionSet); + NativeWebKeyboardEvent(WebEventType 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, MonotonicTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTF::move(commands)) + { + } #elif PLATFORM(IOS_FAMILY) enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(::WebEvent *, HandledByInputMethod); @@ -82,6 +91,10 @@ public: #if USE(LIBWPE) enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(struct wpe_input_keyboard_event*, const String&, bool isAutoRepeat, HandledByInputMethod, std::optional>&&, std::optional&&); + NativeWebKeyboardEvent(WebEventType 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, MonotonicTime timestamp) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp) + { + } #endif #if ENABLE(WPE_PLATFORM) NativeWebKeyboardEvent(WPEEvent*, const String&, bool isAutoRepeat); @@ -92,6 +105,10 @@ public: NativeWebKeyboardEvent(struct wpe_input_keyboard_event*, const String&, bool isAutoRepeat, HandledByInputMethod, std::optional>&&, std::optional&&); #elif PLATFORM(WIN) NativeWebKeyboardEvent(HWND, UINT message, WPARAM, LPARAM, Vector&& pendingCharEvents); + NativeWebKeyboardEvent(WebEventType 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, MonotonicTime timestamp) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp) + { + } #endif #if USE(APPKIT) diff --git a/Source/WebKit/Shared/NativeWebMouseEvent.h b/Source/WebKit/Shared/NativeWebMouseEvent.h index 3f1087581732873bef9aab9de8010804a337e3e5..feb044c070a3042b3c4bf2e81078e52d5c8f7382 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h @@ -91,6 +91,11 @@ public: NativeWebMouseEvent(HWND, UINT message, WPARAM, LPARAM, bool, float deviceScaleFactor); #endif +#if PLATFORM(GTK) || USE(LIBWPE) || PLATFORM(WIN) + NativeWebMouseEvent(WebEventType type, WebMouseEventButton button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet modifiers, MonotonicTime timestamp) + : WebMouseEvent({type, modifiers, timestamp}, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, 0, WebEventInputSource::UserDriven) { } +#endif + #if USE(APPKIT) NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/NativeWebWheelEvent.h b/Source/WebKit/Shared/NativeWebWheelEvent.h index b5361fedd7d921f512956d20819c49d425221080..3628908eeaba9dda7c19ded41b6da6e5c148d382 100644 --- a/Source/WebKit/Shared/NativeWebWheelEvent.h +++ b/Source/WebKit/Shared/NativeWebWheelEvent.h @@ -79,6 +79,11 @@ public: NativeWebWheelEvent(HWND, UINT message, WPARAM, LPARAM, float deviceScaleFactor); #endif +#if !USE(APPKIT) + NativeWebWheelEvent(const WebWheelEvent & webWheelEvent) + : WebWheelEvent(webWheelEvent) { } +#endif + #if USE(APPKIT) NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in index 597e611a1b621f049fa034d7934cb7918cad8f87..5829c63b669d57903b73d7078a41ebfe9006fc89 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in @@ -2728,6 +2728,9 @@ class WebCore::AuthenticationChallenge { class WebCore::DragData { #if PLATFORM(COCOA) String pasteboardName(); +#endif +#if PLATFORM(WIN) + WebCore::DragDataMap dragDataMap(); #endif WebCore::IntPoint clientPosition(); WebCore::IntPoint globalPosition(); @@ -3160,6 +3163,7 @@ enum class WebCore::WasPrivateRelayed : bool; String httpStatusText; String httpVersion; WebCore::HTTPHeaderMap httpHeaderFields; + WebCore::HTTPHeaderMap httpRequestHeaderFields; std::optional networkLoadMetrics; WebCore::ResourceResponseBase::Source source; WebCore::ResourceResponseBase::Type type; diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp index fcadde7e024c363ebdf53d1c20436af5d2512e1a..67cd6dce8d6c1bf66e429c29d9ed0a396718cb80 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.cpp +++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp @@ -51,6 +51,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S ASSERT(isKeyboardEventType(type())); } +WebKeyboardEvent::WebKeyboardEvent(WebEventType 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, MonotonicTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) + , m_key(key) + , m_code(code) + , m_keyIdentifier(keyIdentifier) + , m_windowsVirtualKeyCode(windowsVirtualKeyCode) + , m_nativeVirtualKeyCode(nativeVirtualKeyCode) + , m_macCharCode(0) + , m_commands(WTF::move(commands)) + , m_isAutoRepeat(isAutoRepeat) + , m_isKeypad(isKeypad) + , m_isSystemKey(isSystemKey) +{ + ASSERT(isKeyboardEventType(type)); +} + #elif PLATFORM(GTK) WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&& preeditUnderlines, std::optional&& preeditSelectionRange, Vector&& commands, bool isAutoRepeat, bool isKeypad) @@ -74,6 +92,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S ASSERT(isKeyboardEventType(type())); } +WebKeyboardEvent::WebKeyboardEvent(WebEventType 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, MonotonicTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) + , m_key(key) + , m_code(code) + , m_keyIdentifier(keyIdentifier) + , m_windowsVirtualKeyCode(windowsVirtualKeyCode) + , m_nativeVirtualKeyCode(nativeVirtualKeyCode) + , m_macCharCode(0) + , m_commands(WTF::move(commands)) + , m_isAutoRepeat(isAutoRepeat) + , m_isKeypad(isKeypad) + , m_isSystemKey(isSystemKey) +{ + ASSERT(isKeyboardEventType(type)); +} + #elif PLATFORM(IOS_FAMILY) WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, 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) @@ -137,6 +173,27 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S #endif +#if PLATFORM(WIN) || USE(LIBWPE) + +WebKeyboardEvent::WebKeyboardEvent(WebEventType 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, MonotonicTime timestamp) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) + , m_key(key) + , m_code(code) + , m_keyIdentifier(keyIdentifier) + , m_windowsVirtualKeyCode(windowsVirtualKeyCode) + , m_nativeVirtualKeyCode(nativeVirtualKeyCode) + , m_macCharCode(0) + , m_isAutoRepeat(isAutoRepeat) + , m_isKeypad(isKeypad) + , m_isSystemKey(isSystemKey) +{ + ASSERT(isKeyboardEventType(type)); +} + +#endif + WebKeyboardEvent::~WebKeyboardEvent() = default; bool WebKeyboardEvent::isKeyboardEventType(WebEventType type) diff --git a/Source/WebKit/Shared/WebKeyboardEvent.h b/Source/WebKit/Shared/WebKeyboardEvent.h index 8915f44919a131e5e12344362907396b3821e13e..62846c5c837a584c4180d6c5d069fc39c8b58980 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.h +++ b/Source/WebKit/Shared/WebKeyboardEvent.h @@ -42,14 +42,18 @@ public: #if USE(APPKIT) WebKeyboardEvent(WebEvent&&, 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); + WebKeyboardEvent(WebEventType, 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, MonotonicTime timestamp, Vector&& commands); #elif PLATFORM(GTK) WebKeyboardEvent(WebEvent&&, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&&, std::optional&&, Vector&& commands, bool isAutoRepeat, bool isKeypad); + WebKeyboardEvent(WebEventType, 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, MonotonicTime timestamp, Vector&& commands); #elif PLATFORM(IOS_FAMILY) WebKeyboardEvent(WebEvent&&, 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); #elif USE(LIBWPE) || ENABLE(WPE_PLATFORM) WebKeyboardEvent(WebEvent&&, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional>&&, std::optional&&, bool isAutoRepeat, bool isKeypad); + WebKeyboardEvent(WebEventType, 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, MonotonicTime timestamp); #else WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey); + WebKeyboardEvent(WebEventType, 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, MonotonicTime timestamp); #endif const String& text() const LIFETIME_BOUND { return m_text; } @@ -93,6 +97,7 @@ public: static String keyCodeStringForGdkKeycode(unsigned); static String keyIdentifierForGdkKeyval(unsigned); static int windowsKeyCodeForGdkKeyval(unsigned); + static unsigned gdkKeyCodeForWindowsKeyCode(int); static String singleCharacterStringForGdkKeyval(unsigned); #endif diff --git a/Source/WebKit/Shared/WebMouseEvent.h b/Source/WebKit/Shared/WebMouseEvent.h index 3accf5c66062f746029665e4a9ef970418784df2..e16205860562432eedeb017d354cd0c948b0e036 100644 --- a/Source/WebKit/Shared/WebMouseEvent.h +++ b/Source/WebKit/Shared/WebMouseEvent.h @@ -72,6 +72,7 @@ public: WebMouseEventButton button() const { return m_button; } unsigned short buttons() const { return m_buttons; } + void playwrightSetButtons(unsigned short buttons) { m_buttons = buttons; } const WebCore::DoublePoint& position() const { return m_position; } // Relative to the view. void setPosition(const WebCore::DoublePoint& position) { m_position = position; } const WebCore::DoublePoint& globalPosition() const LIFETIME_BOUND { return m_globalPosition; } diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h index d0e04502450eedf0dc1e6104f10fe122edee992e..aaa5dfced49e1f20cbd02da81364dbf0285a04d9 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h @@ -317,6 +317,9 @@ struct WebPageCreationParameters { WebCore::ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking { WebCore::ShouldRelaxThirdPartyCookieBlocking::No }; bool httpsUpgradeEnabled { true }; + + std::optional deviceOrientationOverride { }; + bool shouldPauseInInspectorWhenShown { false }; #if ENABLE(APP_HIGHLIGHTS) WebCore::HighlightVisibility appHighlightsVisible { WebCore::HighlightVisibility::Hidden }; diff --git a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in index 707a31d075afd590890fb3e0054f256b4a567ac1..55ac3de3488b82b77888101d6677fb76c1b1c00c 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in +++ b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in @@ -233,6 +233,9 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; bool httpsUpgradeEnabled; + std::optional deviceOrientationOverride; + bool shouldPauseInInspectorWhenShown; + #if ENABLE(APP_HIGHLIGHTS) WebCore::HighlightVisibility appHighlightsVisible; #endif diff --git a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp index 64bcde96dfe76998f6ed6297be892c6548123049..be05d2e4f6749ef60a13e2c8cf77e3fa6ffd41f7 100644 --- a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp +++ b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp @@ -32,7 +32,7 @@ namespace WebKit { -#if ENABLE(DEVELOPER_MODE) +#if TRUE static String getExecutablePath() { CString executablePath = FileSystem::currentExecutablePath(); @@ -44,7 +44,7 @@ static String getExecutablePath() static String findWebKitProcess(const ASCIILiteral processName) { -#if ENABLE(DEVELOPER_MODE) +#if TRUE static const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH"); if (execDirectory) { String processPath = FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(execDirectory), processName); diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp index 6091f843195ae84a25e955304170d84df8ec012e..6c8ce488b96ffeee50371925df704accf03e154c 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -51,7 +51,7 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(const String& text, std::optional } NativeWebKeyboardEvent::NativeWebKeyboardEvent(WebEventType type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector&& commands, bool isAutoRepeat, bool isKeypad, OptionSet modifiers) - : WebKeyboardEvent(WebEvent(type, modifiers, MonotonicTime::now()), text, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, false, std::nullopt, std::nullopt, WTF::move(commands), isAutoRepeat, isKeypad) + : WebKeyboardEvent(WebEvent(type, modifiers, MonotonicTime::now()), text, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, false, std::nullopt, std::nullopt, WTF::move(commands), false, isKeypad) { } diff --git a/Source/WebKit/Shared/gtk/WebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/WebKeyboardEventGtk.cpp index 092d3c2f493aa18e09f43db2d153d5aa6822e000..65d577e344637c99885b373500d353c1abbd6aea 100644 --- a/Source/WebKit/Shared/gtk/WebKeyboardEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/WebKeyboardEventGtk.cpp @@ -1328,4 +1328,244 @@ String WebKeyboardEvent::singleCharacterStringForGdkKeyval(unsigned keyval) } } +static const UncheckedKeyHashMap& gdkToWindowsKeyCodeMap() +{ + static UncheckedKeyHashMap* 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 UncheckedKeyHashMap(); + for (unsigned gdkKeyCode : gdkKeyCodes) { + int winKeyCode = WebKeyboardEvent::windowsKeyCodeForGdkKeyval(gdkKeyCode); + // If several gdk key codes map to the same win key code first one is used. + result->add(winKeyCode, gdkKeyCode); + } + }); + return *result; +} + +unsigned WebKeyboardEvent::gdkKeyCodeForWindowsKeyCode(int keycode) +{ + return gdkToWindowsKeyCodeMap().get(keycode); +} + } // namespace WebKit diff --git a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp index 7d054a56b04d1b19f12e6463077bccb67adcad25..bab6718c22da62179df92dcead696c7610cb4a9d 100644 --- a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp +++ b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp @@ -51,6 +51,15 @@ __attribute__((weak)) extern "C" int __llvm_profile_dump(void); namespace WebKit { +static bool hasArgument(const char* argument, int argc, char** argv) +{ + for (int i = 0; i < argc; ++i) { + if (!strcmp(argument, argv[i])) + return true; + } + return false; +} + AuxiliaryProcessMainCommon::AuxiliaryProcessMainCommon() { #if ENABLE(BREAKPAD) @@ -91,6 +100,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv) } #endif +// Playwright begin + if (hasArgument("--enable-shared-array-buffer", argc, argv)) + m_parameters.shouldEnableSharedArrayBuffer = true; +// Playwright end return true; } diff --git a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp index b321d93d23d0d1862385b022569dc65323e8691c..ba3bcc9bc20b9512b9288cb2d7e5a3d8b90a0e37 100644 --- a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp +++ b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp @@ -47,6 +47,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv) m_parameters.connectionIdentifier = IPC::Connection::Identifier { reinterpret_cast(parseIntegerAllowingTrailingJunk(StringView::fromLatin1(argv[++i])).value_or(0)) }; else if (!strcmp(argv[i], "-processIdentifier") && i + 1 < argc) m_parameters.processIdentifier = ObjectIdentifier(parseIntegerAllowingTrailingJunk(StringView::fromLatin1(argv[++i])).value_or(0)); +// Playwright begin + else if (!strcmp(argv[i], "-enable-shared-array-buffer")) + m_parameters.shouldEnableSharedArrayBuffer = true; +// Playwright end else if (!strcmp(argv[i], "-configure-jsc-for-testing")) JSC::Config::configureForTesting(); else if (!strcmp(argv[i], "-disable-jit")) diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt index 382ea8985d8781d7d49f12a90bf0ecc65232985f..ebe6f275fed47f09490052f0548641b1dec4b8f4 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt @@ -403,6 +403,7 @@ UIProcess/AboutSchemeHandler.cpp UIProcess/AuxiliaryProcessProxy.cpp UIProcess/BackgroundProcessResponsivenessTimer.cpp UIProcess/BrowsingContextGroup.cpp +UIProcess/BrowserInspectorPipe.cpp UIProcess/DeviceIdHashSaltStorage.cpp UIProcess/DisplayLink.cpp UIProcess/DisplayLinkProcessProxyClient.cpp @@ -414,17 +415,21 @@ UIProcess/FrameLoadState.cpp UIProcess/FrameProcess.cpp UIProcess/GeolocationPermissionRequestManagerProxy.cpp UIProcess/GeolocationPermissionRequestProxy.cpp +UIProcess/InspectorDialogAgent.cpp +UIProcess/InspectorPlaywrightAgent.cpp UIProcess/LegacyGlobalSettings.cpp UIProcess/MediaKeySystemPermissionRequestManagerProxy.cpp UIProcess/MediaKeySystemPermissionRequestProxy.cpp UIProcess/OverrideLanguages.cpp UIProcess/PageClient.cpp UIProcess/PageLoadState.cpp +UIProcess/PlaywrightFullScreenManagerProxyClient.cpp UIProcess/ProcessActivityGroup.cpp UIProcess/ProcessAssertion.cpp UIProcess/ProcessThrottler.cpp UIProcess/ProvisionalFrameProxy.cpp UIProcess/ProvisionalPageProxy.cpp +UIProcess/RemoteInspectorPipe.cpp UIProcess/RemotePageDrawingAreaProxy.cpp UIProcess/RemotePageFullscreenManagerProxy.cpp UIProcess/RemotePagePlaybackSessionManagerProxy.cpp @@ -472,6 +477,8 @@ UIProcess/WebOpenPanelResultListenerProxy.cpp UIProcess/WebPageDiagnosticLoggingClient.cpp UIProcess/WebPageGroup.cpp UIProcess/WebPageInjectedBundleClient.cpp +UIProcess/WebPageInspectorEmulationAgent.cpp +UIProcess/WebPageInspectorInputAgent.cpp UIProcess/WebPageProxy.cpp UIProcess/WebPageProxyMessageReceiverRegistration.cpp UIProcess/WebPageProxyTesting.cpp @@ -641,6 +648,7 @@ UIProcess/Inspector/WebPageDebuggable.cpp UIProcess/Inspector/WebPageInspectorController.cpp UIProcess/Inspector/Agents/InspectorBrowserAgent.cpp +UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp UIProcess/Media/AudioSessionRoutingArbitratorProxy.cpp UIProcess/Media/MediaUsageManager.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt index 8f5e05d7905c09452701a390277d8528d3c53170..3ac17db7930b41d33d7e0f6ee9564b997967a8a6 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt @@ -286,6 +286,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm @nonARC UIProcess/API/Cocoa/_WKAttachment.mm @nonARC UIProcess/API/Cocoa/_WKAutomationSession.mm @nonARC UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm @nonARC +UIProcess/API/Cocoa/_WKBrowserInspector.mm @nonARC UIProcess/API/Cocoa/_WKContentRuleListAction.mm @nonARC UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm @nonARC UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @nonARC @no-unify diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt index 4b68f079d9d43d1b0bef8e3b31cd0d6f3a730ae9..3799718e6e5791791335171a8adb0365231501bf 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -134,6 +134,7 @@ UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify UIProcess/API/glib/WebKitClipboardPermissionRequest.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 @@ -263,6 +264,7 @@ UIProcess/linux/MemoryPressureMonitor.cpp UIProcess/WebsiteData/glib/WebsiteDataStoreGLib.cpp UIProcess/WebsiteData/soup/WebsiteDataStoreSoup.cpp +UIProcess/glib/BrowserInspectorWebSocketServer.cpp UIProcess/glib/DRMMainDevice.cpp @no-unify UIProcess/glib/DisplayLinkGLib.cpp UIProcess/glib/DisplayVBlankMonitor.cpp @@ -270,6 +272,7 @@ UIProcess/glib/DisplayVBlankMonitorDRM.cpp UIProcess/glib/DisplayVBlankMonitorThreaded.cpp UIProcess/glib/DisplayVBlankMonitorTimer.cpp UIProcess/glib/FenceMonitor.cpp +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/ScreenManager.cpp UIProcess/glib/SystemSettingsManagerProxy.cpp UIProcess/glib/WebPageProxyGLib.cpp @@ -287,9 +290,9 @@ UIProcess/gtk/DisplayX11.cpp @no-unify UIProcess/gtk/DisplayWayland.cpp @no-unify UIProcess/gtk/GRefPtrGtk.cpp @no-unify UIProcess/gtk/GtkUtilities.cpp @no-unify -UIProcess/gtk/WebDateTimePickerGtk.cpp UIProcess/gtk/HardwareAccelerationManager.cpp UIProcess/gtk/KeyBindingTranslator.cpp +UIProcess/gtk/PageInspectorTargetProxyGtk.cpp UIProcess/gtk/PointerLockManager.cpp @no-unify UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify UIProcess/gtk/PointerLockManagerX11.cpp @no-unify @@ -303,6 +306,9 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp UIProcess/gtk/WebColorPickerGtk.cpp UIProcess/gtk/WebContextMenuProxyGtk.cpp UIProcess/gtk/WebDataListSuggestionsDropdownGtk.cpp +UIProcess/gtk/WebDateTimePickerGtk.cpp +UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp +UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp UIProcess/gtk/WebPageProxyGtk.cpp @no-unify UIProcess/gtk/WebPasteboardProxyGtk.cpp UIProcess/gtk/WebPopupMenuProxyGtk.cpp diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt index 3d1ed6156127f02614905e30835fa4c6334ae914..fb362b66d00c2081d6eb5380fb2bd7967223f489 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -138,6 +138,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 @@ -174,6 +175,7 @@ UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify UIProcess/API/glib/WebKitOptionMenuItem.cpp @no-unify UIProcess/API/glib/WebKitPermissionRequest.cpp @no-unify UIProcess/API/glib/WebKitPermissionStateQuery.cpp @no-unify +UIProcess/API/glib/WebKitPointerLockPermissionRequest.cpp @no-unify UIProcess/API/glib/WebKitPolicyDecision.cpp @no-unify UIProcess/API/glib/WebKitPrivate.cpp @no-unify UIProcess/API/glib/WebKitProtocolHandler.cpp @no-unify @@ -242,6 +244,7 @@ UIProcess/Gamepad/wpe/PlatformGamepadWPE.cpp UIProcess/geoclue/GeoclueGeolocationProvider.cpp +UIProcess/glib/BrowserInspectorWebSocketServer.cpp UIProcess/glib/DRMMainDevice.cpp @no-unify UIProcess/glib/DisplayLinkGLib.cpp UIProcess/glib/DisplayVBlankMonitor.cpp @@ -249,6 +252,7 @@ UIProcess/glib/DisplayVBlankMonitorDRM.cpp UIProcess/glib/DisplayVBlankMonitorThreaded.cpp UIProcess/glib/DisplayVBlankMonitorTimer.cpp UIProcess/glib/FenceMonitor.cpp +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/ScreenManager.cpp UIProcess/glib/SystemSettingsManagerProxy.cpp UIProcess/glib/WebPageProxyGLib.cpp @@ -284,9 +288,15 @@ UIProcess/soup/WebProcessPoolSoup.cpp UIProcess/wpe/AcceleratedBackingStore.cpp UIProcess/wpe/DisplayVBlankMonitorWPE.cpp +UIProcess/wpe/PageInspectorTargetProxyWPE.cpp UIProcess/wpe/ScreenManagerWPE.cpp UIProcess/wpe/SystemSettingsManagerProxyWPE.cpp UIProcess/wpe/WPEUtilities.cpp +UIProcess/wpe/WebColorPickerWPE.cpp +UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp +UIProcess/wpe/WebDateTimePickerWPE.cpp +UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp +UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp UIProcess/wpe/WebPageProxyWPE.cpp UIProcess/wpe/WebPasteboardProxyWPE.cpp UIProcess/wpe/WebPreferencesWPE.cpp diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp index 367ad615c527a09f3c3d3d86bf7eca87afbc13ed..9ef85591e159555c93e5b7a9635d5e289c22a243 100644 --- a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp @@ -261,6 +261,11 @@ BrowsingContextGroup* PageConfiguration::preferredBrowsingContextGroup() const return nullptr; } +WebKit::WebPageProxy* PageConfiguration::openerPageForInspector() const +{ + return m_data.openerPageForInspector.get(); +} + WebPageProxy* PageConfiguration::pageToCloneSessionStorageFrom() const { return m_data.pageToCloneSessionStorageFrom.get(); diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.h b/Source/WebKit/UIProcess/API/APIPageConfiguration.h index b2227e338dcd10bfdaaf1a4c4d632003cf9e6f73..3afcd9c4f12d7cf755f9b849da7dfb98812afdf7 100644 --- a/Source/WebKit/UIProcess/API/APIPageConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.h @@ -173,6 +173,10 @@ public: WebKit::WebPageProxy* NODELETE relatedPage() const; void setRelatedPage(WeakPtr&& relatedPage) { m_data.relatedPage = WTF::move(relatedPage); } + // This is similar to relatedPage(), but it is also set for noopener links. + WebKit::WebPageProxy* openerPageForInspector() const; + void setOpenerPageForInspector(WeakPtr&& openerPageForInspector) { m_data.openerPageForInspector = WTF::move(openerPageForInspector); } + WebKit::WebPageProxy* NODELETE pageToCloneSessionStorageFrom() const; void NODELETE setPageToCloneSessionStorageFrom(WeakPtr&&); @@ -540,6 +544,7 @@ private: #endif RefPtr pageGroup; WeakPtr relatedPage; + WeakPtr openerPageForInspector; Box> openerInfo; WebCore::Site openedSite; bool processInheritedFromOpener { false }; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp index 182dacc96abaab8d5fc9be0658dd1683f48af4db..80d6939f779a5d9a46e1a916cafef718faab9326 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp @@ -56,6 +56,10 @@ Ref ProcessPoolConfiguration::copy() copy->m_ignoreSynchronousMessagingTimeoutsForTesting = this->m_ignoreSynchronousMessagingTimeoutsForTesting; copy->m_attrStyleEnabled = this->m_attrStyleEnabled; copy->m_shouldThrowExceptionForGlobalConstantRedeclaration = this->m_shouldThrowExceptionForGlobalConstantRedeclaration; +#if PLATFORM(MAC) + copy->m_forceOverlayScrollbars = this->m_forceOverlayScrollbars; +#endif + copy->m_overrideLanguages = this->m_overrideLanguages; /* playwright revert fb205fb */ copy->m_alwaysRunsAtBackgroundPriority = this->m_alwaysRunsAtBackgroundPriority; copy->m_shouldTakeUIBackgroundAssertion = this->m_shouldTakeUIBackgroundAssertion; copy->m_shouldCaptureDisplayInUIProcess = this->m_shouldCaptureDisplayInUIProcess; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h index 2b0e5565fd123126f1c6db65059975a344f152df..99b237e2736cd1b5c0e93dfcef5c81ab29ea74c1 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h @@ -49,7 +49,7 @@ public: explicit ProcessPoolConfiguration(); virtual ~ProcessPoolConfiguration(); - + Ref copy(); bool usesSingleWebProcess() const { return m_usesSingleWebProcess; } @@ -93,10 +93,20 @@ public: bool attrStyleEnabled() const { return m_attrStyleEnabled; } void setAttrStyleEnabled(bool enabled) { m_attrStyleEnabled = enabled; } - + bool shouldThrowExceptionForGlobalConstantRedeclaration() const { return m_shouldThrowExceptionForGlobalConstantRedeclaration; } void setShouldThrowExceptionForGlobalConstantRedeclaration(bool shouldThrow) { m_shouldThrowExceptionForGlobalConstantRedeclaration = shouldThrow; } - + +#if PLATFORM(MAC) + bool forceOverlayScrollbars() const { return m_forceOverlayScrollbars; } + void setForceOverlayScrollbars(bool forceOverlayScrollbars) { m_forceOverlayScrollbars = forceOverlayScrollbars; } +#endif + + /* playwright revert fb205fb */ + const Vector& overrideLanguages() const { return m_overrideLanguages; } + void setOverrideLanguages(Vector&& languages) { m_overrideLanguages = WTF::move(languages); } + /* end playwright revert fb205fb */ + bool alwaysRunsAtBackgroundPriority() const { return m_alwaysRunsAtBackgroundPriority; } void setAlwaysRunsAtBackgroundPriority(bool alwaysRunsAtBackgroundPriority) { m_alwaysRunsAtBackgroundPriority = alwaysRunsAtBackgroundPriority; } @@ -177,6 +187,10 @@ private: bool m_ignoreSynchronousMessagingTimeoutsForTesting { false }; bool m_attrStyleEnabled { false }; bool m_shouldThrowExceptionForGlobalConstantRedeclaration { true }; +#if PLATFORM(MAC) + bool m_forceOverlayScrollbars { false }; +#endif + Vector m_overrideLanguages; /* playwright revert fb205fb */ bool m_alwaysRunsAtBackgroundPriority { false }; bool m_shouldTakeUIBackgroundAssertion { true }; bool m_shouldCaptureDisplayInUIProcess { DEFAULT_CAPTURE_DISPLAY_IN_UI_PROCESS }; diff --git a/Source/WebKit/UIProcess/API/APIUIClient.h b/Source/WebKit/UIProcess/API/APIUIClient.h index d9f80360027a2e0c9dd5a3594189dddfde53966d..c6862db4346514707fb84427123fb4ce568ffc99 100644 --- a/Source/WebKit/UIProcess/API/APIUIClient.h +++ b/Source/WebKit/UIProcess/API/APIUIClient.h @@ -115,6 +115,7 @@ public: virtual void runJavaScriptAlert(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(); } virtual void runJavaScriptConfirm(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(false); } virtual void runJavaScriptPrompt(WebKit::WebPageProxy&, const WTF::String&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, 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) { } diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.cpp b/Source/WebKit/UIProcess/API/C/WKInspector.cpp index 5ae69462a4c5a61e098e4df7def6dec3c842e167..e04134e2d91bfc5b1832a7a641614483c748513a 100644 --- a/Source/WebKit/UIProcess/API/C/WKInspector.cpp +++ b/Source/WebKit/UIProcess/API/C/WKInspector.cpp @@ -28,6 +28,11 @@ #if !PLATFORM(IOS_FAMILY) +#if PLATFORM(WIN) +#include "BrowserInspectorPipe.h" +#include "InspectorPlaywrightAgentClientWin.h" +#endif + #include "WKAPICast.h" #include "WebFrameProxy.h" #include "WebInspectorUIProxy.h" @@ -131,4 +136,11 @@ void WKInspectorToggleElementSelection(WKInspectorRef inspectorRef) protect(toImpl(inspectorRef))->toggleElementSelection(); } +void WKInspectorInitializeRemoteInspectorPipe(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit) +{ +#if PLATFORM(WIN) + initializeBrowserInspectorPipe(makeUnique(configureDataStore, createPage, quit)); +#endif +} + #endif // !PLATFORM(IOS_FAMILY) diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.h b/Source/WebKit/UIProcess/API/C/WKInspector.h index 026121d114c5fcad84c1396be8d692625beaa3bd..edd6e5cae033124c589959a42522fde07a42fdf6 100644 --- a/Source/WebKit/UIProcess/API/C/WKInspector.h +++ b/Source/WebKit/UIProcess/API/C/WKInspector.h @@ -66,6 +66,10 @@ WK_EXPORT void WKInspectorTogglePageProfiling(WKInspectorRef inspector); WK_EXPORT bool WKInspectorIsElementSelectionActive(WKInspectorRef inspector); WK_EXPORT void WKInspectorToggleElementSelection(WKInspectorRef inspector); +typedef void (*ConfigureDataStoreCallback)(WKWebsiteDataStoreRef dataStore); +typedef WKPageRef (*CreatePageCallback)(WKPageConfigurationRef configuration); +typedef void (*QuitCallback)(); +WK_EXPORT void WKInspectorInitializeRemoteInspectorPipe(ConfigureDataStoreCallback, CreatePageCallback, QuitCallback); #ifdef __cplusplus } #endif diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp index 3ceafb8efa81d2ea5d6d5db862564e5d9549fd50..5aad4b41ff5975d2e4b499e407a41e3fe1983b90 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp @@ -1913,6 +1913,13 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient m_client.addMessageToConsole(toAPI(&page), toAPI(message.impl()), m_client.base.clientInfo); } + void handleJavaScriptDialog(WebPageProxy& page, bool accept, const String& value) final { + if (m_client.handleJavaScriptDialog) { + m_client.handleJavaScriptDialog(toAPI(&page), accept, toAPI(value.impl()), m_client.base.clientInfo); + return; + } + } + void setStatusText(WebPageProxy* page, const String& text) final { if (!m_client.setStatusText) @@ -1950,6 +1957,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/C/WKPageUIClient.h b/Source/WebKit/UIProcess/API/C/WKPageUIClient.h index ae4a98c2fe5782eb2356dc8b6b486f6b44db6db3..62b2f3c351fe287af11c1ee2815f1fabe044d537 100644 --- a/Source/WebKit/UIProcess/API/C/WKPageUIClient.h +++ b/Source/WebKit/UIProcess/API/C/WKPageUIClient.h @@ -98,6 +98,7 @@ typedef void (*WKPageRunBeforeUnloadConfirmPanelCallback)(WKPageRef page, WKStri typedef void (*WKPageRunJavaScriptAlertCallback)(WKPageRef page, WKStringRef alertText, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void *clientInfo); typedef void (*WKPageRunJavaScriptConfirmCallback)(WKPageRef page, WKStringRef message, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void *clientInfo); typedef void (*WKPageRunJavaScriptPromptCallback)(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void *clientInfo); +typedef void (*WKPageHandleJavaScriptDialogCallback)(WKPageRef page, bool accept, WKStringRef value, const void *clientInfo); typedef void (*WKPageRequestStorageAccessConfirmCallback)(WKPageRef page, WKFrameRef frame, WKStringRef requestingDomain, WKStringRef currentDomain, WKPageRequestStorageAccessConfirmResultListenerRef listener, const void *clientInfo); typedef void (*WKPageTakeFocusCallback)(WKPageRef page, WKFocusDirection direction, const void *clientInfo); typedef void (*WKPageFocusCallback)(WKPageRef page, const void *clientInfo); @@ -1366,6 +1367,7 @@ typedef struct WKPageUIClientV14 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; } WKPageUIClientV14; typedef struct WKPageUIClientV15 { @@ -1473,6 +1475,7 @@ typedef struct WKPageUIClientV15 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1584,6 +1587,7 @@ typedef struct WKPageUIClientV16 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1698,6 +1702,7 @@ typedef struct WKPageUIClientV17 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1812,6 +1817,7 @@ typedef struct WKPageUIClientV18 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1928,6 +1934,7 @@ typedef struct WKPageUIClientV19 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h index acaeaef1be6d64f16d56d966db12cf9bb1f0507e..bb81783b20e33f69ceef2d00785a2e9c811dabe8 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h @@ -153,6 +153,12 @@ WK_SWIFT_UI_ACTOR */ - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(WK_SWIFT_UI_ACTOR 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; /*! @abstract A delegate to request permission for microphone audio and camera video access. @param webView The web view invoking the delegate method. diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h index dcab0400bfdd58f9d16726aba6ce66492f7be34b..a1337cc7ab9f04fea3f51a3003fdb946ce3d34e5 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h @@ -132,6 +132,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) @property (nullable, nonatomic, copy) NSArray *proxyConfigurations NS_REFINED_FOR_SWIFT API_AVAILABLE(macos(14.0), ios(17.0)); #endif +- (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 632bf6f982628fe174eac150b36a10c1d7677b09..09f3075420aa9aa84a93c40533d3eea7acbdc587 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm @@ -57,6 +57,7 @@ #import "_WKWebPushActionInternal.h" #import "_WKWebsiteDataStoreConfigurationInternal.h" #import "_WKWebsiteDataStoreDelegate.h" +#import #import #import #import @@ -532,6 +533,11 @@ - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date comple }); } +- (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 0000000000000000000000000000000000000000..8938effdcc896cb45f75e3445fbeac6054f69cc6 --- /dev/null +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class WKWebView; + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserContext : NSObject +@property (nonatomic, strong) WKWebsiteDataStore *dataStore; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +@property (nonatomic, strong) WKProcessPool *processPool; +#pragma clang diagnostic pop +@end + +@protocol _WKBrowserInspectorDelegate +- (WKWebView *)createNewPage:(uint64_t)sessionID; +- (_WKBrowserContext *)createBrowserContext:(NSString *)proxyServer WithBypassList:(NSString *)proxyBypassList; +- (void)deleteBrowserContext:(uint64_t)sessionID; +- (void)quit; +@end + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserInspector : NSObject ++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate headless:(BOOL)headless; +@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 0000000000000000000000000000000000000000..69eb9c6aa30beb8ea21a0ef647e463043a868ab8 --- /dev/null +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "_WKBrowserInspector.h" + +#include "BrowserInspectorPipe.h" +#include "InspectorPlaywrightAgentClientMac.h" +#include "PageClientImplMac.h" +#include "WebKit2Initialize.h" + +#import "WKWebView.h" + +using namespace WebKit; + +@implementation _WKBrowserInspector + ++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate headless:(BOOL)headless +{ +#if ENABLE(REMOTE_INSPECTOR) + InitializeWebKit2(); + PageClientImpl::setHeadless(headless); + initializeBrowserInspectorPipe(makeUnique(delegate, headless)); +#endif +} + +@end + +@implementation _WKBrowserContext +- (void)dealloc +{ + [_dataStore release]; + [_processPool release]; + _dataStore = nil; + _processPool = nil; + [super dealloc]; +} +@end diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h index bcfc045d528aff77f639f53b9ebbbc4487050e39..08e1ec9a39e54fff521dbc65822f6c352087b0c0 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h @@ -67,6 +67,7 @@ WK_EXTERN WK_API_DEPRECATED("Creating and using multiple instances of WKProcessP @property (nonatomic) pid_t presentingApplicationPID WK_API_AVAILABLE(macos(10.13), ios(11.0)); @property (nonatomic) audit_token_t presentingApplicationProcessToken WK_API_AVAILABLE(macos(10.13), ios(11.3)); @property (nonatomic) BOOL processSwapsOnNavigation WK_API_AVAILABLE(macos(10.14), ios(12.0)); +@property (nonatomic) BOOL forceOverlayScrollbars WK_API_AVAILABLE(macos(10.14)); @property (nonatomic) BOOL alwaysKeepAndReuseSwappedProcesses WK_API_AVAILABLE(macos(10.14), ios(12.0)); @property (nonatomic) BOOL processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol WK_API_AVAILABLE(macos(12.0), ios(15.0)); @property (nonatomic) BOOL prewarmsProcessesAutomatically WK_API_AVAILABLE(macos(10.14.4), ios(12.2)); diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm index 63e3701355c7e47568b4506cdced95a46ff375af..014081a828011fa403676839c27f8514b3b73741 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm @@ -244,6 +244,16 @@ - (BOOL)processSwapsOnNavigation return _processPoolConfiguration->processSwapsOnNavigation(); } +- (void)setForceOverlayScrollbars:(BOOL)force +{ + _processPoolConfiguration->setForceOverlayScrollbars(force); +} + +- (BOOL)forceOverlayScrollbars +{ + return _processPoolConfiguration->forceOverlayScrollbars(); +} + - (void)setPrewarmsProcessesAutomatically:(BOOL)prewarms { _processPoolConfiguration->setIsAutomaticProcessWarmingEnabled(prewarms); diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h index 4974e14214e2bb3e982325b885bab33e54f83998..cacdf8c71fab248d38d2faf03f7affdcfed1ef62 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h @@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN @class _WKUserContentWorld; @class WKContentWorld; @class WKWebView; +@class WKContentWorld; typedef NS_ENUM(NSInteger, _WKUserStyleLevel) { _WKUserStyleUserLevel, diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm index 4e688f53f9b1022b423e6ae171f042ddfcb858e0..611cd57e8ce91f64bc379b7be952f0e2ceb3e828 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm @@ -28,6 +28,9 @@ #import #import +#import +#import + @implementation _WKWebPushSubscriptionData - (void)dealloc diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..77f295edf36e1f6ca156afbab06501ae6d0e8f11 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebKitBrowserInspector.h" + +#include "BrowserInspectorPipe.h" +#include "BrowserInspectorWebSocketServer.h" +#include "InspectorPlaywrightAgentClientGLib.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, + QUIT_APPLICATION, + + 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 signal 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); + + /** + * WebKitBrowserInspector::quit-application: + * @inspector: the #WebKitBrowserInspector on which the signal is emitted + * + * Emitted when the inspector is requested to close the browser application. + * + * This signal is emitted when inspector receives 'Browser.close' command + * from its remote client. If the signal is not handled the command will fail. + */ + signals[QUIT_APPLICATION] = g_signal_new( + "quit-application", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitBrowserInspectorClass, quit_application), + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +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); +} + +void webkitBrowserInspectorQuitApplication() +{ + g_signal_emit(webkit_browser_inspector_get_default(), signals[QUIT_APPLICATION], 0, NULL); +} + +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(const char* defaultProxyURI, const char* const* ignoreHosts) +{ + WebKit::initializeBrowserInspectorPipe(makeUnique(String::fromUTF8(defaultProxyURI), ignoreHosts)); +} + +/** + * webkit_browser_inspector_initialize_web_socket: + * @port: port number to start the remote debugging server on + * @defaultProxyURI: default proxy URI + * @ignoreHosts: list of hosts to ignore for proxy + * + * Creates browser inspector and configures HTTP server to communicate with + * remote debugging clients on the specified port. + */ +void webkit_browser_inspector_initialize_web_socket(unsigned port, const char* defaultProxyURI, const char* const* ignoreHosts) +{ + WebKit::initializeBrowserInspectorWebSocket(port, makeUnique(String::fromUTF8(defaultProxyURI), ignoreHosts)); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h new file mode 100644 index 0000000000000000000000000000000000000000..e0b1da48465c850f541532ed961d1b778bea6028 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "WebKitBrowserInspector.h" +#include "WebPageProxy.h" + +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext*); +void webkitBrowserInspectorQuitApplication(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp b/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp index c816d0248895d9aa670e2226798237c696451b45..4d317eb4aaa630a97c03d70e7b15b05460354b01 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitProtocolHandler.cpp @@ -160,51 +160,7 @@ static bool canvasAccelerationEnabled(WebKitURISchemeRequest* request) return webkit_settings_get_enable_2d_canvas_acceleration(webkit_web_view_get_settings(webView)); } -static bool uiProcessContextIsEGL() -{ -#if PLATFORM(GTK) - return Display::singleton().glDisplayIsSharedWithGtk(); -#else - return true; -#endif -} - -static const char* openGLAPI() -{ - if (epoxy_is_desktop_gl()) - return "OpenGL (libepoxy)"; - return "OpenGL ES 2 (libepoxy)"; -} - -#if PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) -static String dmabufRendererWithSupportedBuffers() -{ - StringBuilder buffers; - buffers.append("DMABuf (Supported buffers: "_s); - -#if PLATFORM(GTK) - auto mode = AcceleratedBackingStore::rendererBufferTransportMode(); -#else - OptionSet mode; - if (wpe_display_get_drm_device(wpe_display_get_primary())) - mode.add(RendererBufferTransportMode::Hardware); - mode.add(RendererBufferTransportMode::SharedMemory); -#endif - - if (mode.contains(RendererBufferTransportMode::Hardware)) - buffers.append("Hardware"_s); - if (mode.contains(RendererBufferTransportMode::SharedMemory)) { - if (mode.contains(RendererBufferTransportMode::Hardware)) - buffers.append(", "_s); - buffers.append("Shared Memory"_s); - } - - buffers.append(')'); - return buffers.toString(); -} - #if USE(LIBDRM) - // Base on function 'drmGetFormatName' from 'https://gitlab.freedesktop.org/mesa/drm/-/blob/main/xf86drm.c'. static String webkitDrmGetFormatName(uint32_t format) { @@ -258,47 +214,6 @@ static String modifierListToString(const Vector& modifiers) #endif } -static String renderBufferDescription(WebKitURISchemeRequest* request) -{ - StringBuilder bufferDescription; - auto description = webkitWebViewGetRendererBufferDescription(webkit_uri_scheme_request_get_web_view(request)); - if (description.fourcc) { - auto formatName = webkitDrmGetFormatName(description.fourcc); - switch (description.type) { - case RendererBufferDescription::Type::DMABuf: { - auto modifierName = webkitDrmGetModifierName(description.modifier); - if (!modifierName.isNull()) - bufferDescription.append("DMA-BUF: "_s, formatName, " ("_s, modifierName, ")"_s); - else - bufferDescription.append("Unknown"_s); - break; - } - case RendererBufferDescription::Type::SharedMemory: - bufferDescription.append("Shared Memory: "_s, formatName); - break; -#if OS(ANDROID) - case RendererBufferDescription::Type::AHardwareBuffer: - bufferDescription.append("AHardwareBuffer: "_s, formatName); - break; -#endif - } - switch (description.usage) { - case RendererBufferFormat::Usage::Rendering: - bufferDescription.append(" [Rendering]"_s); - break; - case RendererBufferFormat::Usage::Scanout: - bufferDescription.append(" [Scanout]"_s); - break; - case RendererBufferFormat::Usage::Mapping: - bufferDescription.append(" [Mapping]"_s); - break; - } - } else - bufferDescription.append("Unknown"_s); - - return bufferDescription.toString(); -} - #if USE(GBM) static String preferredBufferFormats(WebKitURISchemeRequest* request, JSON::Array& jsonArray) { @@ -352,6 +267,87 @@ static String preferredBufferFormats(WebKitURISchemeRequest* request, JSON::Arra } #endif // USE(GBM) #endif // USE(LIBDRM) + +static bool uiProcessContextIsEGL() +{ +#if PLATFORM(GTK) + return Display::singleton().glDisplayIsSharedWithGtk(); +#else + return true; +#endif +} + +static const char* openGLAPI() +{ + if (epoxy_is_desktop_gl()) + return "OpenGL (libepoxy)"; + return "OpenGL ES 2 (libepoxy)"; +} + +#if PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) +static String dmabufRendererWithSupportedBuffers() +{ + StringBuilder buffers; + buffers.append("DMABuf (Supported buffers: "_s); + +#if PLATFORM(GTK) + auto mode = AcceleratedBackingStore::rendererBufferTransportMode(); +#else + OptionSet mode; + if (wpe_display_get_drm_device(wpe_display_get_primary())) + mode.add(RendererBufferTransportMode::Hardware); + mode.add(RendererBufferTransportMode::SharedMemory); +#endif + + if (mode.contains(RendererBufferTransportMode::Hardware)) + buffers.append("Hardware"_s); + if (mode.contains(RendererBufferTransportMode::SharedMemory)) { + if (mode.contains(RendererBufferTransportMode::Hardware)) + buffers.append(", "_s); + buffers.append("Shared Memory"_s); + } + + buffers.append(')'); + return buffers.toString(); +} + +#if USE(LIBDRM) +static String renderBufferDescription(WebKitURISchemeRequest* request) +{ + StringBuilder bufferDescription; + auto description = webkitWebViewGetRendererBufferDescription(webkit_uri_scheme_request_get_web_view(request)); + if (description.fourcc) { + auto formatName = webkitDrmGetFormatName(description.fourcc); + switch (description.type) { + case RendererBufferDescription::Type::DMABuf: { + auto modifierName = webkitDrmGetModifierName(description.modifier); + if (!modifierName.isNull()) + bufferDescription.append("DMA-BUF: "_s, formatName, " ("_s, modifierName, ")"_s); + else + bufferDescription.append("Unknown"_s); + break; + } + case RendererBufferDescription::Type::SharedMemory: + bufferDescription.append("Shared Memory: "_s, formatName); + break; + } + switch (description.usage) { + case RendererBufferFormat::Usage::Rendering: + bufferDescription.append(" [Rendering]"_s); + break; + case RendererBufferFormat::Usage::Scanout: + bufferDescription.append(" [Scanout]"_s); + break; + case RendererBufferFormat::Usage::Mapping: + bufferDescription.append(" [Mapping]"_s); + break; + } + } else + bufferDescription.append("Unknown"_s); + + return bufferDescription.toString(); +} +#endif // USE(LIBDRM) #endif // PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) static String vblankMonitorType(const DisplayVBlankMonitor& monitor) @@ -382,7 +378,6 @@ static String threadedRenderingInfo(const RenderProcessInfo& info) static String supportedBufferFormats(const RenderProcessInfo& info, JSON::Array& jsonArray) { StringBuilder builder; -#if PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) for (const auto& format : info.supportedBufferFormats) { StringBuilder jsonStringBuilder; auto formatName = webkitDrmGetFormatName(format.fourcc); @@ -397,7 +392,6 @@ static String supportedBufferFormats(const RenderProcessInfo& info, JSON::Array& } jsonArray.pushString(jsonStringBuilder.toString()); } -#endif return builder.toString(); } #endif @@ -732,14 +726,18 @@ void WebKitProtocolHandler::handleGPU(WebKitURISchemeRequest* request, RenderPro if (showBuffersInfo) { #if PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) addTableRow(hardwareAccelerationObject, "Renderer"_s, dmabufRendererWithSupportedBuffers()); +#endif + #if USE(LIBDRM) #if USE(GBM) auto jsonFormats = JSON::Array::create(); auto formatsString = preferredBufferFormats(request, jsonFormats.get()); addTableRow(hardwareAccelerationObject, "Preferred buffer formats"_s, formatsString, WTF::move(jsonFormats)); #endif - addTableRow(hardwareAccelerationObject, "Buffer format"_s, renderBufferDescription(request)); #endif // USE(LIBDRM) + +#if PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) + addTableRow(hardwareAccelerationObject, "Buffer format"_s, renderBufferDescription(request)); #endif // PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM)) } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp index e94ec4aae750773fdb635e2b302735f6821ae3ef..eb8547be6916f5f95dc3be86c35292b4f7d7b0c5 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp @@ -102,6 +102,10 @@ private: page.makeViewBlankIfUnpaintedSinceLastLoadCommit(); webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTF::move(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 e1e5687811e65ce1f4cbeb082febffef479a279e..352135e3c98948921b5b135805ecc86043bb336a 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -426,10 +426,19 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa } } +static int webkitWebContext = 0; + +int webkitWebContextExistingCount() +{ + return webkitWebContext; +} + static void webkitWebContextConstructed(GObject* object) { G_OBJECT_CLASS(webkit_web_context_parent_class)->constructed(object); + ++webkitWebContext; + GUniquePtr bundleFilename(g_build_filename(injectedBundleDirectory(), INJECTED_BUNDLE_FILENAME, nullptr)); WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(object); @@ -485,6 +494,8 @@ static void webkitWebContextConstructed(GObject* object) static void webkitWebContextDispose(GObject* object) { + --webkitWebContext; + WebKitWebContextPrivate* priv = WEBKIT_WEB_CONTEXT(object)->priv; if (!priv->clientsDetached) { priv->clientsDetached = true; @@ -946,6 +957,11 @@ WebKitNetworkSession* webkit_web_context_get_network_session_for_automation(WebK return nullptr; #endif } + +void webkit_web_context_set_network_session_for_automation(WebKitWebContext* context, WebKitNetworkSession* session) +{ + context->priv->automationNetworkSession = session; +} #endif /** * webkit_web_context_set_cache_model: diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in index 15fe3e8e5652147ba54af266eda66b3962c074b9..d463fa78af375badb239c890da50ba1125e19de8 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in @@ -161,6 +161,10 @@ webkit_web_context_set_automation_allowed (WebKitWebContext #if ENABLE(2022_GLIB_API) WEBKIT_API WebKitNetworkSession * webkit_web_context_get_network_session_for_automation(WebKitWebContext *context); + +WEBKIT_API void +webkit_web_context_set_network_session_for_automation(WebKitWebContext *context, + WebKitNetworkSession *session); #endif WEBKIT_API void diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h index c1945fbe717a42afc1f51d64a80c7de3fa9009ba..ab63fe19b00ecbd64c9421e6eecad3e25cbb2361 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h @@ -43,3 +43,4 @@ void webkitWebContextInitializeNotificationPermissions(WebKitWebContext*); #if ENABLE(REMOTE_INSPECTOR) void webkitWebContextWillCloseAutomationSession(WebKitWebContext*); #endif +int webkitWebContextExistingCount(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index 3ed130d4fb0345c7309a240d3a412991e15f9904..10c9c0c89e4a9caf68d8075cde195bbf805e6887 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -40,6 +40,7 @@ #include "WebContextMenuItem.h" #include "WebContextMenuItemData.h" #include "WebFrameProxy.h" +#include "WebPageInspectorController.h" #include "WebKitAuthenticationRequestPrivate.h" #include "WebKitBackForwardListPrivate.h" #include "WebKitContextMenuClient.h" @@ -160,6 +161,7 @@ enum { CLOSE, SCRIPT_DIALOG, + SCRIPT_DIALOG_HANDLED, DECIDE_POLICY, PERMISSION_REQUEST, @@ -546,6 +548,13 @@ GRefPtr WebKitWebViewClient::showOptionMenu(WebKitPopupMenu& p void WebKitWebViewClient::frameDisplayed(WKWPE::View&) { + +#if USE(SKIA) + sk_sp surface(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get())); + if (surface) + getPage(m_webView).inspectorController().didPaint(WTF::move(surface)); +#endif + { SetForScope inFrameDisplayedGuard(m_webView->priv->inFrameDisplayed, true); for (const auto& callback : m_webView->priv->frameDisplayedCallbacks) { @@ -653,7 +662,7 @@ static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision* static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request) { -#if ENABLE(POINTER_LOCK) +#if ENABLE(POINTER_LOCK) && PLATFORM(GTK) if (WEBKIT_IS_POINTER_LOCK_PERMISSION_REQUEST(request)) { webkit_permission_request_allow(request); return TRUE; @@ -1001,6 +1010,10 @@ static void webkitWebViewConstructed(GObject* object) priv->websitePolicies = adoptGRef(webkit_website_policies_new()); Ref configuration = priv->relatedView && priv->relatedView->priv->configurationForNextRelatedView ? priv->relatedView->priv->configurationForNextRelatedView.releaseNonNull() : webkitWebViewCreatePageConfiguration(webView); + + // Playwright: REGRESSION(278896@main): Need to preserve configuration's preferences. + configuration->setPreferences(webkitSettingsGetPreferences(priv->settings.get())); + webkitWebViewCreatePage(webView, WTF::move(configuration)); webkitWebContextWebViewCreated(priv->context.get(), webView); @@ -2114,6 +2127,15 @@ static void webkit_web_view_class_init(WebKitWebViewClass* webViewClass) G_TYPE_BOOLEAN, 1, WEBKIT_TYPE_SCRIPT_DIALOG); + signals[SCRIPT_DIALOG_HANDLED] = g_signal_new( + "script-dialog-handled", + G_TYPE_FROM_CLASS(webViewClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitWebViewClass, script_dialog), + g_signal_accumulator_true_handled, nullptr, + g_cclosure_marshal_generic, + G_TYPE_BOOLEAN, 1); + /** * WebKitWebView::decide-policy: * @web_view: the #WebKitWebView on which the signal is emitted @@ -2948,6 +2970,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const webkit_script_dialog_unref(webView->priv->currentScriptDialog); } +void webkitWebViewHandleJavaScriptDialog(WebKitWebView* webView, bool accept, const String& value) { + auto* dialog = webView->priv->currentScriptDialog; +#if PLATFORM(WPE) + dialog->isUserHandled = false; +#endif + webkit_script_dialog_ref(dialog); + if (!value.isNull()) + webkitWebViewSetCurrentScriptDialogUserInput(webView, value); + if (accept) + webkitWebViewAcceptCurrentScriptDialog(webView); + else + webkitWebViewDismissCurrentScriptDialog(webView); + gboolean returnValue; + g_signal_emit(webView, signals[SCRIPT_DIALOG_HANDLED], 0, dialog, &returnValue); + webkit_script_dialog_unref(dialog); +} + 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 8bff6235bb227ed9e53017f45ce6469dede379fb..34a4c07514c1661ea7e333de5ea674123b809b2f 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h @@ -67,6 +67,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/glib/webkit.h.in b/Source/WebKit/UIProcess/API/glib/webkit.h.in index d48845217e514f1fb9dc84917cd8ba7b26046dee..0402761230371a6f9e9e78caaaf2f207fa3c760c 100644 --- a/Source/WebKit/UIProcess/API/glib/webkit.h.in +++ b/Source/WebKit/UIProcess/API/glib/webkit.h.in @@ -45,6 +45,7 @@ #include <@API_INCLUDE_PREFIX@/WebKitAutomationSession.h> #include <@API_INCLUDE_PREFIX@/WebKitBackForwardList.h> #include <@API_INCLUDE_PREFIX@/WebKitBackForwardListItem.h> +#include <@API_INCLUDE_PREFIX@/WebKitBrowserInspector.h> #if PLATFORM(GTK) #include <@API_INCLUDE_PREFIX@/WebKitClipboardPermissionRequest.h> #include <@API_INCLUDE_PREFIX@/WebKitColorChooserRequest.h> diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp index a33310d9ef8795338756c5d38da9fdc18fd65d6d..363988712345502a202f9feea21f2ca365ed41c0 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp @@ -246,7 +246,7 @@ WebCore::IntPoint PageClientImpl::accessibilityScreenToRootView(const WebCore::I return screenToRootView(point); } -WebCore::IntRect PageClientImpl::rootViewToAccessibilityScreen(const WebCore::IntRect& rect) +WebCore::IntRect PageClientImpl::rootViewToAccessibilityScreen(const WebCore::IntRect& rect) { return rootViewToScreen(rect); } @@ -255,6 +255,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool { if (wasEventHandled || event.type() != WebEventType::KeyDown || !event.nativeEvent()) return; + if (!event.nativeEvent()) + return; // Always consider arrow keys as handled, otherwise the GtkWindow key bindings will move the focus. guint keyval; @@ -345,9 +347,9 @@ void PageClientImpl::selectionDidChange() webkitWebViewSelectionDidChange(WEBKIT_WEB_VIEW(m_viewWidget)); } -RefPtr PageClientImpl::takeViewSnapshot(std::optional&& clipRect) +RefPtr PageClientImpl::takeViewSnapshot(std::optional&& clipRect, bool nominalResolution) { - return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget), WTF::move(clipRect)); + return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget), WTF::move(clipRect), nominalResolution); } void PageClientImpl::didChangeContentSize(const IntSize& size) diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h index 0dae577227eaac423bdc97d9c859fe5afc2d06c1..8edbe1cb3e7d0f818290122861635c063595c632 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h @@ -104,7 +104,7 @@ private: RefPtr createDataListSuggestionsDropdown(WebPageProxy&) override; Ref createValidationBubble(String&& message, const WebCore::ValidationBubble::Settings&) final; void selectionDidChange() override; - RefPtr takeViewSnapshot(std::optional&&) override; + RefPtr takeViewSnapshot(std::optional&&, bool nominalResolution = false) override; #if ENABLE(DRAG_SUPPORT) void startDrag(WebCore::SelectionData&&, OptionSet, RefPtr&& dragImage, WebCore::IntPoint&& dragImageHotspot) override; void didPerformDragControllerAction() override; diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..1d6c987019e69d2e1ab97266d01180542534f4b0 --- /dev/null +++ b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(__WEBKIT2_H_INSIDE__) && !defined(BUILDING_WEBKIT) +#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); + WebKitWebView *(* quit_application) (WebKitBrowserInspector *browser_inspector); + + 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 (const char* defaultProxyURI, + const char* const* ignoreHosts); + +WEBKIT_API void +webkit_browser_inspector_initialize_web_socket (unsigned port, + const char* defaultProxyURI, + const char* const* ignoreHosts); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in b/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in index 496079da90993ac37689b060b69ecd4a67c2b6a8..af30181ca922f16c0f6e245c70e5ce7d8999341f 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in +++ b/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in @@ -23,7 +23,7 @@ #define WebKitPointerLockPermissionRequest_h #include -#include +#include <@API_INCLUDE_PREFIX@/WebKitDefines.h> G_BEGIN_DECLS diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp index d5bb72f0ffbf99eddebc9819cb3f24fdaffdf468..d248c201e0ee9db63a117b8cde34661595a594fa 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -2879,6 +2879,11 @@ void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase) #endif } +WebKit::AcceleratedBackingStore* webkitWebViewBaseGetAcceleratedBackingStore(WebKitWebViewBase* webkitWebViewBase) +{ + return webkitWebViewBase->priv->acceleratedBackingStore.get(); +} + void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext) { ASSERT(webkitWebViewBase->priv->acceleratedBackingStore); @@ -2935,12 +2940,12 @@ void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase) webkitWebViewBase->priv->acceleratedBackingStore->update({ }); } -RefPtr webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase* webkitWebViewBase, std::optional&& clipRect) +RefPtr webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase* webkitWebViewBase, std::optional&& clipRect, bool nominalResolution) { WebPageProxy* page = webkitWebViewBase->priv->pageProxy.get(); IntSize size = clipRect ? clipRect->size() : page->viewSize(); - float deviceScale = page->deviceScaleFactor(); + float deviceScale = nominalResolution ? 1 : page->deviceScaleFactor(); size.scale(deviceScale); #if !USE(GTK4) diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h index d84099f5109a4a0a8a0b51d4f46ce059460b8280..48d56239c4595053696a63fa48c69db0706ca19a 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h @@ -27,6 +27,7 @@ #pragma once +#include "AcceleratedBackingStore.h" #include "APIPageConfiguration.h" #include "GRefPtrGtk.h" #include "GUniquePtrGtk.h" @@ -105,7 +106,7 @@ void webkitWebViewBaseStartDrag(WebKitWebViewBase*, WebCore::SelectionData&&, Op void webkitWebViewBaseDidPerformDragControllerAction(WebKitWebViewBase*); #endif -RefPtr webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase*, std::optional&&); +RefPtr webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase*, std::optional&&, bool nominalResolution); void webkitWebViewBaseSetEnableBackForwardNavigationGesture(WebKitWebViewBase*, bool enabled); WebKit::ViewGestureController* webkitWebViewBaseViewGestureController(WebKitWebViewBase*); @@ -147,3 +148,5 @@ void webkitWebViewBaseSetPlugID(WebKitWebViewBase*, const String&); WebKit::RendererBufferDescription webkitWebViewBaseGetRendererBufferDescription(WebKitWebViewBase*); void webkitWebViewBaseSetCursor(WebKitWebViewBase*, const WebCore::Cursor&); + +WebKit::AcceleratedBackingStore* webkitWebViewBaseGetAcceleratedBackingStore(WebKitWebViewBase*); diff --git a/Source/WebKit/UIProcess/API/wpe/APIViewClient.h b/Source/WebKit/UIProcess/API/wpe/APIViewClient.h index 9091ae5198e765c2cfe0584d121afe4f88df3c0e..b0efedec419673ef2bfd0fd79406774e24aa98e9 100644 --- a/Source/WebKit/UIProcess/API/wpe/APIViewClient.h +++ b/Source/WebKit/UIProcess/API/wpe/APIViewClient.h @@ -26,6 +26,9 @@ #pragma once #include "UserMessage.h" +#if USE(SKIA) +#include +#endif #include #include @@ -50,6 +53,11 @@ public: virtual bool isGLibBasedAPI() { return false; } virtual void frameDisplayed(WKWPE::View&) { } +// Playwright begin +#if USE(SKIA) + virtual sk_sp takeViewScreenshot() { return nullptr; } +#endif +// Playwright end virtual void willStartLoad(WKWPE::View&) { } virtual void didChangePageID(WKWPE::View&) { } virtual void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler&& completionHandler) { completionHandler(WebKit::UserMessage()); } diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp index 44bec4dfe534281e791339bc6eebc3795d65b2c9..4d7cd002b8420382e3628886a7fc4c6229db2702 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp @@ -36,9 +36,12 @@ #include "WPEWebViewLegacy.h" #include "WPEWebViewPlatform.h" #include "WebColorPicker.h" +#include "WebColorPickerWPE.h" +#include "WebDateTimePickerWPE.h" #include "WebContextMenuProxy.h" #include "WebContextMenuProxyWPE.h" #include "WebDataListSuggestionsDropdown.h" +#include "WebDataListSuggestionsDropdownWPE.h" #include "WebDateTimePicker.h" #include "WebKitPopupMenu.h" #include @@ -62,6 +65,12 @@ #include #endif +#if USE(SKIA) +#include +#include +#include +#endif + namespace WebKit { WTF_MAKE_TZONE_ALLOCATED_IMPL(PageClientImpl); @@ -230,7 +239,7 @@ WebCore::IntPoint PageClientImpl::accessibilityScreenToRootView(const WebCore::I WebCore::IntRect PageClientImpl::rootViewToAccessibilityScreen(const WebCore::IntRect& rect) { - return rootViewToScreen(rect); + return rootViewToScreen(rect); } void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool) @@ -318,14 +327,14 @@ Ref PageClientImpl::createContextMenuProxy(WebPageProxy& pa } #endif -RefPtr PageClientImpl::createColorPicker(WebPageProxy&, const WebCore::Color& intialColor, const WebCore::IntRect&, ColorControlSupportsAlpha supportsAlpha, Vector&&, std::optional) +RefPtr PageClientImpl::createColorPicker(WebPageProxy& page, const WebCore::Color& intialColor, const WebCore::IntRect& rect, ColorControlSupportsAlpha supportsAlpha, Vector&&, std::optional frameID) { - return nullptr; + return WebColorPickerWPE::create(page, intialColor, rect, frameID); } -RefPtr PageClientImpl::createDataListSuggestionsDropdown(WebPageProxy&) +RefPtr PageClientImpl::createDataListSuggestionsDropdown(WebKit::WebPageProxy& page) { - return nullptr; + return WebDataListSuggestionsDropdownWPE::create(page); } RefPtr PageClientImpl::createDateTimePicker(WebPageProxy& page) @@ -585,11 +594,11 @@ void PageClientImpl::callAfterNextPresentationUpdate(CompletionHandler&& m_view.callAfterNextPresentationUpdate(WTF::move(callback)); } -RefPtr PageClientImpl::takeViewSnapshot(std::optional&& clipRect) +RefPtr PageClientImpl::takeViewSnapshot(std::optional&& clipRect, bool nominalResolution) { #if ENABLE(WPE_PLATFORM) if (m_view.wpeView()) { - auto snapshot = static_cast(m_view).takeViewSnapshot(WTF::move(clipRect)); + auto snapshot = static_cast(m_view).takeViewSnapshot(WTF::move(clipRect), nominalResolution); // FIXME Forward the Expected in https://webkit.org/b/300271 if (snapshot) return WTF::move(snapshot.value()); @@ -600,4 +609,11 @@ RefPtr PageClientImpl::takeViewSnapshot(std::optional PageClientImpl::createDateTimePicker(WebPageProxy& page) +{ + return WebDateTimePickerWPE::create(page); +} +#endif + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h index a1f18769eb2398cb467067f7f2d6ad864d1ed0ee..842bc438edd93ad09ddc1012898856e4ac686f00 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h @@ -193,7 +193,11 @@ private: WebKitWebResourceLoadManager* webResourceLoadManager() override; - RefPtr takeViewSnapshot(std::optional&&) override; + RefPtr takeViewSnapshot(std::optional&&, bool nominalResolution) override; + +#if ENABLE(DATE_AND_TIME_INPUT_TYPES) + RefPtr createDateTimePicker(WebPageProxy&) override; +#endif WKWPE::View& m_view; DefaultUndoController m_undoController; diff --git a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp index 32b91bcbf205dfbd36c9275a6167877cf561a172..ce45bcc6e7fdd92efa31d974a8230253fbf3294e 100644 --- a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.cpp @@ -645,9 +645,9 @@ void ViewPlatform::callAfterNextPresentationUpdate(CompletionHandler&& c } } -Expected, String> ViewPlatform::takeViewSnapshot(std::optional&& clipRect) +Expected, String> ViewPlatform::takeViewSnapshot(std::optional&& clipRect, bool nominalResolution) { - return m_backingStore->takeSnapshot(WTF::move(clipRect)); + return m_backingStore->takeSnapshot(WTF::move(clipRect), nominalResolution); } } // namespace WKWPE diff --git a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.h b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.h index c3ca21d8e499d08a4e5ebf4a32290114abfae4ee..1de5446d0763256ac826a5e71e51e6d2838172f8 100644 --- a/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.h +++ b/Source/WebKit/UIProcess/API/wpe/WPEWebViewPlatform.h @@ -63,7 +63,7 @@ public: static WebKit::WebPageProxy* platformWebPageProxyForGamepadInput(); #endif - Expected, String> takeViewSnapshot(std::optional&&); + Expected, String> takeViewSnapshot(std::optional&&, bool nominalResolution); void updateAcceleratedSurface(uint64_t); WebKit::RendererBufferDescription renderBufferDescription() const; diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..22baa003f1220a87d5c1012cd485a6fee1570b22 --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(__WEBKIT_H_INSIDE__) && !defined(BUILDING_WEBKIT) +#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); + WebKitWebView *(* quit_application) (WebKitBrowserInspector *browser_inspector); + + 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 (const char* defaultProxyURI, + const char* const* ignoreHosts); + +WEBKIT_API void +webkit_browser_inspector_initialize_web_socket (unsigned port, + const char* defaultProxyURI, + const char* const* ignoreHosts); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp index 96170b6fd5f7dfc9ae97019f1dae74ee686f3a89..731d1aa724878543872a604c55da6b0affca45b6 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp @@ -56,6 +56,7 @@ struct _WebKitWebViewBackend { struct wpe_view_backend* backend; GDestroyNotify notifyCallback; gpointer notifyCallbackData; + take_screenshot_callback screenshotCallback; int referenceCount { 1 }; }; @@ -118,6 +119,19 @@ struct wpe_view_backend* webkit_web_view_backend_get_wpe_backend(WebKitWebViewBa return viewBackend->backend; } +void webkit_web_view_backend_set_screenshot_callback(WebKitWebViewBackend *view_backend, take_screenshot_callback callback) +{ + view_backend->screenshotCallback = callback; +} + +PlatformImage webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend* view_backend) +{ + if (!view_backend->screenshotCallback) + return nullptr; + + return view_backend->screenshotCallback(view_backend->notifyCallbackData); +} + namespace WTF { WTF_DEFINE_GREF_TRAITS(WebKitWebViewBackend, webkitWebViewBackendRef, webkitWebViewBackendUnref) } diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h index 16dcc1f69c38cd8ad630bc49d6d69feaa3aa811e..98677028c19c12c3b6d513bb5e45375a1528fe8a 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h @@ -28,6 +28,11 @@ #include #include +#if defined(USE_SKIA) && USE_SKIA +#include +using PlatformImage = SkImage*; +#endif + G_BEGIN_DECLS #define WEBKIT_TYPE_WEB_VIEW_BACKEND (webkit_web_view_backend_get_type()) @@ -44,6 +49,12 @@ webkit_web_view_backend_new (struct wpe_view_backend *backend, WEBKIT_API struct wpe_view_backend * webkit_web_view_backend_get_wpe_backend (WebKitWebViewBackend *view_backend); +typedef PlatformImage (*take_screenshot_callback)(gpointer user_data); + +WEBKIT_API void +webkit_web_view_backend_set_screenshot_callback (WebKitWebViewBackend *view_backend, + take_screenshot_callback callback); + G_END_DECLS #endif /* WebKitWebViewBackend_h */ diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h index 21131a4d26ba115f3249b227d3e1dabd42398c80..7b1a6e98f3c1fb5ef5d54f416c49ba3e6188dcf4 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h @@ -32,3 +32,5 @@ WTF_DECLARE_GREF_TRAITS(WebKitWebViewBackend) void webkitWebViewBackendUnref(WebKitWebViewBackend*); #endif // USE(LIBWPE) + +PlatformImage webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend*); diff --git a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h index c38751ae3064aa6a42a3ed8fdb902f70473a8e08..f6bf1a674402bc08f69bccc97058954981ad4ebc 100644 --- a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h +++ b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h @@ -318,6 +318,8 @@ public: void didDestroyFrame(WebCore::FrameIdentifier); + static std::optional platformGetBase64EncodedPNGData(const ViewSnapshot&); + RefPtr webPageProxyForHandle(const String&); String effectiveHandleForWebFrameProxy(const WebFrameProxy&); String handleForWebFrameID(std::optional); @@ -385,7 +387,6 @@ private: // Get base64-encoded PNG data from a bitmap. static std::optional platformGetBase64EncodedPNGData(WebCore::ShareableBitmap::Handle&&); - static std::optional platformGetBase64EncodedPNGData(const ViewSnapshot&); // Save base64-encoded file contents to a local file path and return the path. // This reuses the basename of the remote file path so that the filename exposed to DOM API remains the same. diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp index d2e4f4cf05d2c7ce330319b4116c816c237df2dd..04e2e8d6125daf90a8c0c7aaa69e626f95b044d9 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp @@ -176,7 +176,11 @@ void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& lau launchOptions.processCmdPrefix = String::fromUTF8(processCmdPrefix); #endif // ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE)) +/* playwright revert 50f8fee */ +#if 0 populateOverrideLanguagesLaunchOptions(launchOptions); +#endif +/* end playwright revert 50f8fee */ platformGetLaunchOptions(launchOptions); } diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h index 0241fd8531d53a1f773e7c4a2c871e1903816eba..f199f4096d254ce0242c569db600554efac8c226 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h @@ -296,13 +296,16 @@ protected: InitializationActivityAndGrant initializationActivityAndGrant(); + /* playwright revert 50f8fee - make protected to allow use from WebProcessProxy */ + Vector platformOverrideLanguages() const; + /* end playwright revert 50f8fee */ + private: virtual void connectionWillOpen(IPC::Connection&); virtual void processWillShutDown(IPC::Connection&) = 0; void outgoingMessageQueueIsGrowingLarge(); void populateOverrideLanguagesLaunchOptions(ProcessLauncher::LaunchOptions&) const; - Vector platformOverrideLanguages() const; void platformStartConnectionTerminationWatchdog(); // Connection::Client diff --git a/Source/WebKit/UIProcess/BackingStore.h b/Source/WebKit/UIProcess/BackingStore.h index 15f1d5ff3973e173c1a3ee3eeb3bdf5e1ec4cd87..6516a47bc4aa788b1b1c09d21254ea9482190f6c 100644 --- a/Source/WebKit/UIProcess/BackingStore.h +++ b/Source/WebKit/UIProcess/BackingStore.h @@ -67,6 +67,11 @@ public: float deviceScaleFactor() const { return m_deviceScaleFactor; } void paint(PlatformPaintContextPtr, const WebCore::IntRect&); +#if PLATFORM(GTK) + RefPtr surface() const { return m_surface; } +#elif USE(SKIA) + sk_sp surface() const { return m_surface; } +#endif void incorporateUpdate(UpdateInfo&&); private: diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfb57a48ce387b79613b757e2eb4de2c378aac30 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BrowserInspectorPipe.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include "InspectorPlaywrightAgentClient.h" +#include "RemoteInspectorPipe.h" +#include "WebKit2Initialize.h" +#include + +namespace WebKit { + +void initializeBrowserInspectorPipe(std::unique_ptr client) +{ + // Initialize main loop before creating inspecor agent and pipe queues. + WebKit::InitializeWebKit2(); + + class BrowserInspectorPipe { + public: + BrowserInspectorPipe(std::unique_ptr client) + : m_playwrightAgent(std::move(client)) + , m_remoteInspectorPipe(m_playwrightAgent) + { + } + + InspectorPlaywrightAgent m_playwrightAgent; + 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 0000000000000000000000000000000000000000..cd66887de171cda7d15a8e4dc6dbff63665dc619 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +namespace WebKit { + +class InspectorPlaywrightAgentClient; + +void initializeBrowserInspectorPipe(std::unique_ptr client); + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h index 45abb108899e19cfe0cecd6716083afbff03d73c..11ced1bb2d03c949cb31435eeeee2a196928a2de 100644 --- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h +++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/NavigationSOAuthorizationSession.h @@ -31,6 +31,7 @@ #include "WebViewDidMoveToWindowObserver.h" #include #include +#include namespace WebKit { diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h index 89d125f7742f81ead8c50f218ecb1771b8000636..baa6cf58ad502c6c033ee6293a6cc8d4ce608e7b 100644 --- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h @@ -25,6 +25,7 @@ #if HAVE(APP_SSO) +#import "SOAuthorizationSession.h" #import namespace WebKit { diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h index 1c037ebba6c9cf3713e0936d4f2327d0d46a626e..e0f463694dea3aae9d8d01376ac62e75e9b0e826 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h @@ -105,6 +105,7 @@ private: void runJavaScriptAlert(WebPageProxy&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function&& completionHandler) final; void runJavaScriptConfirm(WebPageProxy&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function&& completionHandler) final; void runJavaScriptPrompt(WebPageProxy&, const WTF::String&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, 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, std::optional&&, CompletionHandler&&) final; void decidePolicyForGeolocationPermissionRequest(WebPageProxy&, WebFrameProxy&, const FrameInfoData&, Function&) final; @@ -233,6 +234,7 @@ private: bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1; + bool webViewHandleJavaScriptDialogValue : 1; bool webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler : 1; bool webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler : 1; bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm index c660d8204b89997bb25637ed24198acf5028e280..6d7c9102b1bc57fd179ba742cf703b1bf3eaf5af 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm @@ -136,6 +136,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.webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:forQuirkDomains:completionHandler:)]; m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; @@ -502,6 +503,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy& page, const WTF::St }).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.get().get() handleJavaScriptDialog:accept value:value.createNSString().get()]; +} + void UIDelegate::UIClient::requestStorageAccessConfirm(WebPageProxy& webPageProxy, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, std::optional&& organizationStorageAccessPromptQuirk, CompletionHandler&& completionHandler) { RefPtr uiDelegate = m_uiDelegate.get(); diff --git a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm index 177ac869fe4128bb459d2577d90f6b208e8395a2..e6ade97d800a2119d4abd9e241186915c432fd9c 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm @@ -45,7 +45,9 @@ #import "NativeWebKeyboardEvent.h" #import "NativeWebMouseEvent.h" #import "NavigationState.h" +#import "NetworkProcessMessages.h" #import "PageClient.h" +#import "PasteboardTypes.h" #import "PlatformXRSystem.h" #import "PlaybackSessionManagerProxy.h" #import "RemoteLayerTreeCommitBundle.h" @@ -446,11 +448,85 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() void WebPageProxy::startDrag(const DragItem& dragItem, ShareableBitmap::Handle&& dragImageHandle, const std::optional& nodeID, const std::optional& frameID) { + if (m_interceptDrags) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName: m_overrideDragPasteboardName.createNSString().get()]; + + m_dragSelectionData = String([pasteboard name]); + if (auto replyID = grantAccessToCurrentPasteboardData(String([pasteboard name]), [] () { })) + protect(websiteDataStore().networkProcess())->connection().waitForAsyncReplyAndDispatchImmediately(*replyID, 100_ms); + m_dragSourceOperationMask = WebCore::anyDragOperation(); + + if (auto& info = dragItem.promisedAttachmentInfo) { + auto attachment = attachmentForIdentifier(info.attachmentIdentifier); + if (!attachment) { + dragCancelled(); + return; + } + if (!attachment->utiType().createNSString().get().length) { + dragCancelled(); + return; + } + + for (size_t index = 0; index < info.additionalTypesAndData.size(); ++index) { + auto nsData = info.additionalTypesAndData[index].second->createNSData(); + [pasteboard setData:nsData.get() forType:info.additionalTypesAndData[index].first.createNSString().get()]; + } + } else { + [pasteboard setString:@"" forType:PasteboardTypes::WebDummyPboardType]; + } + didStartDrag(); + return; + } + if (RefPtr pageClient = this->pageClient()) pageClient->startDrag(dragItem, WTF::move(dragImageHandle), nodeID, frameID); } -#endif +void WebPageProxy::releaseInspectorDragPasteboard() { + if (!!m_dragSelectionData) + m_dragSelectionData = std::nullopt; + if (!m_overrideDragPasteboardName.isEmpty()) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; + [pasteboard releaseGlobally]; + m_overrideDragPasteboardName = ""_s; + } +} + + +void WebPageProxy::setInterceptDrags(bool shouldIntercept) { + m_interceptDrags = shouldIntercept; + if (m_interceptDrags) { + if (m_overrideDragPasteboardName.isEmpty()) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; + m_overrideDragPasteboardName = String([pasteboard name]); + } + legacyMainFrameProcess().send(Messages::WebPage::SetDragPasteboardName(m_overrideDragPasteboardName), webPageIDInMainFrameProcess()); + } else { + legacyMainFrameProcess().send(Messages::WebPage::SetDragPasteboardName(""_s), webPageIDInMainFrameProcess()); + } +} + +// FIXME: Move these functions to WebPageProxyIOS.mm. +#if PLATFORM(IOS_FAMILY) + +void WebPageProxy::setPromisedDataForImage(const String&, const SharedMemory::Handle&, const String&, const String&, const String&, const String&, const String&, const SharedMemory::Handle&, const String&) +{ + notImplemented(); +} + +void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect) +{ + if (m_currentDragCaretRect == dragCaretRect) + return; + + auto previousRect = m_currentDragCaretRect; + m_currentDragCaretRect = dragCaretRect; + pageClient()->didChangeDragCaretRect(previousRect, dragCaretRect); +} + +#endif // PLATFORM(IOS_FAMILY) + +#endif // ENABLE(DRAG_SUPPORT) #if ENABLE(ATTACHMENT_ELEMENT) diff --git a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm index 4b43164f215ca8e72a68252f36862e25b2742ea8..0804791f8ef0174b905cb18851962f04b43151e4 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm @@ -451,7 +451,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END auto screenProperties = WebCore::collectScreenProperties(); parameters.screenProperties = WTF::move(screenProperties); #if PLATFORM(MAC) - parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); + parameters.useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); #endif #if PLATFORM(VISION) @@ -864,8 +864,8 @@ void WebProcessPool::registerNotificationObservers() }]; m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { - auto scrollbarStyle = [NSScroller preferredScrollerStyle]; - sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(scrollbarStyle)); + bool useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); + sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(useOverlayScrollbars)); }]; m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSAppSingleton() queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp index be40fa0e3e3e8698c29f70a2b8dac324225aba97..4e6cc206ed0a25914d8df604f61746562fd9c976 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp @@ -33,6 +33,7 @@ #include "LayerTreeContext.h" #include "MessageSenderInlines.h" #include "UpdateInfo.h" +#include "WebPageInspectorController.h" #include "WebPageProxy.h" #include "WebPreferences.h" #include "WebProcessPool.h" @@ -40,6 +41,15 @@ #include #include #include +#include + +#if PLATFORM(GTK) +#include "WebKitWebViewBasePrivate.h" +#include +#include +#include +#include +#endif #if USE(GLIB_EVENT_LOOP) #include @@ -175,6 +185,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange(CompletionH sendWithAsyncReply(Messages::DrawingArea::SetDeviceScaleFactor(page()->deviceScaleFactor()), WTF::move(completionHandler)); } +void DrawingAreaProxyCoordinatedGraphics::waitForSizeUpdate(Function&& callback) +{ + m_callbacks.append(WTF::move(callback)); +} + void DrawingAreaProxyCoordinatedGraphics::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable) { #if !PLATFORM(WPE) && !PLATFORM(GTK) @@ -234,6 +249,54 @@ void DrawingAreaProxyCoordinatedGraphics::updateAcceleratedCompositingMode(uint6 updateAcceleratedCompositingMode(layerTreeContext); } +#if PLATFORM(GTK) +void DrawingAreaProxyCoordinatedGraphics::captureFrame() +{ + RefPtr surface; + if (isInAcceleratedCompositingMode()) { + AcceleratedBackingStore* backingStore = webkitWebViewBaseGetAcceleratedBackingStore(WEBKIT_WEB_VIEW_BASE(protect(page())->viewWidget())); + if (!backingStore) + return; + + surface = backingStore->surface(); + } + + if (!surface) + return; + + if (cairo_surface_get_type(surface.get()) != CAIRO_SURFACE_TYPE_IMAGE) + return; + + // The original surface is upside down, so we flip it to match orientation in other accelerated backing stores. + auto flippedSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, cairo_image_surface_get_width(surface.get()), cairo_image_surface_get_height(surface.get()))); + { + RefPtr cr = adoptRef(cairo_create(flippedSurface.get())); + cairo_matrix_t transform; + cairo_matrix_init(&transform, 1, 0, 0, -1, 0, cairo_image_surface_get_height(surface.get())); + cairo_transform(cr.get(), &transform); + cairo_set_source_surface(cr.get(), surface.get(), 0, 0); + cairo_paint(cr.get()); + } + cairo_surface_flush(flippedSurface.get()); + + unsigned char* data = cairo_image_surface_get_data(flippedSurface.get()); + int width = cairo_image_surface_get_width(flippedSurface.get()); + int height = cairo_image_surface_get_height(flippedSurface.get()); + int stride = cairo_image_surface_get_stride(flippedSurface.get()); + + SkImageInfo info = SkImageInfo::Make( + width, height, + kBGRA_8888_SkColorType, // matches CAIRO_FORMAT_ARGB32 on LE + kPremul_SkAlphaType + ); + sk_sp skImage = SkImages::RasterFromData(info, SkData::MakeWithCopy(data, height * stride), stride); + if (!skImage) + return; + + protect(page())->inspectorController().didPaint(WTF::move(skImage)); +} +#endif // PLATFORM(GTK) + bool DrawingAreaProxyCoordinatedGraphics::alwaysUseCompositing() const { if (!page()) @@ -301,6 +364,12 @@ void DrawingAreaProxyCoordinatedGraphics::didUpdateGeometry() // we need to resend the new size here. if (m_lastSentSize != size()) sendUpdateGeometry(); + else { + Vector> callbacks; + callbacks.swap(m_callbacks); + for (auto& cb : callbacks) + cb(*this); + } } #if !PLATFORM(WPE) && !PLATFORM(GTK) diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h index 99a1c243ee534edf127f6f932e4d05cb65676528..d880229ef91bfd33e37b5065976fbe3c7f6dc443 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h @@ -29,6 +29,7 @@ #include "DrawingAreaProxy.h" #include "LayerTreeContext.h" +#include #include #include #include @@ -60,6 +61,10 @@ public: bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); } const LayerTreeContext& layerTreeContext() const LIFETIME_BOUND { return m_layerTreeContext; } + void waitForSizeUpdate(Function&&); +#if !PLATFORM(WPE) + void captureFrame(); +#endif void dispatchAfterEnsuringDrawing(CompletionHandler&&); @@ -131,6 +136,7 @@ private: // The last size we sent to the web process. WebCore::IntSize m_lastSentSize; + Vector> m_callbacks; #if !PLATFORM(WPE) && !PLATFORM(GTK) bool m_isBackingStoreDiscardable { true }; diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp index 6537111d8f973509b072b3ec0da911d9c1d24f1d..206023b88f3bb0f7b14bcc7600679bce11a9053a 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp @@ -41,8 +41,10 @@ #include #include #include +#include #include #include +#include #if PLATFORM(MAC) #include @@ -66,7 +68,10 @@ DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebsiteDataStor #if HAVE(MODERN_DOWNLOADPROGRESS) , m_assertion(ProcessAssertion::create(getCurrentProcessID(), "WebKit DownloadProxy DecideDestination"_s, ProcessAssertionType::FinishTaskInterruptable)) #endif + , m_uuid(createVersion4UUIDString()) { + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadCreated(m_uuid, m_request, m_frameInfo->frameInfoData(), originatingPage, this); } DownloadProxy::~DownloadProxy() @@ -86,12 +91,15 @@ void DownloadProxy::cancel(CompletionHandler&& completionHandl { m_downloadIsCancelled = true; if (m_dataStore) { - protect(protect(m_dataStore)->networkProcess())->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTF::move(completionHandler)] (std::span resumeData) mutable { + auto* instrumentation = m_dataStore->downloadInstrumentation(); + protect(protect(m_dataStore)->networkProcess())->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTF::move(completionHandler), instrumentation] (std::span resumeData) mutable { RefPtr protectedThis = weakThis.get(); if (!protectedThis) return completionHandler(nullptr); protectedThis->m_legacyResumeData = createData(resumeData); completionHandler(protectedThis->m_legacyResumeData.get()); + if (instrumentation) + instrumentation->downloadFinished(protectedThis->m_uuid, "canceled"_s); if (RefPtr downloadProxyMap = protectedThis->m_downloadProxyMap.get()) downloadProxyMap->downloadFinished(*protectedThis); }); @@ -182,6 +190,35 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour else suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType()); + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFilenameSuggested(m_uuid, suggestedFilename); + + if (m_dataStore->allowDownloadForAutomation()) { + SandboxExtension::Handle sandboxExtensionHandle; + String destination; + if (*m_dataStore->allowDownloadForAutomation()) { + auto downloadPath = m_dataStore->downloadPathForAutomation(); + FileSystem::makeAllDirectories(downloadPath); + destination = FileSystem::pathByAppendingComponent(downloadPath, m_uuid); + if (auto handle = SandboxExtension::createHandle(destination, SandboxExtension::Type::ReadWrite)) + sandboxExtensionHandle = WTF::move(*handle); + } + m_client->decidePlaceholderPolicy(*this, [completionHandler = WTF::move(completionHandler), destination = WTF::move(destination), sandboxExtensionHandle = WTF::move(sandboxExtensionHandle)] (WebKit::UseDownloadPlaceholder usePlaceholder, const URL& url) mutable { + SandboxExtension::Handle placeHolderSandboxExtensionHandle; + Vector bookmarkData; + Vector activityTokenData; +#if HAVE(MODERN_DOWNLOADPROGRESS) + bookmarkData = bookmarkDataForURL(url); + activityTokenData = activityAccessToken(); +#else + if (auto handle = SandboxExtension::createHandle(url.fileSystemPath(), SandboxExtension::Type::ReadWrite)) + placeHolderSandboxExtensionHandle = WTF::move(*handle); +#endif + completionHandler(destination, WTF::move(sandboxExtensionHandle), AllowOverwrite::Yes, WebKit::UseDownloadPlaceholder::No, url, WTF::move(placeHolderSandboxExtensionHandle), bookmarkData.span(), activityTokenData.span()); + }); + return; + } + protect(client())->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTF::move(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable { SandboxExtension::Handle sandboxExtensionHandle; if (!destination.isNull()) { @@ -246,6 +283,8 @@ void DownloadProxy::didFinish() protect(client())->didFinish(*this); if (m_downloadIsCancelled) return; + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFinished(m_uuid, String()); // This can cause the DownloadProxy object to be deleted. if (RefPtr downloadProxyMap = m_downloadProxyMap.get()) @@ -260,6 +299,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span m_legacyResumeData = createData(resumeData); protect(client())->didFail(*this, error, m_legacyResumeData.get()); + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFinished(m_uuid, error.localizedDescription()); // This can cause the DownloadProxy object to be deleted. if (RefPtr downloadProxyMap = m_downloadProxyMap.get()) diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h index be567b89bb406f0ee0df005c83b186cb956025ae..16342e90dcbf94325b8fac5f4c877c5fd372f673 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h @@ -168,6 +168,7 @@ private: #if HAVE(MODERN_DOWNLOADPROGRESS) RefPtr m_assertion; #endif + String m_uuid; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.h b/Source/WebKit/UIProcess/DrawingAreaProxy.h index 546c51f13212c98bf9a26bf1ee804c74d75f241e..e681ec646dd033ade64bae6eabdc472e9e0b8c6a 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.h +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h @@ -96,6 +96,7 @@ public: const WebCore::IntSize& size() const LIFETIME_BOUND { return m_size; } bool setSize(const WebCore::IntSize&, const WebCore::IntSize& scrollOffset = { }); + void waitForSizeUpdate(Function&&); virtual void minimumSizeForAutoLayoutDidChange() { } virtual void sizeToContentAutoSizeMaximumSizeDidChange() { } diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a89043bb0b8f6a22ee9af2b271de34989e6a5c1 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorScreencastAgent.h" + +#include "PageClient.h" +#include "WebPageInspectorController.h" +#include "WebPageProxy.h" +#include "WebsiteDataStore.h" +#include +#include +#include +#include +#include +#include +#include + +#if USE(SKIA) +#include "DrawingAreaProxyCoordinatedGraphics.h" +#include "DrawingAreaProxy.h" +#include +#include +#include +#include +#include +#include +#include +#endif + +#if PLATFORM(MAC) +#include +#endif + +#if PLATFORM(WIN) +#include "DrawingAreaProxyWC.h" +#endif + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace WebKit { + +const int kMaxFramesInFlight = 1; + +using namespace Inspector; + +WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorScreencastAgent); + +InspectorScreencastAgent::InspectorScreencastAgent(BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page) + : InspectorAgentBase("Screencast"_s) + , m_frontendDispatcher(makeUnique(frontendRouter)) + , m_backendDispatcher(ScreencastBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +InspectorScreencastAgent::~InspectorScreencastAgent() +{ +} + +void InspectorScreencastAgent::didCreateFrontendAndBackend() +{ +} + +void InspectorScreencastAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ +} + +#if USE(SKIA) +void InspectorScreencastAgent::didPaint(sk_sp&& surface) +{ + if (!m_screencast) + return; + + if (m_screencastFramesInFlight > kMaxFramesInFlight) + return; + + MonotonicTime timestamp = MonotonicTime::now(); + sk_sp image(surface); + + // Get actual image size (in device pixels). + WebCore::IntSize displaySize(image->width(), image->height()); + WebCore::IntSize drawingAreaSize = m_page.drawingArea()->size(); + drawingAreaSize.scale(m_page.deviceScaleFactor()); + if (drawingAreaSize != displaySize) + return; + + { + SkPixmap pixmap; + if (!image->peekPixels(&pixmap)) { + fprintf(stderr, "Failed to peek pixels from SkImage to compute hash\n"); + return; + } + // Do not send the same frame over and over. + size_t len = pixmap.computeByteSize(); + auto cryptoDigest = PAL::Crypto::CryptoDigest::create(PAL::Crypto::CryptoDigest::Algorithm::SHA_1); + cryptoDigest->addBytes(std::span(reinterpret_cast(pixmap.addr()), len)); + auto digest = cryptoDigest->computeHash(); + if (m_lastFrameDigest == digest) + return; + m_lastFrameDigest = digest; + } + + // Scale image to fit width / height + double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height()); + if (scale < 1) { + SkBitmap dstBitmap; + dstBitmap.allocPixels(SkImageInfo::MakeN32Premul(displaySize.width() * scale, displaySize.height() * scale)); + SkCanvas canvas(dstBitmap); + canvas.scale(scale, scale); + canvas.drawImage(image, 0, 0); + image = dstBitmap.asImage(); + } + + SkPixmap pixmap; + if (!image->peekPixels(&pixmap)) { + fprintf(stderr, "Failed to peek pixels from SkImage for JPEG encoding\n"); + return; + } + + SkJpegEncoder::Options options; + options.fQuality = 90; + SkDynamicMemoryWStream stream; + if (!SkJpegEncoder::Encode(&stream, pixmap, options)) { + fprintf(stderr, "Failed to encode image to JPEG\n"); + return; + } + sk_sp jpegData = stream.detachAsData(); + String result = base64EncodeToString(std::span(reinterpret_cast(jpegData->data()), jpegData->size())); + ++m_screencastFramesInFlight; + m_frontendDispatcher->screencastFrame(result, timestamp.secondsSinceEpoch().value(), displaySize.width(), displaySize.height()); +} +#endif + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::startScreencast(int width, int height, int toolbarHeight, int quality) +{ + if (m_screencast) + return makeUnexpected("Already screencasting"_s); + + m_screencast = true; + m_screencastWidth = width; + m_screencastHeight = height; + m_screencastQuality = quality; + m_screencastToolbarHeight = toolbarHeight; + ++m_screencastGeneration; + kickFramesStarted(); + return m_screencastGeneration; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::screencastFrameAck(int generation) +{ + if (!m_screencast) + return makeUnexpected("Not screencasting"_s); + + if (m_screencastGeneration != generation) + return { }; + + --m_screencastFramesInFlight; + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::stopScreencast() +{ + if (!m_screencast) + return makeUnexpected("Not screencasting"_s); + + m_screencast = false; + m_framesAreGoing = false; + m_screencastFramesInFlight = 0; + m_lastFrameDigest.clear(); + return { }; +} + +void InspectorScreencastAgent::kickFramesStarted() +{ + if (!m_framesAreGoing) { + m_framesAreGoing = true; +#if !PLATFORM(WPE) + scheduleFrameEncoding(); +#endif + } + m_page.updateRenderingWithForcedRepaint([] { }); +} + +#if !PLATFORM(WPE) +void InspectorScreencastAgent::scheduleFrameEncoding() +{ + if (!m_screencast) + return; + + const int fps = 25; + RunLoop::mainSingleton().dispatchAfter(Seconds(1.0 / fps), [agent = WeakPtr { this }]() mutable { + if (!agent) + return; + if (!agent->m_page.hasPageClient()) + return; + + agent->encodeFrame(); + agent->scheduleFrameEncoding(); + }); +} +#endif + +#if PLATFORM(MAC) +void InspectorScreencastAgent::encodeFrame() +{ + if (!m_screencast) + return; + + RetainPtr imageRef = m_page.pageClient()->takeSnapshotForAutomation(); + if (m_screencast && m_screencastFramesInFlight <= kMaxFramesInFlight) { + MonotonicTime timestamp = MonotonicTime::now(); + CGImage* imagePtr = imageRef.get(); + WebCore::IntSize imageSize(CGImageGetWidth(imagePtr), CGImageGetHeight(imagePtr)); + WebCore::IntSize displaySize = imageSize; + displaySize.contract(0, m_screencastToolbarHeight); + double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height()); + RetainPtr transformedImageRef; + if (scale < 1 || m_screencastToolbarHeight) { + WebCore::IntSize screencastSize = displaySize; + WebCore::IntSize scaledImageSize = imageSize; + if (scale < 1) { + screencastSize.scale(scale); + scaledImageSize.scale(scale); + } + auto colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); + auto context = adoptCF(CGBitmapContextCreate(nullptr, screencastSize.width(), screencastSize.height(), 8, 4 * screencastSize.width(), colorSpace.get(), (CGBitmapInfo)kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + CGContextDrawImage(context.get(), CGRectMake(0, 0, scaledImageSize.width(), scaledImageSize.height()), imagePtr); + transformedImageRef = adoptCF(CGBitmapContextCreateImage(context.get())); + imagePtr = transformedImageRef.get(); + } + auto data = WebCore::encodeData(imagePtr, "image/jpeg"_s, m_screencastQuality * 0.1); + + // Do not send the same frame over and over. + auto cryptoDigest = PAL::Crypto::CryptoDigest::create(PAL::Crypto::CryptoDigest::Algorithm::SHA_1); + cryptoDigest->addBytes(std::span(data.mutableSpan().data(), data.size())); + auto digest = cryptoDigest->computeHash(); + if (m_lastFrameDigest != digest) { + String base64Data = base64EncodeToString(data); + ++m_screencastFramesInFlight; + m_frontendDispatcher->screencastFrame(base64Data, timestamp.secondsSinceEpoch().value(), displaySize.width(), displaySize.height()); + m_lastFrameDigest = digest; + } + } +} +#endif + +#if PLATFORM(GTK) +void InspectorScreencastAgent::encodeFrame() +{ + if (!m_screencast) + return; + + if (auto* drawingArea = m_page.drawingArea()) + static_cast(drawingArea)->captureFrame(); +} +#endif + +#if PLATFORM(WIN) +void InspectorScreencastAgent::encodeFrame() +{ + if (!m_screencast) + return; + + if (auto* drawingArea = m_page.drawingArea()) + static_cast(drawingArea)->captureFrame(); +} +#endif + +} // namespace WebKit + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..afadd2371dffab9d4b92e4245f5622828c8fded1 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +#if USE(SKIA) +#include +#endif + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +class ScreencastFrontendDispatcher; +} + +namespace WebKit { +class InspectorScreencastAgent; +} + +namespace WTF { +template struct IsDeprecatedWeakRefSmartPointerException; +template<> struct IsDeprecatedWeakRefSmartPointerException : std::true_type { }; +} + +namespace WebKit { + +class WebPageProxy; + +class InspectorScreencastAgent : public Inspector::InspectorAgentBase, public Inspector::ScreencastBackendDispatcherHandler, public CanMakeWeakPtr { + WTF_MAKE_NONCOPYABLE(InspectorScreencastAgent); + WTF_MAKE_TZONE_ALLOCATED(InspectorScreencastAgent); +public: + InspectorScreencastAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorScreencastAgent() override; + + void didCreateFrontendAndBackend() override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + +#if USE(SKIA) + void didPaint(sk_sp&& surface); +#endif + + Inspector::Protocol::ErrorStringOr startScreencast(int width, int height, int toolbarHeight, int quality) override; + Inspector::Protocol::ErrorStringOr screencastFrameAck(int generation) override; + Inspector::Protocol::ErrorStringOr stopScreencast() override; + +private: +#if !PLATFORM(WPE) + void scheduleFrameEncoding(); + void encodeFrame(); +#endif + + void kickFramesStarted(); + + std::unique_ptr m_frontendDispatcher; + Ref m_backendDispatcher; + WebPageProxy& m_page; + Vector m_lastFrameDigest; + bool m_screencast = false; + bool m_framesAreGoing = false; + double m_screencastWidth = 0; + double m_screencastHeight = 0; + int m_screencastQuality = 0; + int m_screencastToolbarHeight = 0; + int m_screencastGeneration = 0; + int m_screencastFramesInFlight = 0; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp index 66e1ddd0ad468d7e9d262442ad0efdbcf7989ea1..28c0a0f7b7edaaf7f30c677594365a436344512d 100644 --- a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp +++ b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.cpp @@ -59,6 +59,11 @@ std::unique_ptr PageInspectorTargetProxy::create(Provi return target; } +std::unique_ptr PageInspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId) +{ + return PageInspectorTargetProxy::create(provisionalPage, targetId, Inspector::InspectorTargetType::Page); +} + PageInspectorTargetProxy::PageInspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) : InspectorTargetProxy(targetId, type) , m_page(page) @@ -109,6 +114,31 @@ void PageInspectorTargetProxy::didCommitProvisionalTarget() m_provisionalPage = nullptr; } +void PageInspectorTargetProxy::willResume() +{ + if (m_page->hasRunningProcess()) + m_page->legacyMainFrameProcess().send(Messages::WebPage::ResumeInspectorIfPausedInNewWindow(), m_page->webPageIDInMainFrameProcess()); +} + +void PageInspectorTargetProxy::activate(String& error) +{ + if (type() != Inspector::InspectorTargetType::Page) + return InspectorTarget::activate(error); + + platformActivate(error); +} + +void PageInspectorTargetProxy::close(String& error, bool runBeforeUnload) +{ + if (type() != Inspector::InspectorTargetType::Page) + return InspectorTarget::close(error, runBeforeUnload); + + if (runBeforeUnload) + m_page->tryClose(); + else + m_page->closePage(); +} + bool PageInspectorTargetProxy::isProvisional() const { return !!m_provisionalPage; diff --git a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h index 88fe6b2104c5e26cee4a975a552e8a2c78f44129..96631d61f1a043d09769098849c4d91ad2cf6b21 100644 --- a/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h +++ b/Source/WebKit/UIProcess/Inspector/PageInspectorTargetProxy.h @@ -44,6 +44,7 @@ class PageInspectorTargetProxy final : public InspectorTargetProxy { public: static std::unique_ptr create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); + static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId); PageInspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); void didCommitProvisionalTarget() override; @@ -52,8 +53,13 @@ public: void connect(Inspector::FrontendChannel::ConnectionType) override; void disconnect() override; void sendMessageToTargetBackend(const String&) override; + void activate(String& error) override; + void close(String& error, bool runBeforeUnload) override; private: + void willResume() override; + void platformActivate(String& error) const; + WeakRef m_page; WeakPtr m_provisionalPage; }; diff --git a/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp b/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp index 232b5dc1c574e4d4231307fee144aff59b519758..651fc7fe63d80cf093192e4eec1576c7621201e1 100644 --- a/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp +++ b/Source/WebKit/UIProcess/Inspector/WasmDebuggerDebuggable.cpp @@ -28,6 +28,7 @@ #if ENABLE(WEBASSEMBLY_DEBUGGER) && ENABLE(REMOTE_INSPECTOR) +#include "WebPageProxy.h" #include "WebProcessProxy.h" #include "WebProcessProxyMessages.h" #include diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp index 13da6142d0889583d399b4ee9ead9a6850b700b2..626f87341d5eb3d7192d4c80621e84bf9181940f 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp @@ -26,19 +26,27 @@ #include "config.h" #include "WebPageInspectorController.h" +#include "APINavigation.h" +#include "APIPageConfiguration.h" #include "APIUIClient.h" #include "FrameInspectorTarget.h" #include "FrameInspectorTargetProxy.h" #include "InspectorBrowserAgent.h" +#include "InspectorDialogAgent.h" +#include "InspectorScreencastAgent.h" #include "PageInspectorTarget.h" #include "PageInspectorTargetProxy.h" #include "ProvisionalFrameProxy.h" #include "ProvisionalPageProxy.h" #include "WebFrameProxy.h" #include "WebPageInspectorAgentBase.h" +#include "WebPageInspectorEmulationAgent.h" +#include "WebPageInspectorInputAgent.h" #include "WebPageProxy.h" #include "WebProcessProxy.h" #include "WebsiteDataStore.h" +#include +#include #include #include #include @@ -69,6 +77,17 @@ static String getTargetID(const ProvisionalFrameProxy& provisionalFrame) WTF_MAKE_TZONE_ALLOCATED_IMPL(WebPageInspectorController); +WebPageInspectorControllerObserver* WebPageInspectorController::s_observer = nullptr; + +void WebPageInspectorController::setObserver(WebPageInspectorControllerObserver* observer) +{ + s_observer = observer; +} + +WebPageInspectorControllerObserver* WebPageInspectorController::observer() { + return s_observer; +} + WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPage) : m_frontendRouter(FrontendRouter::create()) , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) @@ -82,16 +101,92 @@ WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPa WebPageInspectorController::~WebPageInspectorController() = default; void WebPageInspectorController::init() +{ + auto targetAgent = makeUniqueRef(m_frontendRouter.get(), m_backendDispatcher.get()); + m_targetAgent = targetAgent.ptr(); + m_agents.append(WTF::move(targetAgent)); + auto emulationAgent = makeUniqueRef(m_backendDispatcher.get(), m_inspectedPage); + m_emulationAgent = emulationAgent.ptr(); + m_agents.append(WTF::move(emulationAgent)); + auto inputAgent = makeUniqueRef(m_backendDispatcher.get(), m_inspectedPage); + m_inputAgent = inputAgent.ptr(); + m_agents.append(WTF::move(inputAgent)); + m_agents.append(makeUniqueRef(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage)); + auto screencastAgent = makeUniqueRef(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage); + m_screecastAgent = screencastAgent.ptr(); + m_agents.append(WTF::move(screencastAgent)); + if (s_observer) + s_observer->didCreateInspectorController(m_inspectedPage); +} + +void WebPageInspectorController::didInitializeWebPage() { String pageTargetId = PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + // 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; addTarget(PageInspectorTargetProxy::create(protect(m_inspectedPage), pageTargetId, Inspector::InspectorTargetType::Page)); + if (m_inspectedPage->mainFrame()) + didCreateFrame(*m_inspectedPage->mainFrame()); } void WebPageInspectorController::pageClosed() { + String pageTargetId = PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + removeTarget(pageTargetId); + + disconnectAllFrontends(); m_agents.discardValues(); + + if (s_observer) + s_observer->willDestroyInspectorController(m_inspectedPage); +} + +bool WebPageInspectorController::pageCrashed(ProcessTerminationReason reason) +{ + if (reason != ProcessTerminationReason::Crash) + return false; + String targetId = PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + auto it = m_targets.find(targetId); + if (it == m_targets.end()) + return false; + m_targetAgent->targetCrashed(*it->value); + m_targets.remove(it); + + return m_targetAgent->isConnected(); +} + +void WebPageInspectorController::willCreateNewPage(const WebCore::WindowFeatures& features, const URL& url) +{ + if (s_observer) + s_observer->willCreateNewPage(m_inspectedPage, features, url); +} + +void WebPageInspectorController::didShowPage() +{ + if (m_frontendRouter->hasFrontends()) + m_emulationAgent->didShowPage(); +} + +void WebPageInspectorController::didProcessAllPendingKeyboardEvents() +{ + if (m_frontendRouter->hasFrontends()) + m_inputAgent->didProcessAllPendingKeyboardEvents(); +} + +void WebPageInspectorController::didProcessAllPendingMouseEvents() +{ + if (m_frontendRouter->hasFrontends()) + m_inputAgent->didProcessAllPendingMouseEvents(); +} + +void WebPageInspectorController::didProcessAllPendingWheelEvents() +{ + if (m_frontendRouter->hasFrontends()) + m_inputAgent->didProcessAllPendingWheelEvents(); } bool WebPageInspectorController::hasLocalFrontend() const @@ -105,6 +200,14 @@ void WebPageInspectorController::connectFrontend(Inspector::FrontendChannel& fro bool connectingFirstFrontend = !m_frontendRouter->hasFrontends(); + // HACK: forcefully disconnect remote connections to show local inspector starting with initial + // agents' state. + if (frontendChannel.connectionType() == Inspector::FrontendChannel::ConnectionType::Local && + !connectingFirstFrontend && !m_frontendRouter->hasLocalFrontend()) { + disconnectAllFrontends(); + connectingFirstFrontend = true; + } + m_frontendRouter->connectFrontend(frontendChannel); if (connectingFirstFrontend) @@ -124,8 +227,10 @@ void WebPageInspectorController::disconnectFrontend(FrontendChannel& frontendCha m_frontendRouter->disconnectFrontend(frontendChannel); bool disconnectingLastFrontend = !m_frontendRouter->hasFrontends(); - if (disconnectingLastFrontend) + if (disconnectingLastFrontend) { m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed); + m_pendingNavigations.clear(); + } Ref inspectedPage = m_inspectedPage.get(); inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); @@ -149,6 +254,8 @@ void WebPageInspectorController::disconnectAllFrontends() // Disconnect any remaining remote frontends. m_frontendRouter->disconnectAllFrontends(); + m_pendingNavigations.clear(); + Ref inspectedPage = m_inspectedPage.get(); inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); @@ -177,6 +284,66 @@ void WebPageInspectorController::setIndicating(bool indicating) } #endif +#if USE(SKIA) +void WebPageInspectorController::didPaint(sk_sp&& surface) +{ + if (!m_frontendRouter->hasFrontends()) + return; + + m_screecastAgent->didPaint(WTF::move(surface)); +} +#endif + + +void WebPageInspectorController::navigate(WebCore::ResourceRequest&& request, WebFrameProxy* frame, NavigationHandler&& completionHandler) +{ + auto navigation = m_inspectedPage->loadRequestForInspector(WTF::move(request), frame); + if (!navigation) { + completionHandler("Failed to navigate"_s, { }); + return; + } + + m_pendingNavigations.set(navigation->navigationID(), WTF::move(completionHandler)); +} + +void WebPageInspectorController::didReceivePolicyDecision(WebCore::PolicyAction action, std::optional navigationID) +{ + if (!m_frontendRouter->hasFrontends()) + return; + + if (!navigationID) + return; + + auto completionHandler = m_pendingNavigations.take(*navigationID); + if (!completionHandler) + return; + + if (action == WebCore::PolicyAction::Ignore) + completionHandler("Navigation cancelled"_s, { }); + else + completionHandler(String(), *navigationID); +} + +void WebPageInspectorController::didDestroyNavigation(WebCore::NavigationIdentifier navigationID) +{ + if (!m_frontendRouter->hasFrontends()) + return; + + auto completionHandler = m_pendingNavigations.take(navigationID); + if (!completionHandler) + return; + + // Inspector initiated navigation is destroyed before policy check only when it + // becomes a fragment navigation (which always reuses current navigation). + completionHandler(String(), { }); +} + +void WebPageInspectorController::didFailProvisionalLoadForFrame(WebCore::NavigationIdentifier navigationID, const WebCore::ResourceError& error) +{ + if (s_observer) + s_observer->didFailProvisionalLoad(m_inspectedPage, navigationID, error.localizedDescription()); +} + void WebPageInspectorController::sendMessageToInspectorFrontend(const String& targetId, const String& message) { if (!m_targets.contains(targetId)) { @@ -191,6 +358,52 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta protect(m_targetAgent)->sendMessageFromTargetToFrontend(targetId, message); } +void WebPageInspectorController::setPauseOnStart(bool shouldPause) +{ + ASSERT(m_frontendRouter->hasFrontends()); + m_targetAgent->setPauseOnStart(shouldPause); +} + +bool WebPageInspectorController::shouldPauseLoadRequest() const +{ + if (!m_frontendRouter->hasFrontends()) + return false; + + if (!m_inspectedPage->isPageOpenedByDOMShowingInitialEmptyDocument()) + return false; + + auto* target = m_targets.get(PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); + // The method is expeted to be called only when the WebPage has already been + // initilized, so the target must exist. + ASSERT(target); + return target->isPaused(); +} + +bool WebPageInspectorController::shouldPauseInInspectorWhenShown() const +{ + if (!m_frontendRouter->hasFrontends()) + return false; + + // Only pause if the page was opened by window.open() or new tab navigation. + // We cannot use isPageOpenedByDOMShowingInitialEmptyDocument() here because + // this method maybe called from WebPageProxy::initializeWebPage and setOpenedByDOM + // is called after the page is initialized. + if (!m_inspectedPage->configuration().windowFeatures()) + return false; + + // The method is called from WebPageProxy::initializePage and the + // target is not created yet (it is created after the new page is + // initialized and attached to the process). + return m_targetAgent->shouldPauseOnStart(); +} + +void WebPageInspectorController::setContinueLoadingCallback(WTF::Function&& callback) +{ + auto* target = m_targets.get(PageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); + ASSERT(target); + target->setResumeCallback(WTF::move(callback)); +} + bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const { if (!m_frontendRouter->hasFrontends()) @@ -210,7 +423,7 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage, WebCore::FrameIdentifier mainFrameID, WebProcessProxy& mainFrameProcess) { - addTarget(PageInspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page)); + addTarget(PageInspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage))); if (shouldManageFrameTargets()) { constexpr bool isProvisional = true; diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h index f670f9007a9386bf9933e59c32463f697dbb6597..17fa5c0f2860c9423de3e167616d46fa5d857125 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h @@ -28,9 +28,11 @@ #include "InspectorTargetProxy.h" #include "ProvisionalPageProxy.h" #include "UIProcess/WebFrameProxy.h" +#include "ProcessTerminationReason.h" #include #include #include +#include #include #include #include @@ -38,11 +40,29 @@ #include #include #include +#include + +#if USE(SKIA) +#include +#include +#endif namespace Inspector { class BackendDispatcher; class FrontendChannel; class FrontendRouter; +class InspectorTarget; +} + +namespace WebCore { +class ResourceError; +class ResourceRequest; +enum class PolicyAction : uint8_t; +struct WindowFeatures; +} + +namespace PAL { +class SessionID; } namespace WebKit { @@ -51,6 +71,22 @@ class InspectorBrowserAgent; class ProvisionalPageProxy; struct WebPageAgentContext; +class InspectorScreencastAgent; +class WebFrameProxy; +class WebPageInspectorEmulationAgent; +class WebPageInspectorInputAgent; + +class WebPageInspectorControllerObserver { +public: + virtual void didCreateInspectorController(WebPageProxy&) = 0; + virtual void willDestroyInspectorController(WebPageProxy&) = 0; + virtual void didFailProvisionalLoad(WebPageProxy&, WebCore::NavigationIdentifier, const String& error) = 0; + virtual void willCreateNewPage(WebPageProxy&, const WebCore::WindowFeatures&, const URL&) = 0; + +protected: + virtual ~WebPageInspectorControllerObserver() = default; +}; + class WebPageInspectorController { WTF_MAKE_TZONE_ALLOCATED(WebPageInspectorController); WTF_MAKE_NONCOPYABLE(WebPageInspectorController); @@ -59,7 +95,21 @@ public: ~WebPageInspectorController(); void init(); + void didInitializeWebPage(); + + static void setObserver(WebPageInspectorControllerObserver*); + static WebPageInspectorControllerObserver* observer(); + void pageClosed(); + bool pageCrashed(ProcessTerminationReason); + + void willCreateNewPage(const WebCore::WindowFeatures&, const URL&); + + void didShowPage(); + + void didProcessAllPendingKeyboardEvents(); + void didProcessAllPendingMouseEvents(); + void didProcessAllPendingWheelEvents(); bool hasLocalFrontend() const; @@ -72,9 +122,25 @@ public: #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); #endif +#if USE(SKIA) + void didPaint(sk_sp&&); +#endif + using NavigationHandler = Function)>; + void navigate(WebCore::ResourceRequest&&, WebFrameProxy*, NavigationHandler&&); + void didReceivePolicyDecision(WebCore::PolicyAction action, std::optional navigationID); + + void didDestroyNavigation(WebCore::NavigationIdentifier navigationID); + + void didFailProvisionalLoadForFrame(WebCore::NavigationIdentifier navigationID, const WebCore::ResourceError& error); void sendMessageToInspectorFrontend(const String& targetId, const String& message); + void setPauseOnStart(bool); + + bool shouldPauseLoadRequest() const; + bool shouldPauseInInspectorWhenShown() const; + void setContinueLoadingCallback(WTF::Function&&); + bool shouldPauseLoading(const ProvisionalPageProxy&) const; void setContinueLoadingCallback(const ProvisionalPageProxy&, WTF::Function&&); @@ -111,9 +177,16 @@ private: CheckedPtr m_targetAgent; HashMap> m_targets; + WebPageInspectorEmulationAgent* m_emulationAgent { nullptr }; + WebPageInspectorInputAgent* m_inputAgent { nullptr }; + InspectorScreencastAgent* m_screecastAgent { nullptr }; + CheckedPtr m_enabledBrowserAgent; bool m_didCreateLazyAgents { false }; + UncheckedKeyHashMap m_pendingNavigations; + + static WebPageInspectorControllerObserver* s_observer; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53bf0625a4e6af2f4387b9a516604d5e6219cfef --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorDialogAgent.h" + +#include "APINavigation.h" +#include "APIUIClient.h" +#include "WebPageProxy.h" +#include + + +namespace WebKit { + +using namespace Inspector; + +WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorDialogAgent); + +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() +{ + disable(); +} + +void InspectorDialogAgent::didCreateFrontendAndBackend() +{ +} + +void InspectorDialogAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ +} + +Inspector::Protocol::ErrorStringOr InspectorDialogAgent::enable() +{ + if (m_page.inspectorDialogAgent()) + return makeUnexpected("Dialog domain is already enabled."_s); + + m_page.setInspectorDialogAgent(this); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorDialogAgent::disable() +{ + if (m_page.inspectorDialogAgent() != this) + return { }; + + m_page.setInspectorDialogAgent(nullptr); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorDialogAgent::handleJavaScriptDialog(bool accept, const String& value) +{ + m_page.uiClient().handleJavaScriptDialog(m_page, accept, value); + return { }; +} + +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 0000000000000000000000000000000000000000..26775d9cfe30d220b14c1b2355a9baf9e6eca815 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#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_TZONE_ALLOCATED(InspectorDialogAgent); +public: + InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorDialogAgent() override; + + void didCreateFrontendAndBackend() override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + Inspector::Protocol::ErrorStringOr enable() override; + Inspector::Protocol::ErrorStringOr disable() override; + Inspector::Protocol::ErrorStringOr handleJavaScriptDialog(bool accept, const String& promptText) override; + + void javascriptDialogOpening(const String& type, const String& message, const String& defaultValue = String()); + +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/InspectorPlaywrightAgent.cpp b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..635da5eda9d9bbe21c5fa35936656b02c4b3ab46 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp @@ -0,0 +1,1033 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorPlaywrightAgent.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "APIGeolocationProvider.h" +#include "APIHTTPCookieStore.h" +#include "APIPageConfiguration.h" +#include "FrameInfoData.h" +#include "InspectorPlaywrightAgentClient.h" +#include "InspectorTargetProxy.h" +#include "NetworkProcessMessages.h" +#include "NetworkProcessProxy.h" +#include "PageClient.h" +#include "PageInspectorTarget.h" +#include "PlaywrightFullScreenManagerProxyClient.h" +#include "SandboxExtension.h" +#include "StorageNamespaceIdentifier.h" +#include "WebAutomationSession.h" +#include "WebGeolocationManagerProxy.h" +#include "WebGeolocationPosition.h" +#include "WebFrameProxy.h" +#include "WebInspectorUtilities.h" +#include "WebPageGroup.h" +#include "WebPageInspectorController.h" +#include "WebPageMessages.h" +#include "WebPageProxy.h" +#include "WebPreferences.h" +#include "WebProcessPool.h" +#include "WebProcessProxy.h" +#include "WebsiteDataRecord.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Inspector; + +namespace WebKit { + +class InspectorPlaywrightAgent::PageProxyChannel : public FrontendChannel { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(InspectorPlaywrightAgent); +public: + PageProxyChannel(FrontendChannel& frontendChannel, String browserContextID, String pageProxyID, WebPageProxy& page) + : m_browserContextID(browserContextID) + , m_pageProxyID(pageProxyID) + , m_frontendChannel(frontendChannel) + , m_page(page) + { + } + + ~PageProxyChannel() override = default; + + void dispatchMessageFromFrontend(const String& message) + { + m_page.inspectorController().dispatchMessageFromFrontend(message); + } + + WebPageProxy& page() { return m_page; } + + void disconnect() + { + m_page.inspectorController().disconnectFrontend(*this); + } + +private: + ConnectionType connectionType() const override { return m_frontendChannel.connectionType(); } + void sendMessageToFrontend(const String& message) override + { + m_frontendChannel.sendMessageToFrontend(addTabIdToMessage(message)); + } + + String addTabIdToMessage(const String& message) { + RefPtr parsedMessage = JSON::Value::parseJSON(message); + if (!parsedMessage) + return message; + + RefPtr messageObject = parsedMessage->asObject(); + if (!messageObject) + return message; + + messageObject->setString("browserContextId"_s, m_browserContextID); + messageObject->setString("pageProxyId"_s, m_pageProxyID); + return messageObject->toJSONString(); + } + + String m_browserContextID; + String m_pageProxyID; + FrontendChannel& m_frontendChannel; + WebPageProxy& m_page; +}; + +class OverridenGeolocationProvider final : public API::GeolocationProvider, public CanMakeWeakPtr { + WTF_MAKE_NONCOPYABLE(OverridenGeolocationProvider); +public: + OverridenGeolocationProvider() + : m_position(WebGeolocationPosition::create(WebCore::GeolocationPositionData())) + { + } + + void setPosition(const Ref& position) { + m_position = position; + } + +private: + void startUpdating(WebGeolocationManagerProxy& proxy) override + { + proxy.providerDidChangePosition(&m_position.get()); + } + + void stopUpdating(WebGeolocationManagerProxy&) override + { + } + + void setEnableHighAccuracy(WebGeolocationManagerProxy&, bool enabled) override + { + } + + Ref m_position; +}; + +namespace { + +void setGeolocationProvider(BrowserContext* browserContext) { + auto provider = makeUnique(); + browserContext->geolocationProvider = *provider; + auto* geoManager = browserContext->processPool->supplement(); + geoManager->setProvider(WTF::move(provider)); +} + +String toBrowserContextIDProtocolString(const PAL::SessionID& sessionID) +{ + StringBuilder builder; + builder.append(hex(sessionID.toUInt64(), 16)); + return builder.toString(); +} + +String toPageProxyIDProtocolString(const WebPageProxy& page) +{ + return makeString(page.identifier().toUInt64()); +} + + +static Ref> getEnabledWindowFeatures(const WebCore::WindowFeatures& features) { + auto result = JSON::ArrayOf::create(); + if (features.x) + result->addItem(makeString("left="_s, String::number(*features.x))); + if (features.y) + result->addItem(makeString("top="_s, String::number(*features.y))); + if (features.width) + result->addItem(makeString("width="_s, String::number(*features.width))); + if (features.height) + result->addItem(makeString("height="_s, String::number(*features.height))); + if (features.menuBarVisible) + result->addItem("menubar"_s); + if (features.toolBarVisible) + result->addItem("toolbar"_s); + if (features.statusBarVisible) + result->addItem("status"_s); + if (features.locationBarVisible) + result->addItem("location"_s); + if (features.scrollbarsVisible) + result->addItem("scrollbars"_s); + if (features.resizable) + result->addItem("resizable"_s); + if (features.fullscreen) + result->addItem("fullscreen"_s); + if (features.dialog) + result->addItem("dialog"_s); + if (features.noopener) + result->addItem("noopener"_s); + if (features.noreferrer) + result->addItem("noreferrer"_s); + for (const auto& additionalFeature : features.additionalFeatures) + result->addItem(additionalFeature); + return result; +} + +Inspector::Protocol::Playwright::CookieSameSitePolicy cookieSameSitePolicy(WebCore::Cookie::SameSitePolicy policy) +{ + switch (policy) { + case WebCore::Cookie::SameSitePolicy::None: + return Inspector::Protocol::Playwright::CookieSameSitePolicy::None; + case WebCore::Cookie::SameSitePolicy::Lax: + return Inspector::Protocol::Playwright::CookieSameSitePolicy::Lax; + case WebCore::Cookie::SameSitePolicy::Strict: + return Inspector::Protocol::Playwright::CookieSameSitePolicy::Strict; + } + ASSERT_NOT_REACHED(); + return Inspector::Protocol::Playwright::CookieSameSitePolicy::None; +} + +Ref buildObjectForCookie(const WebCore::Cookie& cookie) +{ + return Inspector::Protocol::Playwright::Cookie::create() + .setName(cookie.name) + .setValue(cookie.value) + .setDomain(cookie.domain) + .setPath(cookie.path) + .setExpires(cookie.expires.value_or(-1)) + .setHttpOnly(cookie.httpOnly) + .setSecure(cookie.secure) + .setSession(cookie.session) + .setSameSite(cookieSameSitePolicy(cookie.sameSite)) + .release(); +} + +void adjustInspectedPagePreferences(WebPreferences& preferences, std::optional enableStoragePartitioning) +{ + // Set this to true as otherwise updating any preferences will override its + // value in the Web Process to false (and InspectorController sets it locally + // to true when frontend is connected). + preferences.setDeveloperExtrasEnabled(true); + + // Navigation to cached pages doesn't fire some of the events (e.g. execution context created) + // that inspector depends on. So we disable the cache when front-end connects. + preferences.setUsesBackForwardCache(false); + + // Enable popup debugging. + // TODO: allow to set preferences over the inspector protocol or find a better place for this. + preferences.setJavaScriptCanOpenWindowsAutomatically(true); + + // Enable media stream. + if (!preferences.mediaDevicesEnabled()) { + preferences.setMediaDevicesEnabled(true); + preferences.setPeerConnectionEnabled(true); + } + + if (!enableStoragePartitioning || !*enableStoragePartitioning) { + // Disable local storage partitioning. See https://github.com/microsoft/playwright/issues/32230 + preferences.setStorageBlockingPolicy(static_cast(WebCore::StorageBlockingPolicy::AllowAll)); + } +} + +} // namespace + +BrowserContext::BrowserContext() = default; + +BrowserContext::~BrowserContext() = default; + +class InspectorPlaywrightAgent::BrowserContextDeletion { + WTF_MAKE_NONCOPYABLE(BrowserContextDeletion); + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(InspectorPlaywrightAgent::BrowserContextDeletion); +public: + BrowserContextDeletion(std::unique_ptr&& context, size_t numberOfPages, Ref&& callback) + : m_browserContext(WTF::move(context)) + , m_numberOfPages(numberOfPages) + , m_callback(WTF::move(callback)) { } + + void didDestroyPage(const WebPageProxy& page) + { + ASSERT(m_browserContext->dataStore->sessionID() == page.sessionID()); + // Check if new pages have been created during the context destruction and + // close all of them if necessary. + if (m_numberOfPages == 1) { + auto pages = m_browserContext->pages; + size_t numberOfPages = pages.size(); + if (numberOfPages > 1) { + m_numberOfPages = numberOfPages; + for (auto* existingPage : pages) { + if (existingPage != &page) + existingPage->closePage(); + } + } + } + --m_numberOfPages; + if (m_numberOfPages) + return; + m_callback->sendSuccess(); + } + + bool isFinished() const { return !m_numberOfPages; } + + BrowserContext* context() const { return m_browserContext.get(); } + +private: + std::unique_ptr m_browserContext; + size_t m_numberOfPages; + Ref m_callback; +}; + + +InspectorPlaywrightAgent::InspectorPlaywrightAgent(std::unique_ptr client) + : m_frontendChannel(nullptr) + , m_frontendRouter(FrontendRouter::create()) + , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) + , m_client(std::move(client)) + , m_frontendDispatcher(makeUnique(m_frontendRouter)) + , m_playwrightDispatcher(PlaywrightBackendDispatcher::create(m_backendDispatcher.get(), this)) +{ +} + +InspectorPlaywrightAgent::~InspectorPlaywrightAgent() +{ + if (m_frontendChannel) + disconnectFrontend(); +} + +void InspectorPlaywrightAgent::connectFrontend(FrontendChannel& frontendChannel) +{ + ASSERT(!m_frontendChannel); + m_frontendChannel = &frontendChannel; + WebPageInspectorController::setObserver(this); + + m_frontendRouter->connectFrontend(frontendChannel); +} + +void InspectorPlaywrightAgent::disconnectFrontend() +{ + if (!m_frontendChannel) + return; + + disable(); + + m_frontendRouter->disconnectFrontend(*m_frontendChannel); + ASSERT(!m_frontendRouter->hasFrontends()); + + WebPageInspectorController::setObserver(nullptr); + m_frontendChannel = nullptr; + + closeImpl([](String error){}); +} + +void InspectorPlaywrightAgent::dispatchMessageFromFrontend(const String& message) +{ + m_backendDispatcher->dispatch(message, [&](const RefPtr& messageObject) { + RefPtr idValue; + if (!messageObject->getValue("id"_s, idValue)) + return BackendDispatcher::InterceptionResult::Continue; + RefPtr pageProxyIDValue; + if (!messageObject->getValue("pageProxyId"_s, pageProxyIDValue)) + return BackendDispatcher::InterceptionResult::Continue; + + String pageProxyID; + if (!pageProxyIDValue->asString(pageProxyID)) { + m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidRequest, "The type of 'pageProxyId' must be string"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::InterceptionResult::Intercepted; + } + + if (auto pageProxyChannel = m_pageProxyChannels.get(pageProxyID)) { + pageProxyChannel->dispatchMessageFromFrontend(message); + return BackendDispatcher::InterceptionResult::Intercepted; + } + + std::optional requestId = idValue->asInteger(); + if (!requestId) { + m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidRequest, "The type of 'id' must be number"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::InterceptionResult::Intercepted; + } + + m_backendDispatcher->reportProtocolError(*requestId, BackendDispatcher::InvalidParams, "Cannot find page proxy with provided 'pageProxyId'"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::InterceptionResult::Intercepted; + }); +} + +void InspectorPlaywrightAgent::didCreateInspectorController(WebPageProxy& page) +{ + if (!m_isEnabled) + return; + + if (isInspectorProcessPool(page.legacyMainFrameProcess().processPool())) + return; + + ASSERT(m_frontendChannel); + + String browserContextID = toBrowserContextIDProtocolString(page.sessionID()); + String pageProxyID = toPageProxyIDProtocolString(page); + auto* opener = page.configuration().openerPageForInspector(); + String openerId; + if (opener) + openerId = toPageProxyIDProtocolString(*opener); + + BrowserContext* browserContext = getExistingBrowserContext(browserContextID); + browserContext->pages.add(&page); + m_frontendDispatcher->pageProxyCreated(browserContextID, pageProxyID, openerId); + + // Auto-connect to all new pages. + auto pageProxyChannel = makeUnique(*m_frontendChannel, browserContextID, pageProxyID, page); + adjustInspectedPagePreferences(page.preferences(), browserContext->enableStoragePartitioning); + page.inspectorController().connectFrontend(*pageProxyChannel); + // Always pause new targets if controlled remotely. + page.inspectorController().setPauseOnStart(true); + m_pageProxyChannels.set(pageProxyID, WTF::move(pageProxyChannel)); + page.setFullScreenManagerClientOverride(makeUnique(page)); +} + +void InspectorPlaywrightAgent::willDestroyInspectorController(WebPageProxy& page) +{ + if (!m_isEnabled) + return; + + if (isInspectorProcessPool(page.legacyMainFrameProcess().processPool())) + return; + + String browserContextID = toBrowserContextIDProtocolString(page.sessionID()); + BrowserContext* browserContext = getExistingBrowserContext(browserContextID); + browserContext->pages.remove(&page); + m_frontendDispatcher->pageProxyDestroyed(toPageProxyIDProtocolString(page)); + + auto it = m_browserContextDeletions.find(browserContextID); + if (it != m_browserContextDeletions.end()) { + it->value->didDestroyPage(page); + if (it->value->isFinished()) + m_browserContextDeletions.remove(it); + } + + String pageProxyID = toPageProxyIDProtocolString(page); + auto channelIt = m_pageProxyChannels.find(pageProxyID); + ASSERT(channelIt != m_pageProxyChannels.end()); + channelIt->value->disconnect(); + m_pageProxyChannels.remove(channelIt); +} + +void InspectorPlaywrightAgent::didFailProvisionalLoad(WebPageProxy& page, WebCore::NavigationIdentifier navigationID, const String& error) +{ + if (!m_isEnabled) + return; + + m_frontendDispatcher->provisionalLoadFailed( + toPageProxyIDProtocolString(page), + String::number(navigationID.toUInt64()), error); +} + +void InspectorPlaywrightAgent::willCreateNewPage(WebPageProxy& page, const WebCore::WindowFeatures& features, const URL& url) +{ + if (!m_isEnabled) + return; + + m_frontendDispatcher->windowOpen( + toPageProxyIDProtocolString(page), + url.string(), + getEnabledWindowFeatures(features)); +} + +static WebsiteDataStore* findDefaultWebsiteDataStore() { + WebsiteDataStore* result = nullptr; + WebsiteDataStore::forEachWebsiteDataStore([&result] (WebsiteDataStore& dataStore) { + if (dataStore.isPersistent()) { + RELEASE_ASSERT(result == nullptr); + result = &dataStore; + } + }); + return result; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::enable() +{ + if (m_isEnabled) + return { }; + + m_isEnabled = true; + + auto* defaultDataStore = findDefaultWebsiteDataStore(); + if (!m_defaultContext && defaultDataStore) { + auto context = std::make_unique(); + m_defaultContext = context.get(); + context->processPool = WebProcessPool::allProcessPools().first().ptr(); + context->dataStore = defaultDataStore; + setGeolocationProvider(context.get()); + // Add default context to the map so that we can easily find it for + // created/deleted pages. + PAL::SessionID sessionID = context->dataStore->sessionID(); + m_browserContexts.set(toBrowserContextIDProtocolString(sessionID), WTF::move(context)); + } + + WebsiteDataStore::forEachWebsiteDataStore([this] (WebsiteDataStore& dataStore) { + dataStore.setDownloadInstrumentation(this); + }); + for (Ref pool : WebProcessPool::allProcessPools()) { + for (Ref process : pool->processes()) { + for (Ref page : process->pages()) + didCreateInspectorController(WTF::move(page)); + } + } + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::disable() +{ + if (!m_isEnabled) + return { }; + + m_isEnabled = false; + + for (auto it = m_pageProxyChannels.begin(); it != m_pageProxyChannels.end(); ++it) + it->value->disconnect(); + m_pageProxyChannels.clear(); + + WebsiteDataStore::forEachWebsiteDataStore([] (WebsiteDataStore& dataStore) { + dataStore.setDownloadInstrumentation(nullptr); + dataStore.setDownloadForAutomation(std::optional(), String()); + }); + for (auto& it : m_browserContexts) { + it.value->dataStore->setDownloadInstrumentation(nullptr); + it.value->pages.clear(); + } + m_browserContextDeletions.clear(); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::getInfo() +{ +#if PLATFORM(MAC) + return { "macOS"_s }; +#elif PLATFORM(GTK) || PLATFORM(WPE) + return { "Linux"_s }; +#elif PLATFORM(WIN) + return { "Windows"_s }; +#else +#error "Unsupported platform." +#endif +} + +void InspectorPlaywrightAgent::close(Ref&& callback) +{ + closeImpl([callback = WTF::move(callback)] (String error) { + if (!callback->isActive()) + return; + if (error.isNull()) + callback->sendSuccess(); + else + callback->sendFailure(error); + }); +} + +void InspectorPlaywrightAgent::closeImpl(Function&& callback) +{ + Vector> pages; + // If Web Process crashed it will be disconnected from its pool until + // the page reloads. So we cannot discover such processes and the pages + // by traversing all process pools and their processes. Instead we look at + // all existing Web Processes wether in a pool or not. + for (Ref process : WebProcessProxy::allProcessesForInspector()) { + for (Ref page : process->pages()) + pages.append(WTF::move(page)); + } + for (Ref page : pages) + page->closePage(); + + if (!m_defaultContext) { + m_client->closeBrowser(); + callback(String()); + return; + } + + m_defaultContext->dataStore->syncLocalStorage([this, callback = WTF::move(callback)] () { + if (m_client == nullptr) { + callback("no platform delegate to close browser"_s); + } else { + m_client->closeBrowser(); + callback(String()); + } + }); + +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::createContext(const String& proxyServer, const String& proxyBypassList, std::optional&& enableStoragePartitioning) +{ + String errorString; + std::unique_ptr browserContext = m_client->createBrowserContext(errorString, proxyServer, proxyBypassList); + if (!browserContext) + return makeUnexpected(errorString); + + browserContext->enableStoragePartitioning = WTF::move(enableStoragePartitioning); + // Ensure network process. + browserContext->dataStore->networkProcess(); + browserContext->dataStore->setDownloadInstrumentation(this); + setGeolocationProvider(browserContext.get()); + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + String browserContextID = toBrowserContextIDProtocolString(sessionID); + m_browserContexts.set(browserContextID, WTF::move(browserContext)); + return browserContextID; +} + +void InspectorPlaywrightAgent::deleteContext(const String& browserContextID, Ref&& callback) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!lookupBrowserContext(errorString, browserContextID)) { + callback->sendFailure(errorString); + return; + } + + if (browserContext == m_defaultContext) { + callback->sendFailure("Cannot delete default context"_s); + return; + } + + auto pages = browserContext->pages; + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + auto contextHolder = m_browserContexts.take(browserContextID); + if (pages.isEmpty()) { + callback->sendSuccess(); + } else { + m_browserContextDeletions.set(browserContextID, makeUnique(WTF::move(contextHolder), pages.size(), WTF::move(callback))); + for (auto* page : pages) + page->closePage(); + } + m_client->deleteBrowserContext(errorString, sessionID); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::createPage(const String& browserContextID) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!browserContext) + return makeUnexpected(errorString); + + RefPtr page = m_client->createPage(errorString, *browserContext); + if (!page) + return makeUnexpected(errorString); + + return toPageProxyIDProtocolString(*page); +} + +WebFrameProxy* InspectorPlaywrightAgent::frameForID(const String& frameID, String& error) +{ + std::optional frameIdentifier = WebCore::InspectorPageAgent::parseFrameID(frameID); + if (!frameIdentifier) { + error = "Invalid frame id"_s; + return nullptr; + } + + WebFrameProxy* frame = WebFrameProxy::webFrame(*frameIdentifier); + if (!frame) { + error = "Cannot find web frame for the frame id"_s; + return nullptr; + } + + return frame; +} + +void InspectorPlaywrightAgent::navigate(const String& url, const String& pageProxyID, const String& frameID, const String& referrer, Ref&& callback) +{ + auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID); + if (!pageProxyChannel) { + callback->sendFailure("Cannot find page proxy with provided 'pageProxyId'"_s); + return; + } + + auto resourceRequest = WebCore::ResourceRequest(URL { url }); + + if (!!referrer) + resourceRequest.setHTTPReferrer(referrer); + + if (!resourceRequest.url().isValid()) { + callback->sendFailure("Cannot navigate to invalid URL"_s); + return; + } + + WebFrameProxy* frame = nullptr; + if (!!frameID) { + String error; + frame = frameForID(frameID, error); + if (!frame) { + callback->sendFailure(error); + return; + } + + if (frame->page() != &pageProxyChannel->page()) { + callback->sendFailure("Frame with specified is not from the specified page"_s); + return; + } + } + + pageProxyChannel->page().inspectorController().navigate(WTF::move(resourceRequest), frame, [callback = WTF::move(callback)](const String& error, Markable navigationID) { + if (!error.isEmpty()) { + callback->sendFailure(error); + return; + } + + String navigationIDString; + if (navigationID) + navigationIDString = String::number(navigationID->toUInt64()); + callback->sendSuccess(navigationIDString); + }); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::grantFileReadAccess(const String& pageProxyID, Ref&& paths) +{ +#if ENABLE(SANDBOX_EXTENSIONS) + auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID); + if (!pageProxyChannel) + return makeUnexpected("Unknown pageProxyID"_s); + + Vector files; + for (const auto& value : paths.get()) { + String path; + if (!value->asString(path)) + return makeUnexpected("Filr path must be a string"_s); + + files.append(path); + } + + auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("InspectorPlaywrightAgent::grantFileReadAccess"_s, files); + pageProxyChannel->page().legacyMainFrameProcess().send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTF::move(sandboxExtensionHandles)), pageProxyChannel->page().webPageIDInMainFrameProcess()); +#endif + return { }; +} + +void InspectorPlaywrightAgent::takePageScreenshot(const String& pageProxyID, int x, int y, int width, int height, std::optional&& omitDeviceScaleFactor, Ref&& callback) +{ +#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WPE) + auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID); + if (!pageProxyChannel) { + callback->sendFailure("Unknown pageProxyID"_s); + return; + } + + bool nominalResolution = omitDeviceScaleFactor.has_value() && *omitDeviceScaleFactor; + WebCore::IntRect clip(x, y, width, height); + m_client->takePageScreenshot(pageProxyChannel->page(), WTF::move(clip), nominalResolution, [callback = WTF::move(callback)](const String& error, const String& data) { + if (error.isEmpty()) + callback->sendSuccess(data); + else + callback->sendFailure(error); + }); +#else + return callback->sendFailure("This method is not supported on this platform."_s); +#endif +} + + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setIgnoreCertificateErrors(const String& browserContextID, bool ignore) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + browserContext->dataStore->setIgnoreTLSErrors(ignore); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setPageZoomFactor(const String& pageProxyID, double zoomFactor) +{ + auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID); + if (!pageProxyChannel) + return makeUnexpected("Unknown pageProxyID"_s); + + pageProxyChannel->page().setPageZoomFactor(zoomFactor); + return { }; +} + +void InspectorPlaywrightAgent::getAllCookies(const String& browserContextID, Ref&& callback) { + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + browserContext->dataStore->cookieStore().cookies( + [callback = WTF::move(callback)](const Vector& allCookies) { + if (!callback->isActive()) + return; + auto cookies = JSON::ArrayOf::create(); + + for (const auto& cookie : allCookies) + cookies->addItem(buildObjectForCookie(cookie)); + callback->sendSuccess(WTF::move(cookies)); + }); +} + +void InspectorPlaywrightAgent::setCookies(const String& browserContextID, Ref&& in_cookies, Ref&& callback) { + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + Vector cookies; + for (unsigned i = 0; i < in_cookies->length(); ++i) { + RefPtr item = in_cookies->get(i); + RefPtr obj = item->asObject(); + if (!obj) { + callback->sendFailure("Invalid cookie payload format"_s); + return; + } + + WebCore::Cookie cookie; + cookie.name = obj->getString("name"_s); + cookie.value = obj->getString("value"_s); + cookie.domain = obj->getString("domain"_s); + cookie.path = obj->getString("path"_s); + if (!cookie.name || !cookie.value || !cookie.domain || !cookie.path) { + callback->sendFailure("Invalid file payload format"_s); + return; + } + + std::optional expires = obj->getDouble("expires"_s); + if (expires && *expires != -1) + cookie.expires = *expires; + if (std::optional value = obj->getBoolean("httpOnly"_s)) + cookie.httpOnly = *value; + if (std::optional value = obj->getBoolean("secure"_s)) + cookie.secure = *value; + if (std::optional value = obj->getBoolean("session"_s)) + cookie.session = *value; + String sameSite; + if (obj->getString("sameSite"_s, sameSite)) { + if (sameSite == "None"_s) + cookie.sameSite = WebCore::Cookie::SameSitePolicy::None; + if (sameSite == "Lax"_s) + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Lax; + if (sameSite == "Strict"_s) + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Strict; +#if USE(SOUP) + } else { + // Cookies are Lax by default in libsoup and will reject cookies with + // sameSite: None and secure: false (defaults in WebCore::Cookie). + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Lax; +#endif + } + cookies.append(WTF::move(cookie)); + } + + browserContext->dataStore->cookieStore().setCookies(WTF::move(cookies), + [callback = WTF::move(callback)]() { + if (!callback->isActive()) + return; + callback->sendSuccess(); + }); +} + +void InspectorPlaywrightAgent::deleteAllCookies(const String& browserContextID, Ref&& callback) { + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + browserContext->dataStore->cookieStore().deleteAllCookies( + [callback = WTF::move(callback)]() { + if (!callback->isActive()) + return; + callback->sendSuccess(); + }); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setLanguages(Ref&& languages, const String& browserContextID) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + Vector items; + for (const auto& value : languages.get()) { + String language; + if (!value->asString(language)) + return makeUnexpected("Language must be a string"_s); + + items.append(language); + } + + browserContext->processPool->configuration().setOverrideLanguages(WTF::move(items)); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setDownloadBehavior(const String& behavior, const String& downloadPath, const String& browserContextID) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + std::optional allow; + if (behavior == "allow"_s) + allow = true; + if (behavior == "deny"_s) + allow = false; + browserContext->dataStore->setDownloadForAutomation(allow, downloadPath); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setGeolocationOverride(const String& browserContextID, RefPtr&& geolocation) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + auto* geoManager = browserContext->processPool->supplement(); + if (!geoManager) + return makeUnexpected("Internal error: geolocation manager is not available."_s); + + if (geolocation) { + std::optional timestamp = geolocation->getDouble("timestamp"_s); + std::optional latitude = geolocation->getDouble("latitude"_s); + std::optional longitude = geolocation->getDouble("longitude"_s); + std::optional accuracy = geolocation->getDouble("accuracy"_s); + if (!timestamp || !latitude || !longitude || !accuracy) + return makeUnexpected("Invalid geolocation format"_s); + + auto position = WebGeolocationPosition::create(WebCore::GeolocationPositionData(*timestamp, *latitude, *longitude, *accuracy)); + if (!browserContext->geolocationProvider) + return makeUnexpected("Internal error: geolocation provider has been destroyed."_s); + browserContext->geolocationProvider->setPosition(position); + geoManager->providerDidChangePosition(&position.get()); + } else { + geoManager->providerDidFailToDeterminePosition("Position unavailable"_s); + } + return { }; +} + +void InspectorPlaywrightAgent::downloadCreated(const String& uuid, const WebCore::ResourceRequest& request, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr download) +{ + if (!m_isEnabled) + return; + String frameID = WebCore::InspectorPageAgent::serializeFrameID(frameInfoData.frameID); + m_downloads.set(uuid, download); + m_frontendDispatcher->downloadCreated( + toPageProxyIDProtocolString(*page), + frameID, + uuid, request.url().string()); +} + +void InspectorPlaywrightAgent::downloadFilenameSuggested(const String& uuid, const String& suggestedFilename) +{ + if (!m_isEnabled) + return; + m_frontendDispatcher->downloadFilenameSuggested(uuid, suggestedFilename); +} + +void InspectorPlaywrightAgent::downloadFinished(const String& uuid, const String& error) +{ + if (!m_isEnabled) + return; + m_frontendDispatcher->downloadFinished(uuid, error); + m_downloads.remove(uuid); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::cancelDownload(const String& uuid) +{ + if (!m_isEnabled) + return { }; + auto download = m_downloads.get(uuid); + if (!download) + return { }; + download->cancel([] (auto*) {}); + return { }; +} + +void InspectorPlaywrightAgent::clearMemoryCache(const String& browserContextID, Ref&& callback) +{ + if (!m_isEnabled) { + callback->sendSuccess(); + return; + } + String errorString; + auto browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + browserContext->dataStore->removeData(WebKit::WebsiteDataType::MemoryCache, -WallTime::infinity(), [callback] { + callback->sendSuccess(); + }); +} + +BrowserContext* InspectorPlaywrightAgent::getExistingBrowserContext(const String& browserContextID) +{ + BrowserContext* browserContext = m_browserContexts.get(browserContextID); + if (browserContext) + return browserContext; + + auto it = m_browserContextDeletions.find(browserContextID); + RELEASE_ASSERT(it != m_browserContextDeletions.end()); + return it->value->context(); +} + +BrowserContext* InspectorPlaywrightAgent::lookupBrowserContext(ErrorString& errorString, const String& browserContextID) +{ + if (!browserContextID) { + if (!m_defaultContext) + errorString = "Browser started with no default context"_s; + return m_defaultContext; + } + + BrowserContext* browserContext = m_browserContexts.get(browserContextID); + if (!browserContext) + errorString = "Could not find browser context for given id"_s; + return browserContext; +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..1e31698788ab79bc3807b9f29fa2ebc026374909 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include "WebPageInspectorController.h" +#include "WebProcessPool.h" +#include "DownloadProxy.h" +#include +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +class PlaywrightFrontendDispatcher; +} + +namespace PAL { +class SessionID; +} + +namespace WebKit { +class OverridenGeolocationProvider; +} + +namespace WTF { +template struct IsDeprecatedWeakRefSmartPointerException; +template<> struct IsDeprecatedWeakRefSmartPointerException : std::true_type { }; +} + +namespace WebKit { + +class WebFrameProxy; + +class InspectorPlaywrightAgent final + : public WebPageInspectorControllerObserver + , public Inspector::PlaywrightBackendDispatcherHandler + , public DownloadInstrumentation { + WTF_MAKE_NONCOPYABLE(InspectorPlaywrightAgent); + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(InspectorPlaywrightAgent); +public: + explicit InspectorPlaywrightAgent(std::unique_ptr client); + ~InspectorPlaywrightAgent() override; + + // Transport + void connectFrontend(Inspector::FrontendChannel&); + void disconnectFrontend(); + void dispatchMessageFromFrontend(const String& message); + +private: + class BrowserContextDeletion; + class PageProxyChannel; + class TargetHandler; + + // WebPageInspectorControllerObserver + void didCreateInspectorController(WebPageProxy&) override; + void willDestroyInspectorController(WebPageProxy&) override; + void didFailProvisionalLoad(WebPageProxy&, WebCore::NavigationIdentifier navigationID, const String& error) override; + void willCreateNewPage(WebPageProxy&, const WebCore::WindowFeatures&, const URL&) override; + + // PlaywrightDispatcherHandler + Inspector::Protocol::ErrorStringOr enable() override; + Inspector::Protocol::ErrorStringOr disable() override; + Inspector::Protocol::ErrorStringOr getInfo() override; + void close(Ref&&) override; + Inspector::Protocol::ErrorStringOr createContext(const String& proxyServer, const String& proxyBypassList, std::optional&& enableStoragePartitioning) override; + void deleteContext(const String& browserContextID, Ref&& callback) override; + Inspector::Protocol::ErrorStringOr createPage(const String& browserContextID) override; + void navigate(const String& url, const String& pageProxyID, const String& frameId, const String& referrer, Ref&&) override; + Inspector::Protocol::ErrorStringOr grantFileReadAccess(const String& pageProxyID, Ref&& paths) override; + void takePageScreenshot(const String& pageProxyID, int x, int y, int width, int height, std::optional&& omitDeviceScaleFactor, Ref&&) override; + Inspector::Protocol::ErrorStringOr setIgnoreCertificateErrors(const String& browserContextID, bool ignore) override; + Inspector::Protocol::ErrorStringOr setPageZoomFactor(const String& pageProxyID, double zoomFactor) override; + + void getAllCookies(const String& browserContextID, Ref&&) override; + void setCookies(const String& browserContextID, Ref&& in_cookies, Ref&&) override; + void deleteAllCookies(const String& browserContextID, Ref&&) override; + + Inspector::Protocol::ErrorStringOr setGeolocationOverride(const String& browserContextID, RefPtr&& geolocation) override; + Inspector::Protocol::ErrorStringOr setLanguages(Ref&& languages, const String& browserContextID) override; + Inspector::Protocol::ErrorStringOr setDownloadBehavior(const String& behavior, const String& downloadPath, const String& browserContextID) override; + Inspector::Protocol::ErrorStringOr cancelDownload(const String& uuid) override; + void clearMemoryCache(const String& browserContextID, Ref&&) override; + + // DownloadInstrumentation + void downloadCreated(const String& uuid, const WebCore::ResourceRequest&, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr download) override; + void downloadFilenameSuggested(const String& uuid, const String& suggestedFilename) override; + void downloadFinished(const String& uuid, const String& error) override; + + BrowserContext* getExistingBrowserContext(const String& browserContextID); + BrowserContext* lookupBrowserContext(Inspector::ErrorString&, const String& browserContextID); + WebFrameProxy* frameForID(const String& frameID, String& error); + void closeImpl(Function&&); + + Inspector::FrontendChannel* m_frontendChannel { nullptr }; + Ref m_frontendRouter; + Ref m_backendDispatcher; + std::unique_ptr m_client; + std::unique_ptr m_frontendDispatcher; + Ref m_playwrightDispatcher; + UncheckedKeyHashMap> m_pageProxyChannels; + BrowserContext* m_defaultContext; + UncheckedKeyHashMap> m_downloads; + UncheckedKeyHashMap> m_browserContexts; + UncheckedKeyHashMap> m_browserContextDeletions; + bool m_isEnabled { false }; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h new file mode 100644 index 0000000000000000000000000000000000000000..af71e4077eb0c6f95396de7bfef89a3efb5f12d9 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace WebKit { + +class OverridenGeolocationProvider; +class WebsiteDataStore; +class WebPageProxy; +class WebProcessPool; + +class BrowserContext { + WTF_MAKE_NONCOPYABLE(BrowserContext); + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(BrowserContext); +public: + BrowserContext(); + ~BrowserContext(); + + RefPtr dataStore; + RefPtr processPool; + HashSet pages; + WeakPtr geolocationProvider; + std::optional enableStoragePartitioning; +}; + +class InspectorPlaywrightAgentClient { +public: + virtual ~InspectorPlaywrightAgentClient() = default; + virtual RefPtr createPage(WTF::String& error, const BrowserContext& context) = 0; + virtual void closeBrowser() = 0; + virtual std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) = 0; + virtual void deleteBrowserContext(WTF::String& error, PAL::SessionID) = 0; +#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) + virtual void takePageScreenshot(WebPageProxy&, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler&& completionHandler) = 0; +#endif +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp index 9e0f05585ae96f4ec9ab2390cb015b5307fe85e6..048dfad9f9221fc5389de5d7874a0a67ec61499a 100644 --- a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp +++ b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp @@ -160,6 +160,13 @@ void ProcessLauncher::launchProcess() nargs++; } #endif +// Playwright begin + bool enableSharedArrayBuffer = false; + if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web && m_client && m_client->shouldEnableSharedArrayBuffer()) { + enableSharedArrayBuffer = true; + nargs++; + } +// Playwright end Vector argv(nargs); unsigned i = 0; @@ -175,6 +182,10 @@ void ProcessLauncher::launchProcess() if (configureJSCForTesting) argv[i++] = const_cast("--configure-jsc-for-testing"); #endif +// Playwright begin + if (enableSharedArrayBuffer) + argv[i++] = const_cast("--enable-shared-array-buffer"); +// Playwright end argv[i++] = nullptr; // Warning: we want GIO to be able to spawn with posix_spawn() rather than fork()/exec(), in diff --git a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp index 6723ee0d9943be07bc8ad09d2b678838aca968df..0d7fb3c7b1a4c877a2ff2f2189d12c7d00eb8f7b 100644 --- a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp +++ b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp @@ -91,14 +91,21 @@ void ProcessLauncher::launchProcess() commandLineBuilder.append(" -configure-jsc-for-testing"_s); if (!m_client->isJITEnabled()) commandLineBuilder.append(" -disable-jit"_s); +// Playwright begin + if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web && m_client->shouldEnableSharedArrayBuffer()) + commandLineBuilder.append(" -enable-shared-array-buffer"_s); +// Playwright end commandLineBuilder.append('\0'); auto commandLine = commandLineBuilder.toString().wideCharacters(); STARTUPINFO startupInfo { }; startupInfo.cb = sizeof(startupInfo); - startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; startupInfo.wShowWindow = SW_HIDE; + startupInfo.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startupInfo.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startupInfo.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); PROCESS_INFORMATION processInformation { }; BOOL result = ::CreateProcess(0, commandLine.mutableSpan().data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation); diff --git a/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp b/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp index e9bf93632655ddfe5104808d67cb1e550e965098..a62ab1cb298654ea69cc8131f275d2cc7fe75602 100644 --- a/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp +++ b/Source/WebKit/UIProcess/Media/RemoteMediaSessionManagerProxy.cpp @@ -31,6 +31,7 @@ #include "MessageSenderInlines.h" #include "RemoteMediaSessionClientProxy.h" #include "RemoteMediaSessionManagerMessages.h" +#include "RemoteMediaSessionManager.h" #include "RemoteMediaSessionManagerProxyMessages.h" #include "RemoteMediaSessionProxy.h" #include "RemoteMediaSessionState.h" diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h index ec8a8accd195844f2ceb5fea0d73bc0ab50ce733..164e60cbc7fbd520d4d43a99021891c770f1fe3e 100644 --- a/Source/WebKit/UIProcess/PageClient.h +++ b/Source/WebKit/UIProcess/PageClient.h @@ -77,6 +77,11 @@ #include #endif +#if USE(SKIA) +#include +#include +#endif + OBJC_CLASS AVPlayerViewController; OBJC_CLASS CALayer; OBJC_CLASS NSFileWrapper; @@ -400,7 +405,15 @@ public: virtual void selectionDidChange() = 0; #endif -#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) +// Paywright begin +#if PLATFORM(COCOA) + virtual RetainPtr takeSnapshotForAutomation() = 0; +#elif PLATFORM(GTK) || PLATFORM(WPE) + virtual RefPtr takeViewSnapshot(std::optional&&, bool nominalResolution = false) = 0; +#endif +// Paywright end + +#if PLATFORM(COCOA) virtual RefPtr takeViewSnapshot(std::optional&&) = 0; #endif diff --git a/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.cpp b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95b682567eba682f927317cd3327a531358dfebc --- /dev/null +++ b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "PlaywrightFullScreenManagerProxyClient.h" + +#if ENABLE(FULLSCREEN_API) + +#include "WebPageProxy.h" + +namespace WebKit { +using namespace WebCore; + +PlaywrightFullScreenManagerProxyClient::PlaywrightFullScreenManagerProxyClient(WebPageProxy& page) + : m_pageProxy(page) +{ +} + +void PlaywrightFullScreenManagerProxyClient::enterFullScreen(WebCore::FloatSize, CompletionHandler&& completionHandler) +{ + completionHandler(true); +} + +void PlaywrightFullScreenManagerProxyClient::exitFullScreen(CompletionHandler&& completionHandler) +{ + completionHandler(); +} + +void PlaywrightFullScreenManagerProxyClient::beganEnterFullScreen(const WebCore::IntRect&, const WebCore::IntRect&, CompletionHandler&& completionHandler) +{ + completionHandler(true); +} + +void PlaywrightFullScreenManagerProxyClient::beganExitFullScreen(const WebCore::IntRect&, const WebCore::IntRect&, CompletionHandler&& completionHandler) +{ + completionHandler(); +} + +} // namespace WebKit + +#endif // ENABLE(FULLSCREEN_API) diff --git a/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.h b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.h new file mode 100644 index 0000000000000000000000000000000000000000..f855bb5ff6e91cc3383fb9a96d32392ff7aa5493 --- /dev/null +++ b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(FULLSCREEN_API) + +#include "WebFullScreenManagerProxy.h" + +namespace WebKit { + +class WebPageProxy; + +class PlaywrightFullScreenManagerProxyClient : public WebFullScreenManagerProxyClient { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(PlaywrightFullScreenManagerProxyClient); +public: + PlaywrightFullScreenManagerProxyClient(WebPageProxy&); + ~PlaywrightFullScreenManagerProxyClient() override = default; + +private: + void closeFullScreenManager() override { } + bool isFullScreen() override { return m_isFullScreen; } + void enterFullScreen(WebCore::FloatSize mediaDimensions, CompletionHandler&&) override; + void exitFullScreen(CompletionHandler&&) override; + void beganEnterFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame, CompletionHandler&&) override; + void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame, CompletionHandler&&) override; + + WebPageProxy& m_pageProxy; + bool m_isFullScreen { false }; +}; + +} // namespace WebKit + +#endif // ENABLE(FULLSCREEN_API) diff --git a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp index 0e8f21982c6499e6886f5db6c193afc43663f29c..43ed4c8837479744a98ef76ceb2911c0e49d3f2b 100644 --- a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp +++ b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "ProvisionalFrameProxy.h" +#include "WebFrameProxy.h" #include "FrameProcess.h" #include "ProvisionalFrameCreationParameters.h" diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.h b/Source/WebKit/UIProcess/ProvisionalPageProxy.h index 90b6b6b10906e9bf9f4229dc413421380be8a01a..0620c78e35e40e5b4997ab3813cac98cfdef7372 100644 --- a/Source/WebKit/UIProcess/ProvisionalPageProxy.h +++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.h @@ -32,8 +32,10 @@ #include "ProcessThrottler.h" #include "SandboxExtension.h" #include "WebFramePolicyListenerProxy.h" +#include "WebPageProxy.h" #include "WebPageProxyIdentifier.h" #include "WebPageProxyMessageReceiverRegistration.h" +#include "WebsiteDataStore.h" #include #include #include @@ -74,7 +76,6 @@ class WebBackForwardListItem; class WebFrameProxy; class WebPageProxy; class WebProcessProxy; -class WebsiteDataStore; struct FrameInfoData; struct NavigationActionData; diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5fe95e4019e5b2b4e510174111166fb36089e9a --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RemoteInspectorPipe.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include +#include +#include +#include +#include +#include +#include + +#if OS(UNIX) +#include +#include +#endif + +#if PLATFORM(WIN) +#include +#endif + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace WebKit { + +namespace { + +const int readFD = 3; +const int writeFD = 4; + +const size_t kWritePacketSize = 1 << 16; + +#if PLATFORM(WIN) +HANDLE readHandle; +HANDLE writeHandle; +#endif + +size_t ReadBytes(void* buffer, size_t size, bool exact_size) +{ + size_t bytesRead = 0; + while (bytesRead < size) { +#if PLATFORM(WIN) + DWORD sizeRead = 0; + bool hadError = !ReadFile(readHandle, static_cast(buffer) + bytesRead, + size - bytesRead, &sizeRead, nullptr); +#else + int sizeRead = read(readFD, static_cast(buffer) + bytesRead, + size - bytesRead); + if (sizeRead < 0 && errno == EINTR) + continue; + bool hadError = sizeRead <= 0; +#endif + if (hadError) { + return 0; + } + bytesRead += sizeRead; + if (!exact_size) + break; + } + return bytesRead; +} + +void WriteBytes(const char* bytes, size_t size) +{ + size_t totalWritten = 0; + while (totalWritten < size) { + size_t length = size - totalWritten; + if (length > kWritePacketSize) + length = kWritePacketSize; +#if PLATFORM(WIN) + DWORD bytesWritten = 0; + bool hadError = !WriteFile(writeHandle, bytes + totalWritten, static_cast(length), &bytesWritten, nullptr); +#else + int bytesWritten = write(writeFD, bytes + totalWritten, length); + if (bytesWritten < 0 && errno == EINTR) + continue; + bool hadError = bytesWritten <= 0; +#endif + if (hadError) + return; + totalWritten += bytesWritten; + } +} + +} // namespace + +class RemoteInspectorPipe::RemoteFrontendChannel : public Inspector::FrontendChannel { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(RemoteInspectorPipe::RemoteFrontendChannel); +public: + RemoteFrontendChannel() + : m_senderQueue(WorkQueue::create("Inspector pipe writer"_s)) + { + } + + ~RemoteFrontendChannel() override = default; + + ConnectionType connectionType() const override + { + return ConnectionType::Remote; + } + + void sendMessageToFrontend(const String& message) override + { + m_senderQueue->dispatch([message = message.isolatedCopy()]() { + auto utf8 = message.utf8(); + WriteBytes(utf8.data(), utf8.length()); + WriteBytes("\0", 1); + }); + } + +private: + Ref m_senderQueue; +}; + +RemoteInspectorPipe::RemoteInspectorPipe(InspectorPlaywrightAgent& playwrightAgent) + : m_playwrightAgent(playwrightAgent) +{ + m_remoteFrontendChannel = makeUnique(); + start(); +} + +RemoteInspectorPipe::~RemoteInspectorPipe() +{ + stop(); +} + +bool RemoteInspectorPipe::start() +{ + if (m_receiverThread) + return true; + +#if PLATFORM(WIN) + readHandle = reinterpret_cast(_get_osfhandle(readFD)); + writeHandle = reinterpret_cast(_get_osfhandle(writeFD)); +#endif + + m_playwrightAgent.connectFrontend(*m_remoteFrontendChannel); + m_terminated = false; + m_receiverThread = Thread::create("Inspector pipe reader"_s, [this] { + workerRun(); + }); + return true; +} + +void RemoteInspectorPipe::stop() +{ + if (!m_receiverThread) + return; + + m_playwrightAgent.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) { + size_t size = ReadBytes(buffer.get(), bufSize, false); + if (!size) { + RunLoop::mainSingleton().dispatch([this] { + if (!m_terminated) + m_playwrightAgent.disconnectFrontend(); + }); + break; + } + size_t start = 0; + size_t end = line.size(); + line.append(std::span { 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.mutableSpan().data() + start, end - start }); + RunLoop::mainSingleton().dispatch([this, message = WTF::move(message)] { + if (!m_terminated) + m_playwrightAgent.dispatchMessageFromFrontend(message); + }); + } + ++end; + start = end; + } + if (start != 0 && start < line.size()) + memmove(line.mutableSpan().data(), line.mutableSpan().data() + start, line.size() - start); + line.shrink(line.size() - start); + } +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.h b/Source/WebKit/UIProcess/RemoteInspectorPipe.h new file mode 100644 index 0000000000000000000000000000000000000000..23626aa70d5a14e6484c81e05b146b375379be4f --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include +#include + +namespace Inspector { +class FrontendChannel; +} + +namespace WebKit { + +class InspectorPlaywrightAgent; + +class RemoteInspectorPipe { + WTF_MAKE_NONCOPYABLE(RemoteInspectorPipe); + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(RemoteInspectorPipe); +public: + explicit RemoteInspectorPipe(InspectorPlaywrightAgent&); + ~RemoteInspectorPipe(); + +private: + class RemoteFrontendChannel; + + bool start(); + void stop(); + + void workerRun(); + + RefPtr m_receiverThread; + std::atomic m_terminated { false }; + std::unique_ptr m_remoteFrontendChannel; + InspectorPlaywrightAgent& m_playwrightAgent; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteAnimationTimeline.cpp b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteAnimationTimeline.cpp index 7ef986965d3fda34b4f09279c62bdad40712ab12..5e0bc508f72bbbd0bcb4bb1254782028961867a9 100644 --- a/Source/WebKit/UIProcess/RemoteLayerTree/RemoteAnimationTimeline.cpp +++ b/Source/WebKit/UIProcess/RemoteLayerTree/RemoteAnimationTimeline.cpp @@ -30,6 +30,7 @@ #import "RemoteAnimationUtilities.h" #import +#import namespace WebKit { diff --git a/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm b/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm index 07e7aec9d5f53dd4adfb83b6626f469621362663..18d049adb49ab565f60e9e1dded55da1a6aaaf3a 100644 --- a/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm +++ b/Source/WebKit/UIProcess/RemoteLayerTree/mac/RemoteScrollingTreeMac.mm @@ -46,6 +46,7 @@ #import #import #import +#import #import namespace WebKit { diff --git a/Source/WebKit/UIProcess/RemotePagePlaybackSessionManagerProxy.h b/Source/WebKit/UIProcess/RemotePagePlaybackSessionManagerProxy.h index 3f6cd845733e2e8f5e25c318e7ab54f77032d4cf..e4399bfd734a28ef5df5ec855b7c78b46634c91d 100644 --- a/Source/WebKit/UIProcess/RemotePagePlaybackSessionManagerProxy.h +++ b/Source/WebKit/UIProcess/RemotePagePlaybackSessionManagerProxy.h @@ -28,11 +28,11 @@ #if PLATFORM(IOS_FAMILY) || (PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)) #include "MessageReceiver.h" +#include "PlaybackSessionManagerProxy.h" #include namespace WebKit { -class PlaybackSessionManagerProxy; class WebProcessProxy; class RemotePagePlaybackSessionManagerProxy : public IPC::MessageReceiver, public RefCounted { diff --git a/Source/WebKit/UIProcess/RemotePageProxy.cpp b/Source/WebKit/UIProcess/RemotePageProxy.cpp index f7a0ee83fa8ee37d1c6d927f167b6e6bb647d817..919494d9b459a94d17617a0b514552e21cd21a29 100644 --- a/Source/WebKit/UIProcess/RemotePageProxy.cpp +++ b/Source/WebKit/UIProcess/RemotePageProxy.cpp @@ -37,6 +37,7 @@ #include "ProvisionalFrameProxy.h" #include "RemotePageDrawingAreaProxy.h" #include "RemotePageFullscreenManagerProxy.h" +#include "RemotePagePlaybackSessionManagerProxy.h" #include "RemotePageScreenOrientationManagerProxy.h" #include "RemotePageVisitedLinkStoreRegistration.h" #include "RemotePageWebDeviceOrientationUpdateProviderProxy.h" @@ -56,6 +57,7 @@ #include #include + #if ENABLE(FULLSCREEN_API) #include "WebFullScreenManagerProxy.h" #endif diff --git a/Source/WebKit/UIProcess/TextExtractionAssertionScope.h b/Source/WebKit/UIProcess/TextExtractionAssertionScope.h index 986c0812fedd2be938675ef5de41041e9fc76a0b..69da96c1e1ccb3b6d6b142ccb3b337f0bcb14957 100644 --- a/Source/WebKit/UIProcess/TextExtractionAssertionScope.h +++ b/Source/WebKit/UIProcess/TextExtractionAssertionScope.h @@ -25,13 +25,12 @@ #pragma once +#include "WebPageProxy.h" #include #include namespace WebKit { -class WebPageProxy; - class TextExtractionAssertionScope { WTF_MAKE_TZONE_ALLOCATED(TextExtractionAssertionScope); WTF_MAKE_NONCOPYABLE(TextExtractionAssertionScope); diff --git a/Source/WebKit/UIProcess/WebContextMenuProxy.h b/Source/WebKit/UIProcess/WebContextMenuProxy.h index 364666d82ffd69aef6cb4f8d63b61ae13e163d87..a491699c43502e6feae3b3df73b3558a79bb73e3 100644 --- a/Source/WebKit/UIProcess/WebContextMenuProxy.h +++ b/Source/WebKit/UIProcess/WebContextMenuProxy.h @@ -51,6 +51,7 @@ public: void deref() const final { RefCounted::deref(); } virtual void show(); + virtual void hide() {} WebPageProxy* page() const { return m_page.get(); } const FrameInfoData& frameInfo() const LIFETIME_BOUND { return m_frameInfo; } diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc495bff7d10aeb071ba30002d292b82e26d51b7 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" + +#include "APIPageConfiguration.h" +#include "WebPageProxy.h" +#include "WebPreferences.h" +#include "PageClient.h" +#include +#include + + +namespace WebKit { + +using namespace Inspector; + +WTF_MAKE_TZONE_ALLOCATED_IMPL(WebPageInspectorEmulationAgent); + +WebPageInspectorEmulationAgent::WebPageInspectorEmulationAgent(BackendDispatcher& backendDispatcher, WebPageProxy& page) + : InspectorAgentBase("Emulation"_s) + , m_backendDispatcher(EmulationBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +WebPageInspectorEmulationAgent::~WebPageInspectorEmulationAgent() +{ +} + +void WebPageInspectorEmulationAgent::didCreateFrontendAndBackend() +{ +} + +void WebPageInspectorEmulationAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ + m_commandsToRunWhenShown.clear(); +} + +void WebPageInspectorEmulationAgent::setDeviceMetricsOverride(int width, int height, bool fixedlayout, std::optional&& deviceScaleFactor, Ref&& callback) +{ +#if PLATFORM(GTK) + // On gtk, fixed layout doesn't work with compositing enabled + // FIXME: This turns off compositing forever, even if fixedLayout is disabled. + if (fixedlayout) { + auto copy = m_page.preferences().copy(); + copy->setAcceleratedCompositingEnabled(false); + m_page.setPreferences(copy); + } +#endif + + if (deviceScaleFactor) + m_page.setCustomDeviceScaleFactor(deviceScaleFactor.value(), [] { }); + m_page.setUseFixedLayout(fixedlayout); + if (!m_page.pageClient()->isActiveViewVisible() && m_page.configuration().relatedPage()) { + m_commandsToRunWhenShown.append([this, width, height, callback = WTF::move(callback)]() mutable { + setSize(width, height, WTF::move(callback)); + }); + } else { + setSize(width, height, WTF::move(callback)); + } +} + +void WebPageInspectorEmulationAgent::setSize(int width, int height, Ref&& callback) +{ + platformSetSize(width, height, [callback = WTF::move(callback)](const String& error) { + if (error.isEmpty()) + callback->sendSuccess(); + else + callback->sendFailure(error); + }); +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setJavaScriptEnabled(bool enabled) +{ + auto copy = m_page.preferences().copy(); + copy->setJavaScriptEnabled(enabled); + m_page.setPreferences(copy); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setAuthCredentials(const String& username, const String& password, const String& origin) +{ + if (username.isNull() && password.isNull()) + m_page.setAuthCredentialsForAutomation(std::nullopt, std::nullopt); + else + m_page.setAuthCredentialsForAutomation(WebCore::Credential(username, password, WebCore::CredentialPersistence::Permanent), URL(origin)); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setActiveAndFocused(std::optional&& active) +{ + m_page.setActiveForAutomation(WTF::move(active)); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::grantPermissions(const String& origin, Ref&& values) +{ + HashSet set; + for (const auto& value : values.get()) { + String name; + if (!value->asString(name)) + return makeUnexpected("Permission must be a string"_s); + + set.add(name); + } + m_permissions.set(origin, WTF::move(set)); + m_page.setPermissionsForAutomation(m_permissions); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::resetPermissions() +{ + m_permissions.clear(); + m_page.setPermissionsForAutomation(m_permissions); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setOrientationOverride(std::optional&& angle) +{ +#if ENABLE(ORIENTATION_EVENTS) + m_page.setOrientationOverride(WTF::move(angle)); + return { }; +#else + UNUSED_PARAM(angle); + return makeUnexpected("Orientation events are disabled in this build"_s); +#endif +} + + +void WebPageInspectorEmulationAgent::didShowPage() +{ + for (auto& command : m_commandsToRunWhenShown) + command(); + m_commandsToRunWhenShown.clear(); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..8c772fb1b67ec7d83cbe2394d8ab04787a4412a8 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +#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_TZONE_ALLOCATED(WebPageInspectorEmulationAgent); +public: + WebPageInspectorEmulationAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorEmulationAgent() override; + + void didCreateFrontendAndBackend() override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + void setDeviceMetricsOverride(int width, int height, bool fixedlayout, std::optional&& deviceScaleFactor, Ref&&) override; + Inspector::Protocol::ErrorStringOr setJavaScriptEnabled(bool enabled) override; + Inspector::Protocol::ErrorStringOr setAuthCredentials(const String&, const String&, const String&) override; + Inspector::Protocol::ErrorStringOr setActiveAndFocused(std::optional&&) override; + Inspector::Protocol::ErrorStringOr grantPermissions(const String& origin, Ref&& permissions) override; + Inspector::Protocol::ErrorStringOr resetPermissions() override; + Inspector::Protocol::ErrorStringOr setOrientationOverride(std::optional&& angle) override; + + void didShowPage(); + +private: + void setSize(int width, int height, Ref&& callback); + void platformSetSize(int width, int height, Function&&); + + Ref m_backendDispatcher; + WebPageProxy& m_page; + Vector> m_commandsToRunWhenShown; + UncheckedKeyHashMap> m_permissions; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a29ae94cda78928fab928bbdd250f8cd1c8b4cc5 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "MessageSenderInlines.h" +#include "WebPageInspectorInputAgent.h" + +#include "NativeWebKeyboardEvent.h" +#include "NativeWebMouseEvent.h" +#include "NativeWebWheelEvent.h" +#include "WebPageProxy.h" +#include "WebProcessProxy.h" +#include "WebTouchEvent.h" +#include "WebWheelEvent.h" +#include +#include +#include + +#include "WebPageMessages.h" + +namespace WebKit { + +using namespace Inspector; + +WTF_MAKE_TZONE_ALLOCATED_IMPL(WebPageInspectorInputAgent); + +namespace { + +template +class CallbackList { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(CallbackList); +public: + ~CallbackList() + { + for (const auto& callback : m_callbacks) + callback->sendFailure("Page closed"_s); + } + + void append(Ref&& callback) + { + m_callbacks.append(WTF::move(callback)); + } + + void sendSuccess() + { + for (const auto& callback : m_callbacks) + callback->sendSuccess(); + m_callbacks.clear(); + } + +private: + Vector> m_callbacks; +}; + +} // namespace + +class WebPageInspectorInputAgent::KeyboardCallbacks : public CallbackList { +}; + +class WebPageInspectorInputAgent::MouseCallbacks : public CallbackList { +}; + +class WebPageInspectorInputAgent::WheelCallbacks : public CallbackList { +}; + +WebPageInspectorInputAgent::WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page) + : InspectorAgentBase("Input"_s) + , m_backendDispatcher(InputBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +WebPageInspectorInputAgent::~WebPageInspectorInputAgent() = default; + +void WebPageInspectorInputAgent::didProcessAllPendingKeyboardEvents() +{ + m_keyboardCallbacks->sendSuccess(); +} + +void WebPageInspectorInputAgent::didProcessAllPendingMouseEvents() +{ + m_page.setInterceptDrags(false); + m_mouseCallbacks->sendSuccess(); +} + +void WebPageInspectorInputAgent::didProcessAllPendingWheelEvents() +{ + m_wheelCallbacks->sendSuccess(); +} + +void WebPageInspectorInputAgent::didCreateFrontendAndBackend() +{ + m_keyboardCallbacks = makeUnique(); + m_mouseCallbacks = makeUnique(); + m_wheelCallbacks = makeUnique(); +} + +void WebPageInspectorInputAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ + m_keyboardCallbacks = nullptr; + m_mouseCallbacks = nullptr; + m_wheelCallbacks = nullptr; +} + +static String keyIdentifierForKey(const String& key) +{ + if (key.length() == 1) + return makeString("U+"_s, hex(toASCIIUpper(key.codeUnitAt(0)), 4)); + if (key == "Delete"_s) + return "U+007F"_s; + if (key == "Backspace"_s) + return "U+0008"_s; + if (key == "ArrowUp"_s) + return "Up"_s; + if (key == "ArrowDown"_s) + return "Down"_s; + if (key == "ArrowLeft"_s) + return "Left"_s; + if (key == "ArrowRight"_s) + return "Right"_s; + if (key == "Tab"_s) + return "U+0009"_s; + if (key == "Pause"_s) + return "Pause"_s; + if (key == "ScrollLock"_s) + return "Scroll"_s; + return key; +} + +void WebPageInspectorInputAgent::dispatchKeyEvent(const String& type, std::optional&& modifiers, const String& text, const String& unmodifiedText, const String& code, const String& key, std::optional&& windowsVirtualKeyCode, std::optional&& nativeVirtualKeyCode, std::optional&& autoRepeat, std::optional&& isKeypad, std::optional&& isSystemKey, RefPtr&& commands, Ref&& callback) +{ + WebEventType eventType; + if (type == "keyDown"_s) { + eventType = WebEventType::KeyDown; + } else if (type == "keyUp"_s) { + eventType = WebEventType::KeyUp; + } else { + callback->sendFailure("Unsupported event type."_s); + return; + } + OptionSet eventModifiers; + if (modifiers) + eventModifiers = eventModifiers.fromRaw(*modifiers); + int eventWindowsVirtualKeyCode = 0; + if (windowsVirtualKeyCode) + eventWindowsVirtualKeyCode = *windowsVirtualKeyCode; + int eventNativeVirtualKeyCode = 0; + if (nativeVirtualKeyCode) + eventNativeVirtualKeyCode = *nativeVirtualKeyCode; + Vector eventCommands; + if (commands) { + for (const auto& value : *commands) { + String command; + if (!value->asString(command)) { + callback->sendFailure("Command must be string"_s); + return; + } + eventCommands.append(command); + } + } + + String keyIdentifier = keyIdentifierForKey(key); + + bool eventIsAutoRepeat = false; + if (autoRepeat) + eventIsAutoRepeat = *autoRepeat; + bool eventIsKeypad = false; + if (isKeypad) + eventIsKeypad = *isKeypad; + bool eventIsSystemKey = false; + if (isSystemKey) + eventIsSystemKey = *isSystemKey; + MonotonicTime timestamp = MonotonicTime::now(); + + // cancel any active drag on Escape + if (eventType == WebEventType::KeyDown && key == "Escape"_s && m_page.cancelDragIfNeeded()) { + callback->sendSuccess(); + return; + } + + m_keyboardCallbacks->append(WTF::move(callback)); + platformDispatchKeyEvent( + eventType, + text, + unmodifiedText, + key, + code, + keyIdentifier, + eventWindowsVirtualKeyCode, + eventNativeVirtualKeyCode, + eventIsAutoRepeat, + eventIsKeypad, + eventIsSystemKey, + eventModifiers, + eventCommands, + timestamp); +} + +void WebPageInspectorInputAgent::dispatchMouseEvent(const String& type, int x, int y, std::optional&& modifiers, const String& button, std::optional&& buttons, std::optional&& clickCount, std::optional&& deltaX, std::optional&& deltaY, Ref&& callback) +{ + WebEventType eventType = WebEventType::MouseMove; + if (type == "down"_s) + eventType = WebEventType::MouseDown; + else if (type == "up"_s) + eventType = WebEventType::MouseUp; + else if (type == "move"_s) + eventType = WebEventType::MouseMove; + else { + callback->sendFailure("Unsupported event type"_s); + return; + } + + OptionSet eventModifiers; + if (modifiers) + eventModifiers = eventModifiers.fromRaw(*modifiers); + + WebMouseEventButton eventButton = WebMouseEventButton::None; + if (!!button) { + if (button == "left"_s) + eventButton = WebMouseEventButton::Left; + else if (button == "middle"_s) + eventButton = WebMouseEventButton::Middle; + else if (button == "right"_s) + eventButton = WebMouseEventButton::Right; + else if (button == "none"_s) + eventButton = WebMouseEventButton::None; + else { + callback->sendFailure("Unsupported eventButton"_s); + return; + } + } + + unsigned short eventButtons = 0; + if (buttons) + eventButtons = *buttons; + + int eventClickCount = 0; + if (clickCount) + eventClickCount = *clickCount; + int eventDeltaX = 0; + if (deltaX) + eventDeltaX = *deltaX; + int eventDeltaY = 0; + if (deltaY) + eventDeltaY = *deltaY; + m_mouseCallbacks->append(WTF::move(callback)); + + // Convert css coordinates to view coordinates (dip). + double totalScale = m_page.pageScaleFactor() * m_page.viewScaleFactor() * m_page.pageZoomFactor(); + x = clampToInteger(roundf(x * totalScale)); + y = clampToInteger(roundf(y * totalScale)); + eventDeltaX = clampToInteger(roundf(eventDeltaX * totalScale)); + eventDeltaY = clampToInteger(roundf(eventDeltaY * totalScale)); + + // We intercept any drags generated by this mouse event + // to prevent them from creating actual drags in the host + // operating system. This is turned off in the callback. + m_page.setInterceptDrags(true); +#if PLATFORM(MAC) + UNUSED_VARIABLE(eventType); + UNUSED_VARIABLE(eventButton); + UNUSED_VARIABLE(eventClickCount); + platformDispatchMouseEvent(type, x, y, WTF::move(modifiers), button, WTF::move(clickCount), eventButtons); +#elif PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN) + MonotonicTime timestamp = MonotonicTime::now(); + NativeWebMouseEvent event( + eventType, + eventButton, + eventButtons, + {x, y}, + WebCore::IntPoint(), + eventDeltaX, + eventDeltaY, + 0, + eventClickCount, + eventModifiers, + timestamp); + m_page.handleMouseEvent(event); +#endif +} + +void WebPageInspectorInputAgent::dispatchTapEvent(int x, int y, std::optional&& modifiers, Ref&& callback) +{ + m_page.legacyMainFrameProcess().sendWithAsyncReply(Messages::WebPage::FakeTouchTap(WebCore::IntPoint(x, y), modifiers ? *modifiers : 0), [callback]() { + callback->sendSuccess(); + }, m_page.webPageIDInMainFrameProcess()); +} + +void WebPageInspectorInputAgent::dispatchTouchEvent(const String& type, std::optional&& modifiers, RefPtr&& in_touchPoints, Ref&& callback) +{ + float rotationAngle = 0.0; + float force = 1.0; + const WebCore::DoubleSize radius(1, 1); + + uint8_t unsignedModifiers = modifiers ? static_cast(*modifiers) : 0; + OptionSet eventModifiers; + eventModifiers = eventModifiers.fromRaw(unsignedModifiers); + + WebPlatformTouchPoint::State state; + if (type == "touchStart"_s) + state = WebPlatformTouchPoint::State::Pressed; + else if (type == "touchMove"_s) + state = WebPlatformTouchPoint::State::Moved; + else if (type == "touchEnd"_s) + state = WebPlatformTouchPoint::State::Released; + else if (type == "touchCancel"_s) + state = WebPlatformTouchPoint::State::Cancelled; + else { + callback->sendFailure("Unsupported event type"_s); + return; + } + + Vector touchPoints; + for (unsigned i = 0; i < in_touchPoints->length(); ++i) { + RefPtr item = in_touchPoints->get(i); + RefPtr obj = item->asObject(); + if (!obj) { + callback->sendFailure("Invalid TouchPoint format"_s); + return; + } + std::optional x = obj->getInteger("x"_s); + if (!x) { + callback->sendFailure("TouchPoint does not have x"_s); + return; + } + std::optional y = obj->getInteger("y"_s); + if (!y) { + callback->sendFailure("TouchPoint does not have y"_s); + return; + } + std::optional optionalId = obj->getInteger("id"_s); + int id = optionalId ? *optionalId : 0; + const WebCore::IntPoint position(*x, *y); + touchPoints.append(WebPlatformTouchPoint(id, state, position, position, radius, rotationAngle, force)); + } + + WebTouchEvent touchEvent({WebEventType::TouchStart, eventModifiers, MonotonicTime::now()}, WTF::move(touchPoints), {}, {}); + m_page.legacyMainFrameProcess().sendWithAsyncReply(Messages::WebPage::TouchEvent(touchEvent), [callback] (std::optional eventType, bool) { + if (!eventType) { + callback->sendFailure("Failed to dispatch touch event."_s); + return; + } + callback->sendSuccess(); + }, m_page.webPageIDInMainFrameProcess()); +} + +void WebPageInspectorInputAgent::dispatchWheelEvent(int x, int y, std::optional&& modifiers, std::optional&& deltaX, std::optional&& deltaY, Ref&& callback) +{ + OptionSet eventModifiers; + if (modifiers) + eventModifiers = eventModifiers.fromRaw(*modifiers); + + float eventDeltaX = 0.0f; + if (deltaX) + eventDeltaX = *deltaX; + float eventDeltaY = 0.0f; + if (deltaY) + eventDeltaY = *deltaY; + m_wheelCallbacks->append(WTF::move(callback)); + + // Convert css coordinates to view coordinates (dip). + double totalScale = m_page.pageScaleFactor() * m_page.viewScaleFactor() * m_page.pageZoomFactor(); + x = clampToInteger(roundf(x * totalScale)); + y = clampToInteger(roundf(y * totalScale)); + + MonotonicTime timestamp = MonotonicTime::now(); + WebCore::FloatSize delta = {-eventDeltaX, -eventDeltaY}; + WebCore::FloatSize wheelTicks = delta; + wheelTicks.scale(1.0f / WebCore::Scrollbar::pixelsPerLineStep()); + WebWheelEvent webEvent({WebEventType::Wheel, eventModifiers, timestamp}, {x, y}, {x, y}, delta, wheelTicks, WebWheelEvent::Granularity::ScrollByPixelWheelEvent); + NativeWebWheelEvent event(webEvent); + m_page.handleNativeWheelEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..fb0cd51d362dfd8af2370f43ecb8835c96450f21 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "WebEvent.h" +#include "WebKeyboardEvent.h" +#include "WebMouseEvent.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_TZONE_ALLOCATED(WebPageInspectorInputAgent); +public: + WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorInputAgent() override; + + void didProcessAllPendingKeyboardEvents(); + void didProcessAllPendingMouseEvents(); + void didProcessAllPendingWheelEvents(); + + void didCreateFrontendAndBackend() override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + // Protocol handler + void dispatchKeyEvent(const String& type, std::optional&& modifiers, const String& text, const String& unmodifiedText, const String& code, const String& key, std::optional&& windowsVirtualKeyCode, std::optional&& nativeVirtualKeyCode, std::optional&& autoRepeat, std::optional&& isKeypad, std::optional&& isSystemKey, RefPtr&&, Ref&& callback) override; + void dispatchMouseEvent(const String& type, int x, int y, std::optional&& modifiers, const String& button, std::optional&& buttons, std::optional&& clickCount, std::optional&& deltaX, std::optional&& deltaY, Ref&& callback) override; + void dispatchTapEvent(int x, int y, std::optional&& modifiers, Ref&& callback) override; + void dispatchTouchEvent(const String& type, std::optional&& modifiers, RefPtr&& touchPoints, Ref&& callback) override; + void dispatchWheelEvent(int x, int y, std::optional&& modifiers, std::optional&& deltaX, std::optional&& deltaY, Ref&& callback) override; + +private: + void platformDispatchKeyEvent(WebEventType 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, Vector& commands, MonotonicTime timestamp); +#if PLATFORM(MAC) + void platformDispatchMouseEvent(const String& type, int x, int y, std::optional&& modifier, const String& button, std::optional&& clickCount, unsigned short buttons); +#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 KeyboardCallbacks; + std::unique_ptr m_keyboardCallbacks; + class MouseCallbacks; + std::unique_ptr m_mouseCallbacks; + class WheelCallbacks; + std::unique_ptr m_wheelCallbacks; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index b51fd21469a35bea05d91465215e463dd9be078d..87789a4c6edfd8b48bcb3f083cc8b4edb3c5a498 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -219,6 +219,7 @@ #include #include #include +#include #include #include #include @@ -232,6 +233,7 @@ #include #include #include +#include #include #include #include @@ -260,6 +262,7 @@ #include #include #include +#include #include #include #include @@ -269,10 +272,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -366,7 +371,7 @@ #include "ViewSnapshotStore.h" #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) #include #endif @@ -496,6 +501,17 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms; static constexpr Seconds audibleActivityClearDelay = 10_s; #endif +static WebCore::ScreenOrientationType toScreenOrientationType(int angle) +{ + if (angle == -90) + return WebCore::ScreenOrientationType::LandscapeSecondary; + if (angle == 180) + return WebCore::ScreenOrientationType::PortraitSecondary; + if (angle == 90) + return WebCore::ScreenOrientationType::LandscapePrimary; + return WebCore::ScreenOrientationType::PortraitPrimary; +} + #if PLATFORM(COCOA) static WorkQueue& sharedFileQueueSingleton() { @@ -1105,6 +1121,10 @@ WebPageProxy::~WebPageProxy() ASSERT(webPageProxyMap().get(m_identifier) == this); webPageProxyMap().remove(m_identifier); + +#if PLATFORM(COCOA) + releaseInspectorDragPasteboard(); +#endif } void WebPageProxy::addAllMessageReceivers() @@ -1678,7 +1698,7 @@ void WebPageProxy::didAttachToRunningProcess() #if ENABLE(FULLSCREEN_API) ASSERT(!m_fullScreenManager); - m_fullScreenManager = WebFullScreenManagerProxy::create(*this, protect(protect(pageClient())->fullScreenManagerProxyClient()).get()); + m_fullScreenManager = WebFullScreenManagerProxy::create(*this, m_fullScreenManagerClientOverride ? *m_fullScreenManagerClientOverride : protect(protect(pageClient())->fullScreenManagerProxyClient()).get()); #endif #if ENABLE(VIDEO_PRESENTATION_MODE) ASSERT(!m_playbackSessionManager); @@ -1710,7 +1730,7 @@ void WebPageProxy::didAttachToRunningProcess() #endif #if !PLATFORM(IOS_FAMILY) - auto currentOrientation = WebCore::naturalScreenOrientationType(); + auto currentOrientation = m_deviceOrientationOverride ? toScreenOrientationType(*m_deviceOrientationOverride) : WebCore::naturalScreenOrientationType(); #else auto currentOrientation = toScreenOrientationType(m_deviceOrientation); #endif @@ -1850,6 +1870,7 @@ void WebPageProxy::initializeWebPage(const Site& site, WebCore::SandboxFlags eff if (preferences->siteIsolationEnabled()) browsingContextGroup->addPage(*this); process->send(Messages::WebProcess::CreateWebPage(m_webPageID, creationParameters(process, *protect(drawingArea()), m_mainFrame->frameID(), std::nullopt)), 0); + m_inspectorController->didInitializeWebPage(); #if ENABLE(WINDOW_PROXY_PROPERTY_ACCESS_NOTIFICATION) internals().frameLoadStateObserver = WebPageProxyFrameLoadStateObserver::create(); @@ -2171,6 +2192,21 @@ WebProcessProxy& WebPageProxy::ensureRunningProcess() return m_legacyMainFrameProcess; } +RefPtr WebPageProxy::loadRequestForInspector(WebCore::ResourceRequest&& request, WebFrameProxy* frame) +{ + if (!frame || frame == mainFrame()) + return loadRequest(WTF::move(request), WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow); + + auto navigation = m_navigationState->createLoadRequestNavigation(legacyMainFrameProcess().coreProcessIdentifier(), ResourceRequest(request), m_backForwardList->currentItem()); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.request = WTF::move(request); + loadParameters.shouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow; + loadParameters.shouldTreatAsContinuingLoad = ShouldTreatAsContinuingLoad::No; + m_legacyMainFrameProcess->send(Messages::WebPage::LoadRequestInFrameForInspector(WTF::move(loadParameters), frame->frameID()), m_webPageID); + return navigation; +} + RefPtr WebPageProxy::loadRequest(WebCore::ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, NavigationUpgradeToHTTPSBehavior navigationUpgradeToHTTPSBehavior, std::unique_ptr&& lastNavigationAction, API::Object* userData, bool isRequestFromClientOrUserInput) { if (m_isClosed) @@ -2296,11 +2332,29 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref&& proces navigation->setIsLoadedWithNavigationShared(true); protectedProcess->markProcessAsRecentlyUsed(); - if (!protectedProcess->isLaunching() || !url.protocolIsFile()) - protectedProcess->send(Messages::WebPage::LoadRequest(WTF::move(loadParameters)), webPageID); + + // Pause loading for new window navigation. + Function continuation = [ + weakThis = WeakPtr { protectedThis }, + weakProcess = WeakPtr { protectedProcess }, + loadParameters = WTF::move(loadParameters), + webPageID, + url + ]() mutable { + RefPtr innerProtectedProcess = weakProcess.get(); + RefPtr innerProtectedThis = weakThis.get(); + if (!innerProtectedProcess || !innerProtectedThis) + return; + if (!innerProtectedProcess->isLaunching() || !url.protocolIsFile()) + innerProtectedProcess->send(Messages::WebPage::LoadRequest(WTF::move(loadParameters)), webPageID); + else + innerProtectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTF::move(loadParameters), innerProtectedThis->internals().pageLoadState.resourceDirectoryURL(), innerProtectedThis->identifier(), true), webPageID); + innerProtectedProcess->startResponsivenessTimer(); + }; + if (protectedThis->m_inspectorController->shouldPauseLoadRequest()) + protectedThis->m_inspectorController->setContinueLoadingCallback(WTF::move(continuation)); else - protectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTF::move(loadParameters), protectedThis->pageLoadState().resourceDirectoryURL(), protectedThis->identifier(), true), webPageID); - protectedProcess->startResponsivenessTimer(); + continuation(); }); } @@ -2896,6 +2950,53 @@ RefPtr WebPageProxy::activeAutomationSession() const return m_configuration->processPool().automationSession(); } +void WebPageProxy::setAuthCredentialsForAutomation(std::optional&& credentials, std::optional&& origin) +{ + m_credentialsForAutomation = WTF::move(credentials); + m_authOriginForAutomation = WTF::move(origin); +} + +void WebPageProxy::setPermissionsForAutomation(const UncheckedKeyHashMap>& permissions) +{ + m_permissionsForAutomation = permissions; +} + +void WebPageProxy::setOrientationOverride(std::optional&& angle) +{ + m_deviceOrientationOverride = WTF::move(angle); + auto deviceOrientation = toScreenOrientationType(m_deviceOrientationOverride.value_or(0)); + if (m_screenOrientationManager) + m_screenOrientationManager->setCurrentOrientation(deviceOrientation); + m_legacyMainFrameProcess->send(Messages::WebPage::SetDeviceOrientation(m_deviceOrientationOverride.value_or(0)), webPageIDInMainFrameProcess()); +} + +std::optional WebPageProxy::permissionForAutomation(const String& origin, const String& permission) const +{ + auto permissions = m_permissionsForAutomation.find(origin); + if (permissions == m_permissionsForAutomation.end()) + permissions = m_permissionsForAutomation.find("*"_s); + if (permissions == m_permissionsForAutomation.end()) + return std::nullopt; + return permissions->value.contains(permission); +} + +void WebPageProxy::setActiveForAutomation(std::optional active) { + m_activeForAutomation = active; + OptionSet state; + state.add(ActivityState::IsFocused); + state.add(ActivityState::WindowIsActive); + state.add(ActivityState::IsVisible); + state.add(ActivityState::IsVisibleOrOccluded); + activityStateDidChange(state); +} + +void WebPageProxy::logToStderr(const String& str) +{ +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + fprintf(stderr, "RENDERER: %s\n", str.utf8().data()); +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END +} + void WebPageProxy::sendMessageToInspectorFrontend(const String& targetId, const String& message) { m_inspectorController->sendMessageToInspectorFrontend(targetId, message); @@ -3199,6 +3300,24 @@ void WebPageProxy::updateActivityState(OptionSet flagsToUpdate) bool wasVisible = isViewVisible(); RefPtr pageClient = this->pageClient(); internals().activityState.remove(flagsToUpdate); + + if (m_activeForAutomation) { + if (*m_activeForAutomation) { + if (flagsToUpdate & ActivityState::IsFocused) + internals().activityState.add(ActivityState::IsFocused); + if (flagsToUpdate & ActivityState::WindowIsActive) + internals().activityState.add(ActivityState::WindowIsActive); + if (flagsToUpdate & ActivityState::IsVisible) + internals().activityState.add(ActivityState::IsVisible); + if (flagsToUpdate & ActivityState::IsVisibleOrOccluded) + internals().activityState.add(ActivityState::IsVisibleOrOccluded); + } + flagsToUpdate.remove(ActivityState::IsFocused); + flagsToUpdate.remove(ActivityState::WindowIsActive); + flagsToUpdate.remove(ActivityState::IsVisible); + flagsToUpdate.remove(ActivityState::IsVisibleOrOccluded); + } + if (flagsToUpdate & ActivityState::IsFocused && pageClient->isViewFocused()) internals().activityState.add(ActivityState::IsFocused); if (flagsToUpdate & ActivityState::WindowIsActive && pageClient->isViewWindowActive()) @@ -3988,7 +4107,7 @@ void WebPageProxy::performDragOperation(DragData& dragData, const String& dragSt if (!hasRunningProcess()) return; -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) URL url { dragData.asURL() }; if (url.protocolIsFile()) protect(legacyMainFrameProcess())->assumeReadAccessToBaseURL(*this, url.string(), [] { }); @@ -4031,6 +4150,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag if (!hasRunningProcess()) return; + m_dragEventsQueued++; + auto completionHandler = [this, protectedThis = Ref { *this }, action, dragData] (std::optional dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect, std::optional remoteUserInputEventData) mutable { if (!m_pageClient) return; @@ -4042,7 +4163,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag dragData.setClientPosition(roundedIntPoint(remoteUserInputEventData->transformedPoint)); performDragControllerAction(action, dragData, remoteUserInputEventData->targetFrameID); }; -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) ASSERT(dragData.platformData()); sendWithAsyncReplyToProcessContainingFrame(frameID, Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags()), WTF::move(completionHandler)); #else @@ -4077,17 +4198,36 @@ void WebPageProxy::didPerformDragControllerAction(std::optionalpageClient()) pageClient->didPerformDragControllerAction(); + m_dragEventsQueued--; + if (m_dragEventsQueued == 0 && internals().mouseEventQueue.isEmpty()) + m_inspectorController->didProcessAllPendingMouseEvents(); } #if PLATFORM(GTK) || PLATFORM(WPE) void WebPageProxy::startDrag(SelectionData&& selectionData, OptionSet dragOperationMask, std::optional&& dragImageHandle, IntPoint&& dragImageHotspot) { + if (m_interceptDrags) { + m_dragSelectionData = WTF::move(selectionData); + m_dragSourceOperationMask = dragOperationMask; + } else { #if PLATFORM(GTK) - if (RefPtr pageClient = this->pageClient()) { - RefPtr dragImage = dragImageHandle ? ShareableBitmap::create(WTF::move(*dragImageHandle)) : nullptr; - pageClient->startDrag(WTF::move(selectionData), dragOperationMask, WTF::move(dragImage), WTF::move(dragImageHotspot)); + if (RefPtr pageClient = this->pageClient()) { + RefPtr dragImage = dragImageHandle ? ShareableBitmap::create(WTF::move(*dragImageHandle)) : nullptr; + pageClient->startDrag(WTF::move(selectionData), dragOperationMask, WTF::move(dragImage), WTF::move(dragImageHotspot)); + } +#endif } + didStartDrag(); +} #endif + +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) +void WebPageProxy::startDrag(WebCore::DragDataMap&& dragDataMap) +{ + if (m_interceptDrags) { + m_dragSelectionData = WTF::move(dragDataMap); + m_dragSourceOperationMask = WebCore::anyDragOperation(); + } didStartDrag(); } #endif @@ -4108,6 +4248,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo setDragCaretRect({ }); } +bool WebPageProxy::cancelDragIfNeeded() { + if (!m_dragSelectionData) + return false; + m_dragSelectionData = std::nullopt; +#if PLATFORM(COCOA) + releaseInspectorDragPasteboard(); +#endif + + dragEnded(m_lastMousePositionForDrag, IntPoint(), m_dragSourceOperationMask); + return true; +} + +#if !PLATFORM(COCOA) +void WebPageProxy::setInterceptDrags(bool shouldIntercept) { + m_interceptDrags = shouldIntercept; +} +#endif + void WebPageProxy::didStartDrag(const std::optional& targetFrameID) { if (!hasRunningProcess()) @@ -4116,6 +4274,25 @@ void WebPageProxy::didStartDrag(const std::optional& targetFram discardQueuedMouseEvents(); sendToProcessContainingFrame(targetFrameID, Messages::WebPage::DidStartDrag(targetFrameID)); + if (m_interceptDrags) { + { +#if PLATFORM(WIN) || PLATFORM(COCOA) + DragData dragData(*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask); +#else + DragData dragData(&*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask); +#endif + dragEntered(dragData); + } + + { +#if PLATFORM(WIN) || PLATFORM(COCOA) + DragData dragData(*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask); +#else + DragData dragData(&*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask); +#endif + dragUpdated(dragData); + } + } } void WebPageProxy::dragCancelled() @@ -4300,26 +4477,47 @@ void WebPageProxy::processNextQueuedMouseEvent() auto eventType = event->type(); startResponsivenessTimerForMouseEvent(*targetFrame, eventType); - std::optional> sandboxExtensions; + m_lastMousePositionForDrag = roundedIntPoint(event->position()); + if (!m_dragSelectionData) { + std::optional> sandboxExtensions; #if PLATFORM(MAC) - bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEventType::MouseMove && event->button() != WebMouseEventButton::None; - if (eventMayStartDrag) - sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, process->auditToken(), SandboxExtension::MachBootstrapOptions::EnableMachBootstrap); + bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEventType::MouseMove && event->button() != WebMouseEventButton::None; + if (eventMayStartDrag) + sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, process->auditToken(), SandboxExtension::MachBootstrapOptions::EnableMachBootstrap); #endif - auto eventWithCoalescedEvents = event; + auto eventWithCoalescedEvents = event; - if (event->type() == WebEventType::MouseMove) { - internals().coalescedMouseEvents.append(event); - eventWithCoalescedEvents->setCoalescedEvents(internals().coalescedMouseEvents); - } + if (event->type() == WebEventType::MouseMove) { + internals().coalescedMouseEvents.append(event); + eventWithCoalescedEvents->setCoalescedEvents(internals().coalescedMouseEvents); + } - LOG_WITH_STREAM(MouseHandling, stream << "UIProcess: sent mouse event " << eventType << " (queue size " << internals().mouseEventQueue.size() << ", coalesced events size " << internals().coalescedMouseEvents.size() << ")"); + LOG_WITH_STREAM(MouseHandling, stream << "UIProcess: sent mouse event " << eventType << " (queue size " << internals().mouseEventQueue.size() << ", coalesced events size " << internals().coalescedMouseEvents.size() << ")"); - sendMouseEvent(targetFrame->frameID(), eventWithCoalescedEvents, WTF::move(sandboxExtensions)); + sendMouseEvent(m_mainFrame->frameID(), eventWithCoalescedEvents, WTF::move(sandboxExtensions)); - internals().coalescedMouseEvents.clear(); + internals().coalescedMouseEvents.clear(); + } else { +#if PLATFORM(WIN) || PLATFORM(COCOA) + DragData dragData(*m_dragSelectionData, roundedIntPoint(event->position()), roundedIntPoint(event->globalPosition()), m_dragSourceOperationMask); +#else + DragData dragData(&*m_dragSelectionData, roundedIntPoint(event->position()), roundedIntPoint(event->globalPosition()), m_dragSourceOperationMask); +#endif + if (eventType == WebEventType::MouseMove) { + dragUpdated(dragData); + } else if (eventType == WebEventType::MouseUp) { + if (m_currentDragOperation && m_dragSourceOperationMask.containsAny(m_currentDragOperation.value())) { + SandboxExtension::Handle sandboxExtensionHandle; + Vector sandboxExtensionsForUpload; + performDragOperation(dragData, ""_s, WTF::move(sandboxExtensionHandle), WTF::move(sandboxExtensionsForUpload)); + } + m_dragSelectionData = std::nullopt; + dragEnded(roundedIntPoint(event->position()), roundedIntPoint(event->globalPosition()), m_dragSourceOperationMask); + } + didReceiveEventIPC(process->connection(), eventType, true, std::nullopt); + } } #if ENABLE(MAC_GESTURE_EVENTS) @@ -4586,6 +4784,8 @@ void WebPageProxy::wheelEventHandlingCompleted(bool wasHandled) if (RefPtr automationSession = m_configuration->processPool().automationSession()) automationSession->wheelEventsFlushedForPage(*this); + + m_inspectorController->didProcessAllPendingWheelEvents(); } void WebPageProxy::cacheWheelEventScrollingAccelerationCurve(const NativeWebWheelEvent& nativeWheelEvent) @@ -4729,7 +4929,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent) { -#if PLATFORM(COCOA) +#if PLATFORM(IOS_FAMILY) for (auto& touchPoint : touchStartEvent.touchPoints()) { auto location = touchPoint.locationInRootView(); auto update = [this, location](TrackingType& trackingType, EventTrackingRegions::EventType eventType) { @@ -5571,6 +5771,7 @@ Ref WebPageProxy::navigationOriginatingPage(const FrameInfoData& f void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, std::optional, Ref>>&& websitePoliciesAndProcess, Ref&& navigationAction, WillContinueLoadInNewProcess willContinueLoadInNewProcess, std::optional sandboxExtensionHandle, std::optional&& consoleMessage, CompletionHandler&& completionHandler) { + m_inspectorController->didReceivePolicyDecision(action, navigation ? std::optional { navigation->navigationID() } : std::nullopt); if (!hasRunningProcess()) return completionHandler(PolicyDecision { }); @@ -6671,6 +6872,7 @@ void WebPageProxy::viewScaleFactorDidChange(IPC::Connection& connection, double MESSAGE_CHECK_BASE(scaleFactorIsValid(scaleFactor), connection); if (!legacyMainFrameProcess().hasConnection(connection)) return; + m_viewScaleFactor = scaleFactor; forEachWebContentProcess([&] (auto& process, auto pageID) { if (&process == &legacyMainFrameProcess()) @@ -7524,6 +7726,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref&& process, We RefPtr protectedPageClient { pageClient() }; m_navigationState->didDestroyNavigation(process->coreProcessIdentifier(), navigationID); + m_inspectorController->didDestroyNavigation(navigationID); } void WebPageProxy::didStartProvisionalLoadForFrame(IPC::Connection& connection, FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, std::optional navigationID, URL&& url, URL&& unreachableURL, const UserData& userData, WallTime timestamp) @@ -7918,6 +8121,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref&& p m_failingProvisionalLoadURL = { }; m_allowsLoadingAlternateHTMLForFailingProvisionalLoadURL = true; + m_inspectorController->didFailProvisionalLoadForFrame(*navigationID, error); + // If the provisional page's load fails then we destroy the provisional page. if (m_provisionalPage && m_provisionalPage->mainFrame() == &frame && (willContinueLoading == WillContinueLoading::No)) m_provisionalPage = nullptr; @@ -9687,6 +9892,8 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w if (RefPtr page = originatingFrameInfo->page()) openerAppInitiatedState = page->lastNavigationWasAppInitiated(); + m_inspectorController->willCreateNewPage(windowFeatures, request.url()); + auto completionHandler = [ this, protectedThis = Ref { *this }, @@ -9774,6 +9981,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w configuration->setInitialReferrerPolicy(effectiveReferrerPolicy); configuration->setWindowFeatures(WTF::move(windowFeatures)); configuration->setOpenedMainFrameName(openedMainFrameName); + configuration->setOpenerPageForInspector(*this); if (RefPtr openerFrame = WebFrameProxy::webFrame(originatingFrameInfoData.frameID); navigationActionData.hasOpener && openerFrame) { configuration->setRelatedPage(*this); @@ -9809,6 +10017,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w void WebPageProxy::showPage() { m_uiClient->showPage(this); + m_inspectorController->didShowPage(); } bool WebPageProxy::hasOpenedPage() const @@ -9952,6 +10161,10 @@ void WebPageProxy::closePage() if (isClosed()) return; +#if ENABLE(CONTEXT_MENUS) + if (m_activeContextMenu) + m_activeContextMenu->hide(); +#endif WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:"); if (RefPtr pageClient = this->pageClient()) pageClient->clearAllEditCommands(); @@ -9991,6 +10204,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi auto showModal = [protectedThis = Ref { *this }](RefPtr&& frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler&& reply) mutable { protectedThis->runModalJavaScriptDialog(WTF::move(frame), WTF::move(frameInfo), WTF::move(message), [reply = WTF::move(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler&& completion) mutable { + if (page.m_inspectorDialogAgent) + page.m_inspectorDialogAgent->javascriptDialogOpening("alert"_s, message); page.m_uiClient->runJavaScriptAlert(page, WTF::move(message), frame, WTF::move(frameInfo), [reply = WTF::move(reply), completion = WTF::move(completion)]() mutable { reply(); completion(); @@ -10024,6 +10239,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this, message, std::nullopt); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("confirm"_s, message); auto showModal = [protectedThis = Ref { *this }](RefPtr&& frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler&& reply) mutable { protectedThis->runModalJavaScriptDialog(WTF::move(frame), WTF::move(frameInfo), WTF::move(message), [reply = WTF::move(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler&& completion) mutable { @@ -10060,6 +10277,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this, message, defaultValue); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("prompt"_s, message, defaultValue); auto showModal = [protectedThis = Ref { *this }](RefPtr&& frame, FrameInfoData&& frameInfo, String&& message, String&& defaultValue, CompletionHandler&& reply) mutable { protectedThis->runModalJavaScriptDialog(WTF::move(frame), WTF::move(frameInfo), WTF::move(message), [reply = WTF::move(reply), defaultValue = WTF::move(defaultValue)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, String&& message, CompletionHandler&& completion) mutable { @@ -10274,6 +10493,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(IPC::Connection& connection, Fram 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 and the tryClose timer. webProcess->stopResponsivenessTimer(); @@ -10963,6 +11184,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, } #if ENABLE(FULLSCREEN_API) +void WebPageProxy::setFullScreenManagerClientOverride(std::unique_ptr&& client) +{ + m_fullScreenManagerClientOverride = WTF::move(client); +} + WebFullScreenManagerProxy* WebPageProxy::fullScreenManager() { return m_fullScreenManager.get(); @@ -11092,6 +11318,17 @@ void WebPageProxy::requestDOMPasteAccess(IPC::Connection& connection, DOMPasteAc } } + if (isControlledByAutomation()) { + DOMPasteAccessResponse response = DOMPasteAccessResponse::DeniedForGesture; + if (permissionForAutomation(originIdentifier, "clipboard-read"_s).value_or(false)) { + response = DOMPasteAccessResponse::GrantedForGesture; + // Grant access to general pasteboard. + willPerformPasteCommand(DOMPasteAccessCategory::General, [] () { }, frameID); + } + completionHandler(response); + return; + } + protect(pageClient())->requestDOMPasteAccess(pasteAccessCategory, requiresInteraction, elementRect, originIdentifier, WTF::move(completionHandler)); } @@ -12074,6 +12311,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional event if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); didFinishProcessingAllPendingMouseEvents(); + if (m_dragEventsQueued == 0) + m_inspectorController->didProcessAllPendingMouseEvents(); } } @@ -12132,6 +12371,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional eventTy if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); didFinishProcessingAllPendingKeyEvents(); + m_inspectorController->didProcessAllPendingKeyboardEvents(); } } @@ -12576,7 +12816,10 @@ void WebPageProxy::dispatchProcessDidTerminate(WebProcessProxy& process, Process protect(browsingContextGroup())->processDidTerminate(*this, process); } - bool handledByClient = false; + bool handledByClient = m_inspectorController->pageCrashed(reason); + if (handledByClient) + return; + if (m_loaderClient) handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); else @@ -13251,6 +13494,9 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc parameters.allowPostingLegacySynchronousMessages = m_configuration->allowPostingLegacySynchronousMessages(); parameters.backgroundTextExtractionEnabled = m_configuration->backgroundTextExtractionEnabled(); + parameters.deviceOrientationOverride = m_deviceOrientationOverride; + parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseInInspectorWhenShown(); + #if ENABLE(APP_HIGHLIGHTS) parameters.appHighlightsVisible = appHighlightsVisibility() ? HighlightVisibility::Visible : HighlightVisibility::Hidden; #endif @@ -13429,8 +13675,47 @@ void WebPageProxy::allowGamepadAccess() #endif // ENABLE(GAMEPAD) +bool WebPageProxy::shouldSendAutomationCredentialsForProtectionSpace(const WebProtectionSpace& protectionSpace) +{ + if (m_authOriginForAutomation.has_value() && !m_authOriginForAutomation.value().isEmpty()) { + switch (protectionSpace.serverType()) { + case WebCore::ProtectionSpace::ServerType::HTTP: + if (m_authOriginForAutomation.value().protocol() != "http"_s) + return false; + break; + case WebCore::ProtectionSpace::ServerType::HTTPS: + if (m_authOriginForAutomation.value().protocol() != "https"_s) + return false; + break; + default: + return false; + } + + if (protectionSpace.host() != m_authOriginForAutomation.value().host()) + return false; + + if (protectionSpace.port() != m_authOriginForAutomation.value().port().value_or(0)) + return false; + } + return true; +} + void WebPageProxy::didReceiveAuthenticationChallengeProxy(Ref&& authenticationChallenge, NegotiatedLegacyTLS negotiatedLegacyTLS) { + if (authenticationChallenge->core().protectionSpace().authenticationScheme() == WebCore::ProtectionSpaceBaseAuthenticationScheme::ServerTrustEvaluationRequested && websiteDataStore().ignoreTLSErrors()) { + authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::UseCredential, WebCore::Credential("accept server trust"_s, ""_s, WebCore::CredentialPersistence::None)); + return; + } + + if (m_credentialsForAutomation.has_value()) { + if (m_credentialsForAutomation->isEmpty() || authenticationChallenge->core().previousFailureCount() || + !shouldSendAutomationCredentialsForProtectionSpace(*authenticationChallenge->protectionSpace())) { + authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::PerformDefaultHandling); + return; + } + authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::UseCredential, *m_credentialsForAutomation); + return; + } if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) { m_navigationClient->shouldAllowLegacyTLS(*this, authenticationChallenge.get(), [this, protectedThis = Ref { *this }, authenticationChallenge] (bool shouldAllowLegacyTLS) { if (shouldAllowLegacyTLS) @@ -13526,6 +13811,12 @@ void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connect request->deny(); }; + if (isControlledByAutomation()) { + auto securityOrigin = frameInfo.securityOrigin.securityOrigin(); + completionHandler(permissionForAutomation(securityOrigin->toString(), "geolocation"_s).value_or(false)); + return; + } + // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up // and make it one UIClient call that calls the completionHandler with false // if there is no delegate instead of returning the completionHandler @@ -13634,6 +13925,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi shouldChangeDeniedToPrompt = false; if (sessionID().isEphemeral()) { + auto permission = permissionForAutomation(clientOrigin.topOrigin.toString(), name); + if (permission.has_value()) { + completionHandler(permission.value() ? PermissionState::Granted : PermissionState::Denied); + return; + } + completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied); return; } @@ -13648,6 +13945,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi return; } + auto permission = permissionForAutomation(clientOrigin.topOrigin.toString(), name); + if (permission.has_value()) { + completionHandler(permission.value() ? PermissionState::Granted : PermissionState::Denied); + return; + } + if (!canAPISucceed) { completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied); return; diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h index c304883cbac2d21900bd09c7d7bc6e9701597e15..7083a7d4aba95ae552cbeb2b20440448a740ddca 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -28,6 +28,7 @@ // Including more headers here slows down build times a lot. // Use forward declarations and WebPageProxyInternals.h instead. #include "APIObject.h" +#include "APIWebsitePolicies.h" #include "MessageReceiver.h" #include #include @@ -40,6 +41,20 @@ #include #include #include +#include "InspectorDialogAgent.h" +#include "WebProtectionSpace.h" +#include +#include +#include "WebPageDiagnosticLoggingClient.h" +#include "WebPageInjectedBundleClient.h" +#include "WebPreferences.h" +#include "ViewSnapshotStore.h" + +OBJC_CLASS NSPasteboard; + +#if PLATFORM(GTK) || PLATFORM(WPE) +#include +#endif #if USE(COORDINATED_GRAPHICS) && HAVE(DISPLAY_LINK) #include "DisplayLinkObserverID.h" @@ -127,6 +142,7 @@ class DragData; class Exception; class FloatPoint; class FloatQuad; +typedef HashMap> DragDataMap; class FloatRect; class FloatSize; class FontAttributeChanges; @@ -839,6 +855,8 @@ public: RefPtr activeAutomationSession() const; + InspectorDialogAgent* inspectorDialogAgent() { return m_inspectorDialogAgent; } + void setInspectorDialogAgent(InspectorDialogAgent * dialogAgent) { m_inspectorDialogAgent = dialogAgent; } WebPageInspectorController& inspectorController() LIFETIME_BOUND { return m_inspectorController.get(); } #if PLATFORM(IOS_FAMILY) @@ -872,6 +890,7 @@ public: bool NODELETE hasSleepDisabler() const; #if ENABLE(FULLSCREEN_API) + void setFullScreenManagerClientOverride(std::unique_ptr&&); WebFullScreenManagerProxy* NODELETE fullScreenManager(); void setFullScreenClientForTesting(std::unique_ptr&&); @@ -940,6 +959,12 @@ public: void setPageLoadStateObserver(RefPtr&&); + void setAuthCredentialsForAutomation(std::optional&&, std::optional&&); + void setPermissionsForAutomation(const UncheckedKeyHashMap>&); + void setOrientationOverride(std::optional&& angle); + void setActiveForAutomation(std::optional active); + void logToStderr(const String& str); + void initializeWebPage(const WebCore::Site&, WebCore::SandboxFlags, WebCore::ReferrerPolicy); void setDrawingArea(RefPtr&&); @@ -971,6 +996,8 @@ public: RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::NavigationUpgradeToHTTPSBehavior); RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::NavigationUpgradeToHTTPSBehavior, std::unique_ptr&&, API::Object* userData = nullptr, bool isRequestFromClientOrUserInput = true); + RefPtr loadRequestForInspector(WebCore::ResourceRequest&&, WebFrameProxy*); + RefPtr loadFile(const String& fileURL, const String& resourceDirectoryURL, bool isAppInitiated = true, API::Object* userData = nullptr); RefPtr loadData(Ref&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData = nullptr); RefPtr loadData(Ref&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldOpenExternalURLsPolicy); @@ -1072,6 +1099,7 @@ public: void restoreSelectionInFocusedEditableElement(); PageClient* NODELETE pageClient() const; + bool hasPageClient() const { return !!m_pageClient; } void setViewNeedsDisplay(const WebCore::Region&); void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin, WebCore::ScrollIsAnimated, WebCore::InterruptScrollAnimation); @@ -1755,11 +1783,14 @@ public: void didStartDrag(const std::optional& = std::nullopt); void dragCancelled(); void setDragCaretRect(const WebCore::IntRect&); + void setInterceptDrags(bool shouldIntercept); + bool cancelDragIfNeeded(); #if PLATFORM(COCOA) void propagateDragAndDrop(DragEventForwardingData&&, const String&, WebCore::DragData&&); void startDrag(const WebCore::DragItem&, WebCore::ShareableBitmapHandle&& dragImageHandle, const std::optional&, const std::optional& = std::nullopt); void setPromisedDataForImage(IPC::Connection&, const String& pasteboardName, WebCore::SharedMemoryHandle&& imageHandle, const String& filename, const String& extension, const String& title, const String& url, const String& visibleURL, WebCore::SharedMemoryHandle&& archiveHandle, const String& originIdentifier); + void releaseInspectorDragPasteboard(); #endif #if PLATFORM(GTK) || PLATFORM(WPE) void startDrag(WebCore::SelectionData&&, OptionSet, std::optional&& dragImage, WebCore::IntPoint&& dragImageHotspot); @@ -1767,6 +1798,9 @@ public: #if ENABLE(MODEL_PROCESS) void modelDragEnded(const WebCore::NodeIdentifier); #endif +#if PLATFORM(WIN) + void startDrag(WebCore::DragDataMap&& dragDataMap); +#endif #endif void processDidBecomeUnresponsive(WebProcessProxy&); @@ -2030,6 +2064,7 @@ public: void setViewportSizeForCSSViewportUnits(const WebCore::FloatSize&); WebCore::FloatSize NODELETE viewportSizeForCSSViewportUnits() const; + bool shouldSendAutomationCredentialsForProtectionSpace(const WebProtectionSpace&); void didReceiveAuthenticationChallengeProxy(Ref&&, NegotiatedLegacyTLS); void negotiatedLegacyTLS(); void didNegotiateModernTLS(const URL&); @@ -2063,6 +2098,8 @@ public: // TODO Replace RefPtr with Expected for error reporting https://webkit.org/b/300271 RefPtr takeViewSnapshot(std::optional&&); RefPtr takeViewSnapshot(std::optional&&, ForceSoftwareCapturingViewportSnapshot); +#elif PLATFORM(WPE) + RefPtr takeViewSnapshot(std::optional&&) { return nullptr; } #endif void serializeAndWrapCryptoKey(IPC::Connection&, WebCore::CryptoKeyData&&, CompletionHandler>&&)>&&); @@ -3202,6 +3239,7 @@ private: RefPtr launchProcessForReload(); void requestNotificationPermission(const String& originString, CompletionHandler&&); + std::optional permissionForAutomation(const String& origin, const String& permission) const; #if ENABLE(WEB_ARCHIVE) bool NODELETE shouldAlwaysPromptForPermission(WebCore::PermissionName) const; @@ -3752,11 +3790,13 @@ private: String m_openedMainFrameName; RefPtr m_inspector; + InspectorDialogAgent* m_inspectorDialogAgent { nullptr }; Deque> m_pendingUndoRedo; uint32_t m_undoVersion { 0 }; #if ENABLE(FULLSCREEN_API) + std::unique_ptr m_fullScreenManagerClientOverride; RefPtr m_fullScreenManager; std::unique_ptr m_fullscreenClient; #endif @@ -3962,6 +4002,22 @@ private: std::optional m_currentDragOperation; bool m_currentDragIsOverFileInput { false }; unsigned m_currentDragNumberOfFilesToBeAccepted { 0 }; + WebCore::IntRect m_currentDragCaretRect; + WebCore::IntRect m_currentDragCaretEditableElementRect; + bool m_interceptDrags { false }; + OptionSet m_dragSourceOperationMask; + WebCore::IntPoint m_lastMousePositionForDrag; + int m_dragEventsQueued = 0; +#if PLATFORM(COCOA) + std::optional m_dragSelectionData; + String m_overrideDragPasteboardName; +#endif +#if PLATFORM(GTK) || PLATFORM(WPE) + std::optional m_dragSelectionData; +#endif +#if PLATFORM(WIN) + std::optional m_dragSelectionData; +#endif #endif bool m_mainFrameHasHorizontalScrollbar { false }; @@ -4132,6 +4188,11 @@ private: RefPtr messageBody; }; Vector m_pendingInjectedBundleMessages; + std::optional m_credentialsForAutomation; + std::optional m_authOriginForAutomation; + UncheckedKeyHashMap> m_permissionsForAutomation; + std::optional m_deviceOrientationOverride; + std::optional m_activeForAutomation; #if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION) RefPtr m_webDeviceOrientationUpdateProviderProxy; diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in index 155543cbd71b814586ab391daaa2efa2d11c22ea..b39e2260133f4aa7fe9580496bd4237b3fd52629 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.messages.in +++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in @@ -35,6 +35,7 @@ messages -> WebPageProxy { RunJavaScriptConfirm(WebCore::FrameIdentifier frameID, struct WebKit::FrameInfoData frameInfo, String message) -> (bool result) Synchronous RunJavaScriptPrompt(WebCore::FrameIdentifier frameID, struct WebKit::FrameInfoData frameInfo, String message, String defaultValue) -> (String result) Synchronous MouseDidMoveOverElement(struct WebKit::WebHitTestResultData hitTestResultData, OptionSet modifiers) + LogToStderr(String text) DidReceiveEventIPC(enum:uint32_t WebKit::WebEventType eventType, bool handled, struct std::optional remoteUserInputEventData) SetCursor(WebCore::Cursor cursor) @@ -365,6 +366,10 @@ messages -> WebPageProxy { StartDrag(WebCore::SelectionData selectionData, OptionSet dragOperationMask, std::optional dragImage, WebCore::IntPoint dragImageHotspot) #endif +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) + StartDrag(HashMap> dragDataMap) +#endif + #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT) WillReceiveEditDragSnapshot() DidReceiveEditDragSnapshot(RefPtr textIndicator) diff --git a/Source/WebKit/UIProcess/WebProcessCache.cpp b/Source/WebKit/UIProcess/WebProcessCache.cpp index 1593c4e060fb5fbf399c7d53cb7a81896b945556..c10a4b847f118012380a8d8f35984c81c841d697 100644 --- a/Source/WebKit/UIProcess/WebProcessCache.cpp +++ b/Source/WebKit/UIProcess/WebProcessCache.cpp @@ -125,6 +125,10 @@ bool WebProcessCache::canCacheProcess(WebProcessProxy& process) const return false; } + auto sessionID = process.websiteDataStore()->sessionID(); + if (sessionID.isEphemeral() && !process.processPool().hasPagesUsingWebsiteDataStore(*process.websiteDataStore())) + return false; + return true; } diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp index c9e5f1f1a7dfed59616429838f635538c34124f9..af87d3e1c00f0513658180c5fb397621c1b5505a 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.cpp +++ b/Source/WebKit/UIProcess/WebProcessPool.cpp @@ -423,10 +423,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr& void WebProcessPool::setOverrideLanguages(Vector&& languages) { - WebKit::setOverrideLanguages(WTF::move(languages)); + m_configuration->setOverrideLanguages(WTF::move(languages)); LOG_WITH_STREAM(Language, stream << "WebProcessPool is setting OverrideLanguages: " << languages); - sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(overrideLanguages())); + sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(m_configuration->overrideLanguages())); #if ENABLE(GPU_PROCESS) if (RefPtr gpuProcess = GPUProcessProxy::singletonIfCreated()) @@ -434,9 +434,10 @@ void WebProcessPool::setOverrideLanguages(Vector&& languages) #endif #if USE(SOUP) for (Ref networkProcess : NetworkProcessProxy::allNetworkProcesses()) - networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(overrideLanguages()), 0); + networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(m_configuration->overrideLanguages()), 0); #endif } +/* end playwright revert fb205fb */ void WebProcessPool::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled) { @@ -977,7 +978,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa #endif parameters.cacheModel = LegacyGlobalSettings::singleton().cacheModel(); - parameters.overrideLanguages = overrideLanguages(); + parameters.overrideLanguages = configuration().overrideLanguages(); /* playwright revert fb205fb */ LOG_WITH_STREAM(Language, stream << "WebProcessPool is initializing a new web process with overrideLanguages: " << parameters.overrideLanguages); parameters.urlSchemesRegisteredAsSecure = copyToVector(LegacyGlobalSettings::singleton().schemesToRegisterAsSecure()); @@ -1056,7 +1057,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa if (!injectedBundleInitializationUserData) injectedBundleInitializationUserData = m_injectedBundleInitializationUserData; parameters.initializationUserData = UserData(process.transformObjectsToHandles(injectedBundleInitializationUserData.get())); - + if (websiteDataStore) parameters.websiteDataStoreParameters = webProcessDataStoreParameters(process, *websiteDataStore); @@ -1150,14 +1151,14 @@ void WebProcessPool::processDidFinishLaunching(WebProcessProxy& process) // Sometimes the memorySampler gets initialized after process initialization has happened but before the process has finished launching // so check if it needs to be started here if (m_memorySamplerEnabled) { - SandboxExtension::Handle sampleLogSandboxHandle; + SandboxExtension::Handle sampleLogSandboxHandle; WallTime now = WallTime::now(); auto sampleLogFilePath = makeString("WebProcess"_s, now.secondsSinceEpoch().secondsAs(), "pid"_s, process.processID()); if (auto handleAndFilePath = SandboxExtension::createHandleForTemporaryFile(sampleLogFilePath, SandboxExtension::Type::ReadWrite)) { sampleLogSandboxHandle = WTF::move(handleAndFilePath->first); sampleLogFilePath = WTF::move(handleAndFilePath->second); } - + process.send(Messages::WebProcess::StartMemorySampler(WTF::move(sampleLogSandboxHandle), sampleLogFilePath, m_memorySamplerInterval), 0); } @@ -1327,6 +1328,12 @@ Ref WebProcessPool::createWebPage(PageClient& pageClient, Refpreferences())->forceEnhancedSecurity() || pageConfiguration->isEnhancedSecurityEnabled() || useEnhancedSecurityFallback) ? EnhancedSecurity::EnabledPolicy : EnhancedSecurity::Disabled; RefPtr relatedPage = pageConfiguration->relatedPage(); + + // Fix WPE/GTK crashes after 310806@main. upstream-status (pending). See issue https://github.com/microsoft/playwright-browsers/issues/2171 + // Ensure popups inherit the StorageBlockingPolicy of the parent so they stay compatible for same-process popup creation. + if (relatedPage) + pageConfiguration->preferences().setStorageBlockingPolicy(relatedPage->preferences().storageBlockingPolicy()); + bool siteIsolationEnabled = protect(pageConfiguration->preferences())->siteIsolationEnabled(); if (siteIsolationEnabled) protect(pageConfiguration->preferences())->setUseUIProcessForBackForwardItemLoading(true); @@ -1358,9 +1365,9 @@ Ref WebProcessPool::createWebPage(PageClient& pageClient, RefuserContentController(); - + ASSERT(process); - + process->setAllowTestOnlyIPC(pageConfiguration->allowTestOnlyIPC()); auto page = process->createWebPage(pageClient, WTF::move(pageConfiguration)); @@ -1745,18 +1752,18 @@ void WebProcessPool::setEnhancedAccessibility(bool flag) { sendToAllProcesses(Messages::WebProcess::SetEnhancedAccessibility(flag)); } - + void WebProcessPool::startMemorySampler(const double interval) -{ +{ // For new WebProcesses we will also want to start the Memory Sampler m_memorySamplerEnabled = true; m_memorySamplerInterval = interval; - + // For UIProcess #if ENABLE(MEMORY_SAMPLER) WebMemorySampler::singleton()->start(interval); #endif - + for (auto& process : m_processes) { if (!process->canSendMessage()) continue; @@ -1775,10 +1782,10 @@ void WebProcessPool::startMemorySampler(const double interval) } void WebProcessPool::stopMemorySampler() -{ +{ // For WebProcess m_memorySamplerEnabled = false; - + // For UIProcess #if ENABLE(MEMORY_SAMPLER) WebMemorySampler::singleton()->stop(); @@ -1830,7 +1837,7 @@ void WebProcessPool::setAutomationSession(RefPtr&& automat { if (RefPtr previousSession = m_automationSession) previousSession->setProcessPool(nullptr); - + m_automationSession = WTF::move(automationSession); #if ENABLE(REMOTE_INSPECTOR) @@ -2403,7 +2410,7 @@ std::tuple, RefPtr, ASCIILiteral> WebPr } auto reason = "Navigation is cross-site"_s; - + if (m_configuration->alwaysKeepAndReuseSwappedProcesses()) { LOG(ProcessSwapping, "(ProcessSwapping) Considering re-use of a previously cached process for domain %s", targetSite.domain().string().utf8().data()); @@ -2508,7 +2515,7 @@ void WebProcessPool::setDomainsWithUserInteraction(HashSet>&& domains, CompletionHandler&& completionHandler) -{ +{ Ref callbackAggregator = CallbackAggregator::create(WTF::move(completionHandler)); for (Ref process : borrow(this->processes()).get()) diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp index 1f2073d6c2900da0994e09c3edaee6c67298fade..b7a2870799a36988a051efe48c62f1d975156751 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.cpp +++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp @@ -215,6 +215,11 @@ Vector> WebProcessProxy::allProcesses() }); } +Vector> WebProcessProxy::allProcessesForInspector() +{ + return copyToVector(allProcesses()); +} + RefPtr WebProcessProxy::processForIdentifier(ProcessIdentifier identifier) { return allProcessMap().get(identifier); @@ -583,6 +588,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt if (WebKit::isInspectorProcessPool(processPool())) launchOptions.extraInitializationData.add("inspector-process"_s, "1"_s); + /* playwright revert fb205fb, 50f8fee */ + LOG(Language, "WebProcessProxy is getting launch options."); + auto overrideLanguages = m_processPool->configuration().overrideLanguages(); + if (overrideLanguages.isEmpty()) { + LOG(Language, "overrideLanguages() reports empty. Calling platformOverrideLanguages()"); + overrideLanguages = platformOverrideLanguages(); + } + if (!overrideLanguages.isEmpty()) { + StringBuilder languageString; + for (size_t i = 0; i < overrideLanguages.size(); ++i) { + if (i) + languageString.append(','); + languageString.append(overrideLanguages[i]); + } + LOG_WITH_STREAM(Language, stream << "Setting WebProcess's launch OverrideLanguages to " << languageString); + launchOptions.extraInitializationData.add("OverrideLanguages"_s, languageString.toString()); + } else + LOG(Language, "overrideLanguages is still empty. Not setting WebProcess's launch OverrideLanguages."); + /* end playwright revert fb205fb, 50f8fee */ + launchOptions.nonValidInjectedCodeAllowed = shouldAllowNonValidInjectedCode(); if (isPrewarmed()) diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h index 2bf85bf9e81bcca1c2c0830004a3cb6ef67708d0..4284c4b480346514dd3ba1ad4c01802ff151753b 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.h +++ b/Source/WebKit/UIProcess/WebProcessProxy.h @@ -208,6 +208,7 @@ public: static void forWebPagesWithOrigin(PAL::SessionID, const WebCore::SecurityOriginData&, NOESCAPE const Function&); static Vector> allowedFirstPartiesForCookies(); + static Vector> allProcessesForInspector(); void initializeWebProcess(WebProcessCreationParameters&&); diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp index 200b1f02601242c6e2240ab6bbb7d2b7e093e5b4..a95b9dfb1939a1fb2ae271e34a00d7201dfe06aa 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp @@ -315,15 +315,10 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W static Ref networkProcessForSession(PAL::SessionID sessionID) { -#if ((PLATFORM(GTK) || PLATFORM(WPE)) && !ENABLE(2022_GLIB_API)) - if (sessionID.isEphemeral()) { - // Reuse a previous persistent session network process for ephemeral sessions. - for (auto& dataStore : allDataStores().values()) { - if (dataStore->isPersistent()) - return dataStore->networkProcess(); - } - } +// Playwright begin +#if PLATFORM(GTK) || PLATFORM(WPE) return NetworkProcessProxy::create(); +// Playwright end #else UNUSED_PARAM(sessionID); return NetworkProcessProxy::ensureDefaultNetworkProcess(); @@ -2100,6 +2095,15 @@ void WebsiteDataStore::setCacheModelSynchronouslyForTesting(CacheModel cacheMode processPool->setCacheModelSynchronouslyForTesting(cacheModel); } +// Playwright begin +#if !USE(SOUP) +void WebsiteDataStore::setIgnoreTLSErrors(bool ignoreTLSErrors) +{ + m_ignoreTLSErrors = ignoreTLSErrors; +} +#endif +// Playwright begin + Vector WebsiteDataStore::parametersFromEachWebsiteDataStore() { return WTF::map(allDataStores(), [](auto& entry) { @@ -2524,6 +2528,12 @@ void WebsiteDataStore::lastPageLoadNetworkActivityCompletionCodeForTesting(WebCo protect(networkProcess())->lastPageLoadNetworkActivityCompletionCodeForTesting(m_sessionID, pageID, WTF::move(completionHandler)); } +void WebsiteDataStore::setDownloadForAutomation(std::optional allow, const String& downloadPath) +{ + m_allowDownloadForAutomation = allow; + m_downloadPathForAutomation = downloadPath; +} + #if ENABLE(APP_BOUND_DOMAINS) void WebsiteDataStore::hasAppBoundSession(CompletionHandler&& completionHandler) const { diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h index 8de753cfce229075cbfa2bc7a81eab3d2fe1fb03..f78922cea6147503e3bcbcf8869ebda2518ef62c 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h @@ -103,6 +103,7 @@ class DeviceIdHashSaltStorage; class DownloadProxy; class NetworkProcessProxy; class SOAuthorizationCoordinator; +class DownloadProxy; class VirtualAuthenticatorManager; class WebPageProxy; class WebProcessPool; @@ -118,6 +119,7 @@ enum class UnifiedOriginStorageLevel : uint8_t; enum class WebsiteDataFetchOption : uint8_t; enum class WebsiteDataType : uint32_t; +struct FrameInfoData; struct ITPThirdPartyData; struct NetworkProcessConnectionInfo; struct WebPushMessage; @@ -127,6 +129,14 @@ struct WebsiteDataStoreParameters; enum RemoveDataTaskCounterType { }; using RemoveDataTaskCounter = RefCounter; +class DownloadInstrumentation { +public: + virtual void downloadCreated(const String& uuid, const WebCore::ResourceRequest&, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr download) = 0; + virtual void downloadFilenameSuggested(const String& uuid, const String& suggestedFilename) = 0; + virtual void downloadFinished(const String& uuid, const String& error) = 0; + virtual ~DownloadInstrumentation() = default; +}; + class WebsiteDataStore : public API::ObjectImpl, public CanMakeWeakPtr { public: static WebsiteDataStore& defaultDataStore(); @@ -330,8 +340,10 @@ public: #if USE(SOUP) void setPersistentCredentialStorageEnabled(bool); bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled && isPersistent(); } +#endif void setIgnoreTLSErrors(bool); bool ignoreTLSErrors() const { return m_ignoreTLSErrors; } +#if USE(SOUP) void setNetworkProxySettings(WebCore::SoupNetworkProxySettings&&); const WebCore::SoupNetworkProxySettings& networkProxySettings() const LIFETIME_BOUND { return m_networkProxySettings; } void setCookiePersistentStorage(const String&, SoupCookiePersistentStorageType); @@ -422,6 +434,12 @@ public: static const String& defaultBaseDataDirectory(); #endif + void setDownloadForAutomation(std::optional allow, const String& downloadPath); + std::optional allowDownloadForAutomation() { return m_allowDownloadForAutomation; }; + String downloadPathForAutomation() { return m_downloadPathForAutomation; }; + void setDownloadInstrumentation(DownloadInstrumentation* instrumentation) { m_downloadInstrumentation = instrumentation; }; + DownloadInstrumentation* downloadInstrumentation() { return m_downloadInstrumentation; }; + void resetQuota(CompletionHandler&&); void resetStoragePersistedState(CompletionHandler&&); #if PLATFORM(IOS_FAMILY) @@ -642,7 +660,9 @@ private: #if USE(SOUP) bool m_persistentCredentialStorageEnabled { true }; - bool m_ignoreTLSErrors { true }; +#endif + bool m_ignoreTLSErrors { false }; +#if USE(SOUP) WebCore::SoupNetworkProxySettings m_networkProxySettings; String m_cookiePersistentStoragePath; SoupCookiePersistentStorageType m_cookiePersistentStorageType { SoupCookiePersistentStorageType::SQLite }; @@ -669,6 +689,10 @@ private: const RefPtr m_cookieStore; RefPtr m_networkProcess; + std::optional m_allowDownloadForAutomation; + String m_downloadPathForAutomation; + DownloadInstrumentation* m_downloadInstrumentation { nullptr }; + #if HAVE(APP_SSO) const std::unique_ptr m_soAuthorizationCoordinator; #endif diff --git a/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp b/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp index ad30e3705de228f71b2206a9da314451bbb2ca00..e46d97003021b06d17f66dd60f7ffcf2c69049cb 100644 --- a/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp +++ b/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp @@ -31,6 +31,7 @@ #if USE(CAIRO) #include "UpdateInfo.h" +#include "WebPageProxy.h" #include #include #include diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp index b79d617e64cbfb9d6e8faa811a0bf2890e75fe05..1b022935348aa29760e13c6ceaa2a97cca21977e 100644 --- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp +++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp @@ -114,6 +114,14 @@ void GeoclueGeolocationProvider::stop() } m_sourceType = LocationProviderSource::Unknown; + stopGeoclueClient(); + g_cancellable_cancel(m_cancellable_start.get()); + m_cancellable_start = nullptr; + g_cancellable_cancel(m_cancellable_setup.get()); + m_cancellable_setup = nullptr; + g_cancellable_cancel(m_cancellable_create.get()); + m_cancellable_create = nullptr; + destroyStateLater(); } void GeoclueGeolocationProvider::setEnableHighAccuracy(bool enabled) @@ -386,6 +394,8 @@ void GeoclueGeolocationProvider::createGeoclueClient(const char* clientPath) return; } + g_cancellable_cancel(m_cancellable_create.get()); + m_cancellable_create = adoptGRef(g_cancellable_new()); g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, nullptr, "org.freedesktop.GeoClue2", clientPath, "org.freedesktop.GeoClue2.Client", m_cancellable.get(), [](GObject*, GAsyncResult* result, gpointer userData) { diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h index 96bf77411e2e1f4c835f56b409dc179977d197ee..512af5ffce511711b502248e34e49e45e85dbc4e 100644 --- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h +++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h @@ -92,6 +92,9 @@ private: unsigned responseSignalId; } m_portal; GRefPtr m_cancellable; + GRefPtr m_cancellable_start; + GRefPtr m_cancellable_setup; + GRefPtr m_cancellable_create; UpdateNotifyFunction m_updateNotifyFunction; LocationProviderSource m_sourceType { LocationProviderSource::Unknown }; RunLoop::Timer m_destroyLaterTimer; diff --git a/Source/WebKit/UIProcess/glib/BrowserInspectorWebSocketServer.cpp b/Source/WebKit/UIProcess/glib/BrowserInspectorWebSocketServer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00483c4a7fdd24c93702c773687643ad045e7127 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/BrowserInspectorWebSocketServer.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2026 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BrowserInspectorWebSocketServer.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include "InspectorPlaywrightAgentClient.h" +#include "WebKit2Initialize.h" +#include +#include +#include +#include +#include + +namespace WebKit { + +namespace { + +class WebSocketFrontendChannel : public Inspector::FrontendChannel { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(WebSocketFrontendChannel); +public: + explicit WebSocketFrontendChannel(SoupWebsocketConnection* connection) + : m_connection(connection) + { + } + + ~WebSocketFrontendChannel() override = default; + +private: + ConnectionType connectionType() const override + { + return ConnectionType::Remote; + } + + void sendMessageToFrontend(const String& message) override + { + soup_websocket_connection_send_text(m_connection.get(), message.utf8().data()); + } + + GRefPtr m_connection; +}; + +class BrowserInspectorWebSocketServer { +public: + BrowserInspectorWebSocketServer(std::unique_ptr client, GRefPtr soupServer) + : m_playwrightAgent(std::move(client)) + , m_soupServer(std::move(soupServer)) + { + soup_server_add_websocket_handler(m_soupServer.get(), nullptr, nullptr, nullptr, &BrowserInspectorWebSocketServer::handleWebSocketConnection, this, nullptr); + } + +private: + static void handleWebSocketConnection(SoupServer*, SoupServerMessage*, const char* path, SoupWebsocketConnection* connection, gpointer userData) + { + auto server = static_cast(userData); + if (!server->handleWebSocketConnection(connection)) { + soup_websocket_connection_close(connection, SOUP_WEBSOCKET_CLOSE_POLICY_VIOLATION, "WebSocket connection already established"); + return; + } + + g_signal_connect(connection, "closed", G_CALLBACK(+[](SoupWebsocketConnection* connection, gpointer userData) { + auto server = static_cast(userData); + server->handleConnectionClosed(connection); + }), server); + + g_signal_connect(connection, "message", G_CALLBACK(+[] (SoupWebsocketConnection*, SoupWebsocketDataType messageType, GBytes* message, gpointer userData) { + auto server = static_cast(userData); + server->handleWebSocketMessage(messageType, message); + }), server); + } + + + void handleConnectionClosed(SoupWebsocketConnection* connection) + { + if (m_frontendChannel) { + m_playwrightAgent.disconnectFrontend(); + m_frontendChannel.reset(); + } + } + + void handleWebSocketMessage(SoupWebsocketDataType messageType, GBytes* message) + { + if (messageType != SOUP_WEBSOCKET_DATA_TEXT) { + fprintf(stderr, "WebSocket message received non-text message: %d\n", messageType); + return; + } + + gsize messageSize; + gconstpointer messageData = g_bytes_get_data(message, &messageSize); + String messageString = String::fromUTF8(std::span(static_cast(messageData), messageSize)); + fprintf(stderr, "WebSocket message received: %s\n", messageString.utf8().data()); + m_playwrightAgent.dispatchMessageFromFrontend(messageString); + } + + bool handleWebSocketConnection(SoupWebsocketConnection* connection) + { + if (m_frontendChannel) { + fprintf(stderr, "WebSocket connection already established\n"); + return false; + } + m_frontendChannel = std::make_unique(connection); + m_playwrightAgent.connectFrontend(*m_frontendChannel); + return true; + } + + InspectorPlaywrightAgent m_playwrightAgent; + GRefPtr m_soupServer; + std::unique_ptr m_frontendChannel; +}; + +} // namespace + +void initializeBrowserInspectorWebSocket(unsigned port, std::unique_ptr client) +{ + // Initialize main loop before creating inspector agent and starting the server. + WebKit::InitializeWebKit2(); + + GRefPtr soupServer = adoptGRef(soup_server_new("server-header", "WebKit-Playwright-WSS", nullptr)); + + GUniqueOutPtr error; + const SoupServerListenOptions options = static_cast(0); + if (!soup_server_listen_local(soupServer.get(), port, options, &error.outPtr())) { + fprintf(stderr, "Failed to start WebSocket server at port %u: %s\n", port, error->message); + return; + } + + int actualPort = port; + if (!actualPort) { + GSList* uris = soup_server_get_uris(soupServer.get()); + g_assert_nonnull(uris); + GUri* uri = static_cast(uris->data); + actualPort = g_uri_get_port(uri); + g_slist_free_full(uris, reinterpret_cast(g_uri_unref)); + } + if (actualPort == -1) { + fprintf(stderr, "Failed to start WebSocket server\n"); + return; + } + + static NeverDestroyed server(std::move(client), std::move(soupServer)); + + fprintf(stderr, "Playwright listening on ws://localhost:%d\n", actualPort); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/BrowserInspectorWebSocketServer.h b/Source/WebKit/UIProcess/glib/BrowserInspectorWebSocketServer.h new file mode 100644 index 0000000000000000000000000000000000000000..bd30f58d2d4afe85060eabf3bb178c20c0c73828 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/BrowserInspectorWebSocketServer.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2026 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +namespace WebKit { + +class InspectorPlaywrightAgentClient; + +void initializeBrowserInspectorWebSocket(unsigned port, std::unique_ptr client); + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) + diff --git a/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5a8e68580d8ba7ad968d1736220793711214988 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorPlaywrightAgentClientGLib.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include "PageClient.h" +#include "ViewSnapshotStore.h" +#include "WebAutomationSession.h" +#include "WebKitBrowserInspectorPrivate.h" +#include "WebKitWebContextPrivate.h" +#include "WebKitWebsiteDataManagerPrivate.h" +#include "WebKitWebViewPrivate.h" +#include "WebPageProxy.h" +#include +#include +#include +#include +#include + +namespace WebKit { + +static WebCore::SoupNetworkProxySettings parseRawProxySettings(const String& proxyServer, const char* const* ignoreHosts) +{ + WebCore::SoupNetworkProxySettings settings; + if (proxyServer.isEmpty()) + return settings; + + settings.mode = WebCore::SoupNetworkProxySettings::Mode::Custom; + settings.defaultProxyURL = proxyServer.utf8(); + settings.ignoreHosts.reset(g_strdupv(const_cast(ignoreHosts))); + return settings; +} + +static WebCore::SoupNetworkProxySettings parseProxySettings(const String& proxyServer, const String& proxyBypassList) +{ + Vector ignoreHosts; + if (!proxyBypassList.isEmpty()) { + Vector tokens = proxyBypassList.split(','); + Vector protectTokens; + for (String token : tokens) { + CString cstr = token.utf8(); + ignoreHosts.append(cstr.data()); + protectTokens.append(WTF::move(cstr)); + } + } + ignoreHosts.append(nullptr); + return parseRawProxySettings(proxyServer, ignoreHosts.mutableSpan().data()); +} + +InspectorPlaywrightAgentClientGlib::InspectorPlaywrightAgentClientGlib(const WTF::String& proxyURI, const char* const* ignoreHosts) + : m_proxySettings(parseRawProxySettings(proxyURI, ignoreHosts)) +{ +} + +RefPtr InspectorPlaywrightAgentClientGlib::createPage(WTF::String& error, const BrowserContext& browserContext) +{ + auto sessionID = browserContext.dataStore->sessionID(); + WebKitWebContext* context = m_idToContext.get(sessionID); + if (!context && !browserContext.dataStore->isPersistent()) { + ASSERT_NOT_REACHED(); + error = "Context with provided id not found"_s; + return nullptr; + } + + RefPtr page = webkitBrowserInspectorCreateNewPageInContext(context); + if (page == nullptr) { + error = "Failed to create new page in the context"_s; + return nullptr; + } + + if (context == nullptr && sessionID != page->sessionID()) { + ASSERT_NOT_REACHED(); + error = " Failed to create new page in default context"_s; + return nullptr; + } + + return page; +} + +void InspectorPlaywrightAgentClientGlib::closeBrowser() +{ + m_idToContext.clear(); + webkitBrowserInspectorQuitApplication(); + if (webkitWebContextExistingCount() > 1) + fprintf(stderr, "LEAK: %d contexts are still alive when closing browser\n", webkitWebContextExistingCount()); +} + +std::unique_ptr InspectorPlaywrightAgentClientGlib::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) +{ + GRefPtr context = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, nullptr))); + if (!context) { + error = "Failed to create GLib ephemeral context"_s; + return nullptr; + } + + GRefPtr networkSession = adoptGRef(webkit_network_session_new_ephemeral()); + webkit_web_context_set_network_session_for_automation(context.get(), networkSession.get()); + GRefPtr data_manager = webkit_network_session_get_website_data_manager(networkSession.get()); + + auto browserContext = std::make_unique(); + browserContext->processPool = &webkitWebContextGetProcessPool(context.get()); + browserContext->dataStore = &webkitWebsiteDataManagerGetDataStore(data_manager.get()); + PAL::SessionID sessionID = browserContext.get()->dataStore->sessionID(); + m_idToContext.set(sessionID, WTF::move(context)); + + if (!proxyServer.isEmpty()) { + WebCore::SoupNetworkProxySettings contextProxySettings = parseProxySettings(proxyServer, proxyBypassList); + browserContext->dataStore->setNetworkProxySettings(WTF::move(contextProxySettings)); + } else { + browserContext->dataStore->setNetworkProxySettings(WebCore::SoupNetworkProxySettings(m_proxySettings)); + } + return browserContext; +} + +void InspectorPlaywrightAgentClientGlib::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + m_idToContext.remove(sessionID); +} + +void InspectorPlaywrightAgentClientGlib::takePageScreenshot(WebPageProxy& page, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler&& completionHandler) +{ + page.callAfterNextPresentationUpdate([protectedPage = Ref{ page }, clip = WTF::move(clip), nominalResolution, completionHandler = WTF::move(completionHandler)]() mutable { +#if PLATFORM(GTK) || (PLATFORM(WPE) && USE(SKIA)) + RefPtr viewSnapshot = protectedPage->pageClient()->takeViewSnapshot(WTF::move(clip), nominalResolution); + if (viewSnapshot) { + std::optional data = WebAutomationSession::platformGetBase64EncodedPNGData(*viewSnapshot); + if (data) { + completionHandler(emptyString(), makeString("data:image/png;base64,"_s, *data)); + return; + } + } +#endif + completionHandler("Failed to take screenshot"_s, emptyString()); + }); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h new file mode 100644 index 0000000000000000000000000000000000000000..68bc7b610703bfcd3eff0d1c032092f6967fdc16 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include "WebKitWebContext.h" +#include +#include +#include +#include + +namespace WebKit { + +class InspectorPlaywrightAgentClientGlib : public InspectorPlaywrightAgentClient { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(InspectorPlaywrightAgentClientGlib); +public: + InspectorPlaywrightAgentClientGlib(const WTF::String& proxyURI, const char* const* ignoreHosts); + ~InspectorPlaywrightAgentClientGlib() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + void takePageScreenshot(WebPageProxy&, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler&& completionHandler) override; + +private: + WebKitWebContext* findContext(WTF::String& error, PAL::SessionID); + + UncheckedKeyHashMap> m_idToContext; + WebCore::SoupNetworkProxySettings m_proxySettings; +}; + +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp b/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp index e69e33b4359e24075e9054f014f5e5ab488b78c7..f395398acf790cc4fa80122dd4f59381ee03f5ac 100644 --- a/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp +++ b/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp @@ -127,6 +127,8 @@ static OptionSet availableInputDevices() return toAvailableInputDevices(gdk_seat_get_capabilities(seat)); } #endif + if (!WebCore::screenHasTouchDeviceOverride() || !WebCore::screenHasTouchDeviceOverride().value()) + return AvailableInputDevices::Mouse; #if ENABLE(TOUCH_EVENTS) return AvailableInputDevices::Touchscreen; #else diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp index 3dd2a77a24c59cb7fb1f01d3a74d75267a0f36bf..a020ccc929af8c9130ecca0125e5229ee8670e54 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.cpp @@ -864,4 +864,30 @@ RefPtr AcceleratedBackingStore::bufferAsNativeImageForTesting() con return m_committedBuffer->asNativeImageForTesting(); } +// Playwright begin +cairo_surface_t* AcceleratedBackingStore::surface() +{ + RefPtr buffer = m_committedBuffer.get(); + if (!buffer) + return nullptr; + + RefPtr surface = buffer->surface(); + if (!surface) + return nullptr; + + // The original surface is upside down, so we flip it to match orientation in other accelerated backing stores. + m_flippedSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, cairo_image_surface_get_width(surface.get()), cairo_image_surface_get_height(surface.get()))); + { + RefPtr cr = adoptRef(cairo_create(m_flippedSurface.get())); + cairo_matrix_t transform; + cairo_matrix_init(&transform, 1, 0, 0, -1, 0, cairo_image_surface_get_height(surface.get()) / buffer->deviceScaleFactor()); + cairo_transform(cr.get(), &transform); + cairo_set_source_surface(cr.get(), surface.get(), 0, 0); + cairo_paint(cr.get()); + } + cairo_surface_flush(m_flippedSurface.get()); + return m_flippedSurface.get(); +} +// Playwright end + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h index 2a15a005441f41bcc3a44ce666dabeab7ab671f2..cc802e0634696b9455cd650527886c35a14a3ea3 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h @@ -42,6 +42,7 @@ #include typedef void *EGLImage; +typedef struct _cairo_surface cairo_surface_t; #if USE(GBM) #include @@ -86,6 +87,7 @@ public: void unrealize(); RendererBufferDescription bufferDescription() const; RefPtr bufferAsNativeImageForTesting() const; + cairo_surface_t* surface(); private: explicit AcceleratedBackingStore(WebPageProxy&); @@ -268,6 +270,10 @@ private: RefPtr m_committedBuffer; Rects m_pendingDamageRects; HashMap> m_buffers; +// Playwright begin + RefPtr m_flippedSurface; +// Playwright end + }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f661f8c62dc091670f9474db037e7eee0ec37ce --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include "GtkUtilities.h" +#include + +namespace WebKit { + +void InspectorTargetProxy::platformActivate(String& error) const +{ + GtkWidget* parent = GTK_WIDGET(gtk_widget_get_root(m_page->viewWidget())); + if (WebCore::widgetIsOnscreenToplevelWindow(parent)) + gtk_window_present(GTK_WINDOW(parent)); + else + error = "The view is not on screen"_s; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/PageInspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/PageInspectorTargetProxyGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4412881043189ba16e7803eeab98bce574ab9267 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/PageInspectorTargetProxyGtk.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageInspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include "GtkUtilities.h" +#include + +namespace WebKit { + +void PageInspectorTargetProxy::platformActivate(String& error) const +{ + GtkWidget* parent = GTK_WIDGET(gtk_widget_get_root(m_page->viewWidget())); + if (widgetIsOnscreenToplevelWindow(parent)) + gtk_window_present(GTK_WINDOW(parent)); + else + error = "The view is not on screen"_s; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp index ed7f7adafd75f27ce458324b50144b28fb225565..3864cd324b918f97283a7d99dad753c84e3cb748 100644 --- a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp +++ b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp @@ -128,6 +128,8 @@ int SystemSettingsManagerProxy::xftDPI() const bool SystemSettingsManagerProxy::followFontSystemSettings() const { + // Align with WPE's behavior, which always returns false. + return false; #if USE(GTK4) #if GTK_CHECK_VERSION(4, 16, 0) GtkFontRendering fontRendering; diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5dd29805ed464ae7641b44193caca700fa9f8a1e --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DrawingAreaProxyCoordinatedGraphics.h" +#include "WebPageInspectorEmulationAgent.h" +#include "WebPageProxy.h" +#include "GtkUtilities.h" +#include "GtkVersioning.h" +#include +#include + +namespace WebKit { + +static bool windowHasManyTabs(GtkWidget* widget) { + for (GtkWidget* parent = gtk_widget_get_parent(widget); parent; parent = gtk_widget_get_parent(parent)) { + if (GTK_IS_NOTEBOOK(parent)) { + int pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(parent)); + return pages > 1; + } + } + return false; +} + +void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function&& callback) +{ + WebCore::IntSize viewSize(width, height); + GtkWidget* viewWidget = m_page.viewWidget(); + GtkWidget* window = gtk_widget_get_toplevel(viewWidget); + if (!window) { + callback("Cannot find parent window"_s); + return; + } + if (!GTK_IS_WINDOW(window)) { + callback("Toplevel is not a window"_s); + return; + } + GtkAllocation viewAllocation; + gtk_widget_get_allocation(viewWidget, &viewAllocation); + + // In GTK4 newly added tabs will have allocation size of 0x0, before the tab is shown. + // This is a Ctrl+click scenario. We invoke callback right away to not stall. + if (!viewAllocation.width && !viewAllocation.height && windowHasManyTabs(viewWidget)) { + callback(String()); + return; + } + + if (viewAllocation.width == width && viewAllocation.height == height) { + callback(String()); + return; + } + + GtkAllocation windowAllocation; + gtk_widget_get_allocation(window, &windowAllocation); + + width += windowAllocation.width - viewAllocation.width; + height += windowAllocation.height - viewAllocation.height; + + if (auto* drawingArea = static_cast(m_page.drawingArea())) { + bool didNotHaveInitialAllocation = (!windowAllocation.width && !windowAllocation.height) || + // Default size for new windows from browser_window_init in Tools/MiniBrowser/gtk/BrowserWindow.c. + (windowAllocation.width == 1024 && windowAllocation.height == 768); + // The callback can only be called if the page is still alive, so we can safely capture `this`. + drawingArea->waitForSizeUpdate([this, callback = WTF::move(callback), didNotHaveInitialAllocation, viewSize](const DrawingAreaProxyCoordinatedGraphics& drawingArea) mutable { + if (viewSize == drawingArea.size()) { + callback(String()); + return; + } + if (didNotHaveInitialAllocation) { + // In gtk4 resize request may be lost (overridden by default one) if the window is not yet + // allocated when we are changing the size, so we try again. + platformSetSize(viewSize.width(), viewSize.height(), WTF::move(callback)); + return; + } + callback("Failed to resize window"_s); + }); + } else { + callback("No backing store for window"_s); + } + // Depending on whether default size has been applied or not, we need to + // do one of the calls, so we just do both. + gtk_window_set_default_size(GTK_WINDOW(window), width, height); + gtk_widget_set_size_request(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 0000000000000000000000000000000000000000..40355b2c69d7a94e924451b5fe1c0b96ff025663 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "KeyBindingTranslator.h" +#include "NativeWebKeyboardEvent.h" +#include "WebPageProxy.h" +#include + +namespace WebKit { + +static unsigned modifiersToEventState(OptionSet modifiers) +{ + unsigned state = 0; + if (modifiers.contains(WebEventModifier::ControlKey)) + state |= GDK_CONTROL_MASK; + if (modifiers.contains(WebEventModifier::ShiftKey)) + state |= GDK_SHIFT_MASK; + if (modifiers.contains(WebEventModifier::AltKey)) + state |= GDK_META_MASK; + if (modifiers.contains(WebEventModifier::CapsLockKey)) + state |= GDK_LOCK_MASK; + return state; +} + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType 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, Vector& macCommands, MonotonicTime timestamp) +{ + Vector commands; + const guint keyVal = WebKeyboardEvent::gdkKeyCodeForWindowsKeyCode(windowsVirtualKeyCode); + if (keyVal) { + unsigned state = modifiersToEventState(modifiers); + commands = KeyBindingTranslator().commandsForKeyval(keyVal, state); + } + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp, + WTF::move(commands)); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp index baeb21c5cee36343d37fdf552cc36b26b2d5213e..d9efcdf56227966efafe53ba82c98673a47a9959 100644 --- a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp +++ b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp @@ -85,8 +85,10 @@ void WebPasteboardProxy::setPrimarySelectionOwner(WebFrameProxy* frame) if (m_primarySelectionOwner == frame) return; - if (m_primarySelectionOwner) - m_primarySelectionOwner->collapseSelection(); +// Playwright begin: do not change selection in another page! + // if (m_primarySelectionOwner) + // m_primarySelectionOwner->collapseSelection(); +// Playwright end m_primarySelectionOwner = frame; } diff --git a/Source/WebKit/UIProcess/mac/CorrectionPanel.h b/Source/WebKit/UIProcess/mac/CorrectionPanel.h index 8afb6132fad823816f84328a8b0a1a514f998bf7..54b582e60f4b16b3c7ba038c8c52466cce9875c4 100644 --- a/Source/WebKit/UIProcess/mac/CorrectionPanel.h +++ b/Source/WebKit/UIProcess/mac/CorrectionPanel.h @@ -33,11 +33,10 @@ #import #import #import +#import "WebViewImpl.h" namespace WebKit { -class WebViewImpl; - class CorrectionPanel { public: CorrectionPanel(); diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h new file mode 100644 index 0000000000000000000000000000000000000000..edb4581e8f1f484976a9081d37cb61e54b9b81c5 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "InspectorPlaywrightAgentClient.h" +#include + +OBJC_PROTOCOL(_WKBrowserInspectorDelegate); + +namespace WebKit { + +class InspectorPlaywrightAgentClientMac : public InspectorPlaywrightAgentClient { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(InspectorPlaywrightAgentClientMac); +public: + InspectorPlaywrightAgentClientMac(_WKBrowserInspectorDelegate* delegate, bool headless); + ~InspectorPlaywrightAgentClientMac() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + void takePageScreenshot(WebPageProxy&, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler&& completionHandler) override; + +private: + _WKBrowserInspectorDelegate* delegate_; + bool headless_; +}; + + +} // namespace API diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..409444cd94c22ff0662d786c95b04688ce2ea7b3 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "InspectorPlaywrightAgentClientMac.h" + +#import "PageClient.h" +#import "WebPageProxy.h" +#import "WebProcessPool.h" +#import "WebsiteDataStore.h" +#import "_WKBrowserInspector.h" +#import "WKProcessPoolInternal.h" +#import "WKWebsiteDataStoreInternal.h" +#import "WKWebView.h" +#import "WKWebViewInternal.h" +#import +#import +#import + +namespace WebKit { + +InspectorPlaywrightAgentClientMac::InspectorPlaywrightAgentClientMac(_WKBrowserInspectorDelegate* delegate, bool headless) + : delegate_(delegate), + headless_(headless) +{ +} + +RefPtr InspectorPlaywrightAgentClientMac::createPage(WTF::String& error, const BrowserContext& browserContext) +{ + auto sessionID = browserContext.dataStore->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].get(); +} + +void InspectorPlaywrightAgentClientMac::closeBrowser() +{ + [delegate_ quit]; +} + +std::unique_ptr InspectorPlaywrightAgentClientMac::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) +{ + _WKBrowserContext* wkBrowserContext = [[delegate_ createBrowserContext:proxyServer.createNSString().get() WithBypassList:proxyBypassList.createNSString().get()] autorelease]; + auto browserContext = std::make_unique(); + browserContext->processPool = &static_cast([[wkBrowserContext processPool] _apiObject]); + browserContext->dataStore = &static_cast([[wkBrowserContext dataStore] _apiObject]); + return browserContext; +} + +void InspectorPlaywrightAgentClientMac::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + [delegate_ deleteBrowserContext:sessionID.toUInt64()]; +} + +void InspectorPlaywrightAgentClientMac::takePageScreenshot(WebPageProxy& page, WebCore::IntRect&& clipRect, bool, CompletionHandler&& completionHandler) +{ + int toolbarHeight = headless_ ? 0 : 59; + page.callAfterNextPresentationUpdate([protectedPage = Ref { page }, toolbarHeight, clipRect = WTF::move(clipRect), completionHandler = WTF::move(completionHandler)]() mutable { + RetainPtr imageRef = protectedPage->pageClient()->takeSnapshotForAutomation(); + if (!imageRef) { + completionHandler("Could not take view snapshot"_s, emptyString()); + return; + } + + clipRect.move(0, toolbarHeight); + RetainPtr transformedImageRef = adoptCF(CGImageCreateWithImageInRect(imageRef.get(), clipRect)); + completionHandler(emptyString(), WebCore::encodeDataURL(transformedImageRef.get(), "image/png"_s, std::nullopt)); + }); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..8adbd51bfecad2a273117588bf50f8f741850d14 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "InspectorTargetProxy.h" +#import "WebPageProxy.h" + +#if PLATFORM(MAC) + +namespace WebKit { + +void InspectorTargetProxy::platformActivate(String& error) const +{ + NSWindow* window = m_page->platformWindow(); + [window makeKeyAndOrderFront:nil]; +} + +} // namespace WebKit + +#endif diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.h b/Source/WebKit/UIProcess/mac/PageClientImplMac.h index a621f334b3f1a1d2ea1c4bba63d73fa0757fe2bd..3d6b14a3a2a8a6f42f8da31b535e76715b6fe20a 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.h +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.h @@ -31,9 +31,11 @@ #include "PageClientImplCocoa.h" #include "WebFullScreenManagerProxy.h" #include +#include #include #include #include +#include @class WKEditorUndoTarget; @class WKView; @@ -61,6 +63,8 @@ class PageClientImpl final : public PageClientImplCocoa WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(PageClientImpl); #endif public: + static void setHeadless(bool headless); + PageClientImpl(NSView *, WKWebView *); virtual ~PageClientImpl(); @@ -177,6 +181,9 @@ private: void updateAcceleratedCompositingMode(const LayerTreeContext&) override; void didFirstLayerFlush(const LayerTreeContext&) override; +// Paywright begin + RetainPtr takeSnapshotForAutomation() override; +// Paywright end RefPtr takeViewSnapshot(std::optional&&) override; RefPtr takeViewSnapshot(std::optional&&, ForceSoftwareCapturingViewportSnapshot) override; void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override; @@ -233,6 +240,10 @@ private: void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame, CompletionHandler&&) override; #endif +#if ENABLE(TOUCH_EVENTS) + void doneWithTouchEvent(const WebTouchEvent&, bool wasEventHandled) override; +#endif + void navigationGestureDidBegin() override; void navigationGestureWillEnd(bool willNavigate, WebBackForwardListItem&) override; void navigationGestureDidEnd(bool willNavigate, WebBackForwardListItem&) override; diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm index 23ae9a262af01284fadc90a18436b77af5752c24..730af4dee8db0f9a5dcf34623d499f4619e0d83d 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm @@ -113,6 +113,13 @@ using namespace WebCore; WTF_MAKE_TZONE_ALLOCATED_IMPL(PageClientImpl); +static bool _headless = false; + +// static +void PageClientImpl::setHeadless(bool headless) { + _headless = headless; +} + PageClientImpl::PageClientImpl(NSView *view, WKWebView *webView) : PageClientImplCocoa(webView) , m_view(view) @@ -172,6 +179,9 @@ NSWindow *PageClientImpl::activeWindow() const bool PageClientImpl::isViewWindowActive() { + if (_headless) + return true; + ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer)); RetainPtr activeViewWindow = activeWindow(); return activeViewWindow.get().isKeyWindow || (activeViewWindow && [NSApp keyWindow] == activeViewWindow.get()); @@ -179,6 +189,9 @@ bool PageClientImpl::isViewWindowActive() bool PageClientImpl::isViewFocused() { + if (_headless) + return true; + // FIXME: This is called from the WebPageProxy constructor before we have a WebViewImpl. // Once WebViewImpl and PageClient merge, this won't be a problem. if (CheckedPtr impl = m_impl.get()) @@ -202,6 +215,9 @@ void PageClientImpl::makeFirstResponder() bool PageClientImpl::isViewVisible(NSView *view, NSWindow *viewWindow) const { + if (_headless) + return true; + auto windowIsOccluded = [&]()->bool { return m_impl && m_impl->windowOcclusionDetectionEnabled() && (viewWindow.occlusionState & NSWindowOcclusionStateVisible) != NSWindowOcclusionStateVisible; }; @@ -300,7 +316,8 @@ void PageClientImpl::didRelaunchProcess() void PageClientImpl::preferencesDidChange() { - protect(m_impl)->preferencesDidChange(); + if (CheckedPtr impl = m_impl.get()) + impl->preferencesDidChange(); } void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip) @@ -533,6 +550,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { + if (!event.nativeEvent()) + return; protect(m_impl)->doneWithKeyEvent(RetainPtr { event.nativeEvent() }.get(), eventWasHandled); } @@ -552,6 +571,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl RefPtr PageClientImpl::createPopupMenuProxy(WebPageProxy& page) { + if (_headless) + return nullptr; return WebPopupMenuProxyMac::create(m_view.get().get(), protect(page.popupMenuClient())); } @@ -677,6 +698,12 @@ CALayer *PageClientImpl::footerBannerLayer() const return m_impl->footerBannerLayer(); } +// Paywright begin +RetainPtr PageClientImpl::takeSnapshotForAutomation() { + return m_impl->takeSnapshotForAutomation(); +} +// Paywright begin + RefPtr PageClientImpl::takeViewSnapshot(std::optional&&) { return protect(m_impl)->takeViewSnapshot(); @@ -898,6 +925,13 @@ void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntR #endif // ENABLE(FULLSCREEN_API) +#if ENABLE(TOUCH_EVENTS) +void PageClientImpl::doneWithTouchEvent(const WebTouchEvent& event, bool wasEventHandled) +{ + notImplemented(); +} +#endif // ENABLE(TOUCH_EVENTS) + void PageClientImpl::navigationGestureDidBegin() { protect(m_impl)->dismissContentRelativeChildWindowsWithAnimation(true); @@ -1078,6 +1112,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event) { + // Simulated event. + if (!event.nativeEvent()) + return false; return protect(m_impl)->windowIsFrontWindowUnderMouse(RetainPtr { event.nativeEvent() }.get()); } diff --git a/Source/WebKit/UIProcess/mac/PageInspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/PageInspectorTargetProxyMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..cdeaad88feeb7c0d0d6ec485c73928030741904a --- /dev/null +++ b/Source/WebKit/UIProcess/mac/PageInspectorTargetProxyMac.mm @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "PageInspectorTargetProxy.h" +#import "WebPageProxy.h" + +#if PLATFORM(MAC) + +namespace WebKit { + +void PageInspectorTargetProxy::platformActivate(String& error) const +{ + NSWindow* window = m_page->platformWindow(); + [window makeKeyAndOrderFront:nil]; +} + +} // namespace WebKit + +#endif diff --git a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in index f46895285dbc84c624537a194814c18f771a0c08..29ef9e5afa13b8d2b47b7f2dd4ce37846b61c35f 100644 --- a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in +++ b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in @@ -20,6 +20,7 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#if ENABLE(SEC_ITEM_SHIM) [ DispatchedFrom=Networking, DispatchedTo=UI, @@ -27,9 +28,8 @@ ] messages -> SecItemShimProxy { -#if ENABLE(SEC_ITEM_SHIM) SecItemRequestSync(WebKit::SecItemRequestData request) -> (std::optional response) Synchronous SecItemRequest(WebKit::SecItemRequestData request) -> (std::optional response) -#endif } +#endif diff --git a/Source/WebKit/UIProcess/mac/WKTextAnimationManagerMac.mm b/Source/WebKit/UIProcess/mac/WKTextAnimationManagerMac.mm index 6cfc616d5492bd12f7516ff2d6a67e77705f42b0..fd2e2a98b1db2c469a7f18fb2b7cbfbdc8ea3a8b 100644 --- a/Source/WebKit/UIProcess/mac/WKTextAnimationManagerMac.mm +++ b/Source/WebKit/UIProcess/mac/WKTextAnimationManagerMac.mm @@ -35,6 +35,7 @@ #import "WebViewImpl.h" #import #import +#import #import @interface WKTextAnimationTypeEffectData : NSObject diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h index d063c571127353548110ca306fabf076cae2c966..015f0932a0b9da6888365eb072f7c6d5d048b9bb 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h @@ -87,6 +87,7 @@ private: void show() override; void showContextMenuWithItems(Vector>&&) override; void useContextMenuItems(Vector>&&) override; + void hide() override; bool showAfterPostProcessingContextData(); diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm index 960f2529fe031dd6799c5d0d16ebf899089620e6..0a9e4684a6a149cffc4addc64b3b79bffc07211b 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm @@ -543,6 +543,12 @@ RetainPtr WebContextMenuProxyMac::createShareMenuItem(ShareMenuItemT } #endif +void WebContextMenuProxyMac::hide() +{ + if (m_menu) + [m_menu cancelTracking]; +} + void WebContextMenuProxyMac::show() { #if ENABLE(SERVICE_CONTROLS) diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..6113f4cd60a5d72b8ead61176cb43200803478ed --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "WebPageInspectorEmulationAgent.h" + +#import "WebPageProxy.h" + +namespace WebKit { + +void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function&& callback) +{ + 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]; + callback(String()); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..e6d3a8764ef084790a4ca4e9891b09ddcbb70781 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "NativeWebMouseEvent.h" +#import "NetworkProcessMessages.h" +#import "NetworkProcessProxy.h" +#import "WebPageInspectorInputAgent.h" +#import "WebPageProxy.h" +#import "WebPageProxyMessages.h" +#import "WebsiteDataStore.h" +#import +#import +#import "NativeWebKeyboardEvent.h" + +namespace WebKit { + +using namespace WebCore; + +void WebPageInspectorInputAgent::platformDispatchMouseEvent(const String& type, int x, int y, std::optional&& optionalModifiers, const String& button, std::optional&& optionalClickCount, unsigned short buttons) { + IntPoint locationInWindow(x, y); + + NSEventModifierFlags modifiers = 0; + if (optionalModifiers) { + int inputModifiers = *optionalModifiers; + if (inputModifiers & 1) + modifiers |= NSEventModifierFlagShift; + if (inputModifiers & 2) + modifiers |= NSEventModifierFlagControl; + if (inputModifiers & 4) + modifiers |= NSEventModifierFlagOption; + if (inputModifiers & 8) + modifiers |= NSEventModifierFlagCommand; + } + int clickCount = optionalClickCount ? *optionalClickCount : 0; + + NSTimeInterval timestamp = [NSDate timeIntervalSinceReferenceDate]; + NSWindow *window = m_page.platformWindow(); + NSInteger windowNumber = window.windowNumber; + + NSEventType downEventType; + NSEventType dragEventType; + NSEventType upEventType; + + if (!button || button == "none"_s) { + downEventType = NSEventTypeMouseMoved; + dragEventType = NSEventTypeMouseMoved; + upEventType = NSEventTypeMouseMoved; + } else if (button == "left"_s) { + downEventType = NSEventTypeLeftMouseDown; + dragEventType = NSEventTypeLeftMouseDragged; + upEventType = NSEventTypeLeftMouseUp; + } else if (button == "middle"_s) { + downEventType = NSEventTypeOtherMouseDown; + dragEventType = NSEventTypeOtherMouseDragged; + upEventType = NSEventTypeOtherMouseUp; + } else if (button == "right"_s) { + downEventType = NSEventTypeRightMouseDown; + dragEventType = NSEventTypeRightMouseDragged; + upEventType = NSEventTypeRightMouseUp; + } else { + return; + } + + NSInteger eventNumber = 0; + + NSEvent* event; + if (type == "move"_s) { + event = [NSEvent mouseEventWithType:dragEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:0.0f]; + } else if (type == "down"_s) { + event = [NSEvent mouseEventWithType:downEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:WebCore::ForceAtClick]; + } else if (type == "up"_s) { + event = [NSEvent mouseEventWithType:upEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:0.0f]; + } else { + return; + } + + if (button == "middle"_s) { + CGEventRef cgEvent = [event CGEvent]; + CGEventSetIntegerValueField(cgEvent, kCGMouseEventButtonNumber, kCGMouseButtonCenter); + event = [NSEvent eventWithCGEvent:cgEvent]; + } + + NativeWebMouseEvent nativeEvent(event, nil, [window contentView], WebKit::WebEventInputSource::UserDriven); + nativeEvent.playwrightSetButtons(buttons); + m_page.handleMouseEvent(nativeEvent); +} + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType 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, Vector& commands, MonotonicTime timestamp) +{ + Vector macCommands; + for (const String& command : commands) { + m_page.registerKeypressCommandName(command); + macCommands.append(WebCore::KeypressCommand(command)); + } + if (text.length() > 0 && macCommands.size() == 0) + macCommands.append(WebCore::KeypressCommand("insertText:"_s, text)); + if (!macCommands.isEmpty()) + if (auto replyID = m_page.grantAccessToCurrentPasteboardData(NSPasteboardNameGeneral, [] () { })) + protect(m_page.websiteDataStore().networkProcess())->connection().waitForAsyncReplyAndDispatchImmediately(*replyID, 100_ms); + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp, + WTF::move(macCommands)); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.h b/Source/WebKit/UIProcess/mac/WebViewImpl.h index 00f01a73b212bdc22a7da18c3ce1441735cec72f..ec0714a8b65d0323de74d09d039373059708f528 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.h +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.h @@ -39,6 +39,7 @@ #include "WKLayoutMode.h" #include "WebMouseEvent.h" #include +#include #include #include #include @@ -615,6 +616,9 @@ public: void provideDataForPasteboard(NSPasteboard *, NSString *type); NSArray *namesOfPromisedFilesDroppedAtDestination(NSURL *dropDestination); +// Paywright begin + RetainPtr takeSnapshotForAutomation(); +// Paywright end RefPtr takeViewSnapshot(); RefPtr takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot); void saveBackForwardSnapshotForCurrentItem(); diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.mm b/Source/WebKit/UIProcess/mac/WebViewImpl.mm index 3899b38da4dab24c275d8ac5e17e5ad39c54501a..e473f92023b209565c7e558503d25b847947e918 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.mm +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.mm @@ -2604,6 +2604,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace() if (!m_colorSpace) m_colorSpace = [NSColorSpace sRGBColorSpace]; } + // Playwright begin + // window.colorSpace is sometimes null on popup windows in headless mode + if (!m_colorSpace) + return WebCore::DestinationColorSpace::SRGB(); + // Playwright end ASSERT(m_colorSpace); return WebCore::DestinationColorSpace { [m_colorSpace CGColorSpace] }; @@ -5059,6 +5064,17 @@ static RetainPtr takeWindowSnapshot(CGSWindowID windowID, bool captu return WebCore::cgWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions); } +// Paywright begin +RetainPtr WebViewImpl::takeSnapshotForAutomation() { + NSWindow *window = [m_view window]; + + CGSWindowID windowID = (CGSWindowID)window.windowNumber; + if (!windowID || !window.isVisible) + return nullptr; + return takeWindowSnapshot(windowID, true, ForceSoftwareCapturingViewportSnapshot::Yes); +} +// Paywright end + RefPtr WebViewImpl::takeViewSnapshot() { return takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot::No); diff --git a/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.cpp b/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.cpp index 2a5f7ebbd13e88c0141fb1a1b5212bafcedff04d..77bf2c0a74f5263dc85281b3eb261875b13ca332 100644 --- a/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.cpp +++ b/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.cpp @@ -35,6 +35,7 @@ #include "MessageSenderInlines.h" #include "UpdateInfo.h" #include "WebPageProxy.h" +#include "WebPageInspectorController.h" #include namespace WebKit { @@ -116,6 +117,19 @@ void DrawingAreaProxyWC::discardBackingStore() m_backingStore = std::nullopt; } +void DrawingAreaProxyWC::captureFrame() +{ + if (!m_backingStore) + return; + auto surface = m_backingStore->surface(); + if (!surface) + return; + auto image = surface->makeImageSnapshot(); + if (!image) + return; + page()->inspectorController().didPaint(WTF::move(image)); +} + } // namespace WebKit #endif // USE(GRAPHICS_LAYER_WC) diff --git a/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.h b/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.h index 5ede972f4b6efe213ccdd866ef77594acfcbf162..67f66b7c685eea3478b6386e1ec449d94dfff17f 100644 --- a/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.h +++ b/Source/WebKit/UIProcess/wc/DrawingAreaProxyWC.h @@ -50,6 +50,8 @@ public: void paint(PlatformPaintContextPtr, const WebCore::IntRect&, WebCore::Region& unpaintedRegion); + void captureFrame(); + private: DrawingAreaProxyWC(WebPageProxy&, WebProcessProxy&); diff --git a/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01d4c66fc3c471ecf58a66e18512fc78d4465d8b --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorPlaywrightAgentClientWin.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "APIPageConfiguration.h" +#include "APIProcessPoolConfiguration.h" +#include "InspectorPlaywrightAgent.h" +#include "WebPageProxy.h" +#include "WebsiteDataStore.h" +#include "WebPreferences.h" +#include "WebProcessPool.h" +#include "WebView.h" +#include "WKAPICast.h" +#include +#include +#include +#include +#include + +namespace WebKit { + +InspectorPlaywrightAgentClientWin::InspectorPlaywrightAgentClientWin(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit) + : m_configureDataStore(configureDataStore) + , m_createPage(createPage) + , m_quit(quit) +{ +} + +RefPtr InspectorPlaywrightAgentClientWin::createPage(WTF::String& error, const BrowserContext& context) +{ + auto conf = API::PageConfiguration::create(); + conf->setProcessPool(context.processPool.get()); + conf->setWebsiteDataStore(context.dataStore.get()); + return toImpl(m_createPage(toAPI(&conf.get()))); +} + +void InspectorPlaywrightAgentClientWin::closeBrowser() +{ + m_quit(); +} + +std::unique_ptr InspectorPlaywrightAgentClientWin::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) +{ + auto config = API::ProcessPoolConfiguration::create(); + auto browserContext = std::make_unique(); + browserContext->processPool = WebKit::WebProcessPool::create(config); + browserContext->dataStore = WebKit::WebsiteDataStore::createNonPersistent(); + m_configureDataStore(toAPI(browserContext->dataStore.get())); + if (!proxyServer.isEmpty()) { + URL proxyURL = URL(URL(), proxyServer); + WebCore::CurlProxySettings settings(WTF::move(proxyURL), String(proxyBypassList)); + browserContext->dataStore->setNetworkProxySettings(WTF::move(settings)); + } + return browserContext; +} + +void InspectorPlaywrightAgentClientWin::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h new file mode 100644 index 0000000000000000000000000000000000000000..18be1f2e544e3069df48cdd1e55ad8536f57802a --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include +#include + +typedef void (*ConfigureDataStoreCallback)(WKWebsiteDataStoreRef dataStore); +typedef WKPageRef (*CreatePageCallback)(WKPageConfigurationRef configuration); +typedef void (*QuitCallback)(); + +namespace WebKit { + +class InspectorPlaywrightAgentClientWin : public InspectorPlaywrightAgentClient { + WTF_DEPRECATED_MAKE_FAST_ALLOCATED(InspectorPlaywrightAgentClientWin); +public: + InspectorPlaywrightAgentClientWin(ConfigureDataStoreCallback, CreatePageCallback, QuitCallback); + ~InspectorPlaywrightAgentClientWin() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + ConfigureDataStoreCallback m_configureDataStore; + CreatePageCallback m_createPage; + QuitCallback m_quit; +}; + +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/win/InspectorTargetProxyWin.cpp b/Source/WebKit/UIProcess/win/InspectorTargetProxyWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..135a60361fa8fbf907382625e7c8dd4ea64ceb94 --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorTargetProxyWin.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorTargetProxy.h" +#include "WebPageProxy.h" + +namespace WebKit { + +void InspectorTargetProxy::platformActivate(String& error) const +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/PageInspectorTargetProxyWin.cpp b/Source/WebKit/UIProcess/win/PageInspectorTargetProxyWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6469d95bbe7abe4c2dd77848e17462467eda78d0 --- /dev/null +++ b/Source/WebKit/UIProcess/win/PageInspectorTargetProxyWin.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageInspectorTargetProxy.h" +#include "WebPageProxy.h" + +namespace WebKit { + +void PageInspectorTargetProxy::platformActivate(String& error) const +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp index 8017b507ce2f0d67922035b1d41b9898f5dddb8c..7e40f52a0e878aeaa0aa38199b432377a6dc4cfd 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp +++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp @@ -114,5 +114,11 @@ WebContextMenuProxyWin::~WebContextMenuProxyWin() ::DestroyMenu(m_menu); } +void WebContextMenuProxyWin::hide() +{ + if (m_menu) + ::EndMenu(); +} + } // namespace WebKit #endif // ENABLE(CONTEXT_MENUS) diff --git a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h index ad633673cb4f1c5979aee23c0c3fd32f1b7421a2..2204867f7d2d6c756f17c968c1767ee667aca8c7 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h +++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h @@ -47,6 +47,7 @@ public: private: WebContextMenuProxyWin(WebPageProxy&, FrameInfoData&&, ContextMenuContextData&&, const UserData&); void showContextMenuWithItems(Vector>&&) override; + void hide() override; HMENU m_menu; }; diff --git a/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..df55ee613ec085cb85ed12b45deff3a1b046861c --- /dev/null +++ b/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" +#include "WebPageProxy.h" + +namespace WebKit { + +void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function&& callback) +{ + HWND viewHwnd = reinterpret_cast(m_page.viewWidget()); + HWND windowHwnd = GetAncestor(viewHwnd, GA_ROOT); + RECT viewRect; + RECT windowRect; + + if (!windowHwnd || !GetWindowRect(windowHwnd, &windowRect)) { + callback("Could not retrieve window size"_s); + return; + } + if (!GetWindowRect(viewHwnd, &viewRect)) { + callback("Could retrieve view size"_s); + return; + } + + width += windowRect.right - windowRect.left - viewRect.right + viewRect.left; + height += windowRect.bottom - windowRect.top - viewRect.bottom + viewRect.top; + + if (!SetWindowPos(windowHwnd, 0, 0, 0, width, height, SWP_NOCOPYBITS | SWP_NOSENDCHANGING | SWP_NOMOVE)) { + callback("Could not resize window"_s); + return; + } + callback(String()); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebPageInspectorInputAgentWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorInputAgentWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36fc7af8eb98b3f70d255ee858dccf580fae6679 --- /dev/null +++ b/Source/WebKit/UIProcess/win/WebPageInspectorInputAgentWin.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "NativeWebKeyboardEvent.h" +#include "WebPageProxy.h" +#include + +namespace WebKit { + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType 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, Vector& macCommands, MonotonicTime timestamp) +{ + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebView.cpp b/Source/WebKit/UIProcess/win/WebView.cpp index 0dab0688f2a24f27477f346e9f1c791763a10b86..003b1ef6c8e9c292b870076677d6cfd915858b05 100644 --- a/Source/WebKit/UIProcess/win/WebView.cpp +++ b/Source/WebKit/UIProcess/win/WebView.cpp @@ -570,7 +570,7 @@ LRESULT WebView::onSizeEvent(HWND hwnd, UINT, WPARAM, LPARAM lParam, bool& handl float intrinsicDeviceScaleFactor = deviceScaleFactorForWindow(hwnd); if (m_page) m_page->setIntrinsicDeviceScaleFactor(intrinsicDeviceScaleFactor); - m_viewSize = expandedIntSize(FloatSize(LOWORD(lParam), HIWORD(lParam)) / intrinsicDeviceScaleFactor); + m_viewSize = expandedIntSize(FloatSize(LOWORD(lParam), HIWORD(lParam))); if (m_page && m_page->drawingArea()) { // FIXME specify correctly layerPosition. diff --git a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp index 0705d7a9536a44a09c410d9e0e14b99c7ce5623e..7c9d8a156147707740cd984c170271593dcdacbd 100644 --- a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp +++ b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.cpp @@ -231,7 +231,7 @@ static Expected getImageInfoFromBuffer(const GRefPtr, String> saveBufferSnapshot(const GRefPtr& buffer, std::optional&& clipRect) +static Expected, String> saveBufferSnapshot(const GRefPtr& buffer, std::optional&& clipRect, bool nominalResolution) { GUniqueOutPtr error; GBytes* pixels = wpe_buffer_import_to_pixels(buffer.get(), &error.outPtr()); @@ -249,33 +249,39 @@ static Expected, String> saveBufferSnapshot(const GRefPtrminRowBytes()); + sk_sp fullScreenshot = SkImage::MakeRasterDirect(info, pixelsData, info->minRowBytes()); - if (clipRect) { - SkIRect clippedRect = SkIRect::MakeXYWH(clipRect->x(), clipRect->y(), clipRect->width(), clipRect->height()); - SkImageInfo clippedInfo = info->makeWH(clipRect->width(), clipRect->height()); - SkPixmap clippedPixmap(info.value(), nullptr, clippedInfo.minRowBytes()); - if (!pixmap.extractSubset(&clippedPixmap, clippedRect)) - return makeUnexpected("Failed to extract clipped snapshot"_s); - pixmap = clippedPixmap; - } - - auto image = SkImages::RasterFromPixmap(pixmap, [](const void*, void* context) { - g_bytes_unref(static_cast(context)); - }, bytes.leakRef()); + float deviceScale = m_view.page().deviceScaleFactor(); + if (!clipRect && (!nominalResolution || deviceScale == 1)) + return { ViewSnapshot::create(WTF::move(fullScreenshot)) }; - if (!image) - return makeUnexpected("Failed to create snapshot image"_s); + WebCore::IntSize size = clipRect ? clipRect->size() : m_view.page().viewSize(); + if (!nominalResolution) { + size.scale(deviceScale); + if (clipRect) + clipRect->scale(deviceScale); + } - return { ViewSnapshot::create(WTF::move(image)) }; + SkBitmap bitmap; + bitmap.allocPixels(SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType)); + SkCanvas canvas(bitmap); + if (clipRect) { + canvas.translate(-clipRect->x(), -clipRect->y()); + SkRect rect = SkRect::MakeXYWH(clipRect->x(), clipRect->y(), clipRect->width(), clipRect->height()); + canvas.clipRect(rect); + } + if (nominalResolution) + canvas.scale(1/deviceScale, 1/deviceScale); + canvas.drawImage(fullScreenshot, 0, 0); + return { ViewSnapshot::create(WTF::move(bitmap.asImage())) }; } -Expected, String> AcceleratedBackingStore::takeSnapshot(std::optional&& clipRect) +Expected, String> AcceleratedBackingStore::takeSnapshot(std::optional&& clipRect, bool nominalResolution) { if (!m_committedBuffer && !m_pendingBuffer) [[unlikely]] return makeUnexpected("No buffer to create snapshot from"_s); - return saveBufferSnapshot(m_committedBuffer ? m_committedBuffer : m_pendingBuffer, WTF::move(clipRect)); + return saveBufferSnapshot(m_committedBuffer ? m_committedBuffer : m_pendingBuffer, WTF::move(clipRect), nominalResolution); } void AcceleratedBackingStore::renderPendingBuffer() diff --git a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h index dcb02699a62caf8b79e21259287419b76bb71b77..905c613a2550fe4442666b35b393e75784405f07 100644 --- a/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h +++ b/Source/WebKit/UIProcess/wpe/AcceleratedBackingStore.h @@ -73,7 +73,7 @@ public: void updateSurfaceID(uint64_t); - Expected, String> takeSnapshot(std::optional&&); + Expected, String> takeSnapshot(std::optional&&, bool nominalResolution); RendererBufferDescription bufferDescription() const; diff --git a/Source/WebKit/UIProcess/wpe/PageInspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/PageInspectorTargetProxyWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..912e1919a1e2a29ad221114ff312ef118d323093 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/PageInspectorTargetProxyWPE.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "PageInspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include + +namespace WebKit { + +void PageInspectorTargetProxy::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/UIProcess/wpe/WebColorPickerWPE.cpp b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3c6d0a59daca4667ca8c709dad7816492389b47 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebColorPickerWPE.h" + +#include "WebPageProxy.h" + +namespace WebKit { +using namespace WebCore; + +Ref WebColorPickerWPE::create(WebPageProxy& page, const Color& initialColor, const IntRect& rect, std::optional frameID) +{ + return adoptRef(*new WebColorPickerWPE(page, initialColor, rect, frameID)); +} + +WebColorPickerWPE::WebColorPickerWPE(WebPageProxy& page, const Color& initialColor, const IntRect&, std::optional frameID) + : WebColorPicker(&page.colorPickerClient(), frameID) +{ +} + +WebColorPickerWPE::~WebColorPickerWPE() +{ + endPicker(); +} + +void WebColorPickerWPE::endPicker() +{ +} + +void WebColorPickerWPE::showColorPicker(const Color& color, const IntRect&) +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h new file mode 100644 index 0000000000000000000000000000000000000000..7f588248e107a19f5b700fb8e0fe51d1c5cf5aac --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WebColorPickerWPE_h +#define WebColorPickerWPE_h + +#include "WebColorPicker.h" + +typedef struct _GtkColorChooser GtkColorChooser; + +namespace WebCore { +class Color; +class IntRect; +} + +namespace WebKit { + +class WebColorPickerWPE : public WebColorPicker { +public: + static Ref create(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&, std::optional = std::nullopt); + virtual ~WebColorPickerWPE(); + + void endPicker() override; + void showColorPicker(const WebCore::Color&, const WebCore::IntRect&) override; + +protected: + WebColorPickerWPE(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&, std::optional = std::nullopt); +}; + +} // namespace WebKit + +#endif // WebColorPickerWPE_h diff --git a/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3ac81529d4dfb7070a9e1c30d4634eb10382713 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebDataListSuggestionsDropdownWPE.h" + +#include "WebPageProxy.h" +#include + +namespace WebKit { + +WebDataListSuggestionsDropdownWPE::WebDataListSuggestionsDropdownWPE(WebPageProxy& page) + : WebDataListSuggestionsDropdown(page) +{ +} + +WebDataListSuggestionsDropdownWPE::~WebDataListSuggestionsDropdownWPE() +{ +} + +void WebDataListSuggestionsDropdownWPE::platformShow(WebCore::DataListSuggestionInformation&& information) +{ +} + +void WebDataListSuggestionsDropdownWPE::handleKeydownWithIdentifier(const String& key) +{ +} + +void WebDataListSuggestionsDropdownWPE::close() +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.h b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.h new file mode 100644 index 0000000000000000000000000000000000000000..07a7cd3ab025616a41dc809e843a7f393b8e8e2f --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebDataListSuggestionsDropdownWPE.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2019 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "WebDataListSuggestionsDropdown.h" + +namespace WebKit { + +class WebPageProxy; + +class WebDataListSuggestionsDropdownWPE final : public WebDataListSuggestionsDropdown { +public: + static Ref create(WebPageProxy& page) + { + return adoptRef(*new WebDataListSuggestionsDropdownWPE(page)); + } + + ~WebDataListSuggestionsDropdownWPE(); + +private: + WebDataListSuggestionsDropdownWPE(WebPageProxy&); + + void platformShow(WebCore::DataListSuggestionInformation&&) final; + void handleKeydownWithIdentifier(const String&) final; + void close() final; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.cpp b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a44463faf011fbab08f87bb7007a5e71c2a73758 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 Apple Inc. All rights reserved. + * Copyright (C) 2021 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebDateTimePickerWPE.h" + +#if ENABLE(DATE_AND_TIME_INPUT_TYPES) + +using namespace WebCore; + +namespace WebKit { + +Ref WebDateTimePickerWPE::create(WebPageProxy& page) +{ + return adoptRef(*new WebDateTimePickerWPE(page)); +} + +WebDateTimePickerWPE::~WebDateTimePickerWPE() +{ +} + +WebDateTimePickerWPE::WebDateTimePickerWPE(WebPageProxy& page) + : WebDateTimePicker(page) +{ +} + +void WebDateTimePickerWPE::showDateTimePicker(WebCore::DateTimeChooserParameters&& params) +{ +} + +} // namespace WebKit + +#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES) diff --git a/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.h b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.h new file mode 100644 index 0000000000000000000000000000000000000000..0c0e3fce33b06ee72c4c29d2a4abe9644f4cc895 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2020 Apple Inc. All rights reserved. + * Copyright (C) 2021 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(DATE_AND_TIME_INPUT_TYPES) + +#include "WebDateTimePicker.h" +#include +#include + +namespace WebKit { + +class WebDateTimePickerWPE final : public WebDateTimePicker { +public: + static Ref create(WebPageProxy&); + ~WebDateTimePickerWPE(); + +private: + WebDateTimePickerWPE(WebPageProxy&); + + void showDateTimePicker(WebCore::DateTimeChooserParameters&&) final; +}; + +} // namespace WebKit + +#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES) diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..493c44f0051a748d6570070f8b169e0e781370f4 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" + +#include "DrawingAreaProxyCoordinatedGraphics.h" +#include "WebPageProxy.h" +#include + +namespace WebKit { + +void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function&& callback) +{ + WebCore::IntSize viewSize(width, height); + if (m_page.viewSize() == viewSize) { + callback(String()); + return; + } + + struct wpe_view_backend* backend = m_page.viewBackend(); + wpe_view_backend_dispatch_set_size(backend, viewSize.width(), viewSize.height()); + if (auto* drawingArea = static_cast(m_page.drawingArea())) { + drawingArea->waitForSizeUpdate([callback = WTF::move(callback)](const DrawingAreaProxyCoordinatedGraphics&) mutable { + callback(String()); + }); + } else + callback(String()); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c6af56767484e2889208c96d454a0924f290ba9c --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "NativeWebKeyboardEvent.h" +#include "WebPageProxy.h" +#include +#include + +namespace WebKit { + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType 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, Vector& macCommands, MonotonicTime timestamp) +{ + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp index 9b688ad328317fea4fd96ce66e9714bad8f0f937..402a36a9c565e13ec298aa7f014f0d9208ebddb7 100644 --- a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp +++ b/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp @@ -33,6 +33,10 @@ void WebPreferences::platformInitializeStore() setAcceleratedCompositingEnabled(true); setForceCompositingMode(true); setThreadedScrollingEnabled(true); + + // Playwright override begin + setThreadedScrollingEnabled(false); + // Playwright override end } } // namespace WebKit diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj index 1b110e60239dfe1599a356d71f02b9bfe2e9a17c..1af727420f121f24a564e7756d41b51a3623f040 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj @@ -1570,6 +1570,7 @@ 5CABDC8722C40FED001EDE8E /* APIMessageListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CABDC8322C40FA7001EDE8E /* APIMessageListener.h */; }; 5CADDE05215046BD0067D309 /* WKWebProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C74300E21500492004BFA17 /* WKWebProcess.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5CAECB6627465AE400AB78D0 /* UnifiedSource115.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */; }; + BF2C49ED7AD83CB7BC93CC92 /* UnifiedSource116.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D7178FBC4EDB168CDB0B04D /* UnifiedSource116.cpp */; }; 5CAF7AA726F93AB00003F19E /* adattributiond.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAF7AA526F93A950003F19E /* adattributiond.cpp */; }; 5CAFDE452130846300B1F7E1 /* _WKInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE422130843500B1F7E1 /* _WKInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; 5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */; }; @@ -2393,6 +2394,18 @@ DF0C5F28252ECB8E00D921DB /* WKDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F24252ECB8D00D921DB /* WKDownload.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2A252ECB8E00D921DB /* WKDownloadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2B252ED44000D921DB /* WKDownloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */; }; + D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */; }; + D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */; }; + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94392370F060002C4D9E /* RemoteInspectorPipe.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 /* PageInspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* PageInspectorTargetProxyMac.mm */; }; + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */; }; + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */; }; DF462E0F23F22F5500EFF35F /* WKHTTPCookieStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF462E1223F338BE00EFF35F /* WKContentWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF7A231C291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF7A231B291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -2500,6 +2513,8 @@ E5BEF6822130C48000F31111 /* WebDataListSuggestionsDropdownIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = E5BEF6802130C47F00F31111 /* WebDataListSuggestionsDropdownIOS.h */; }; E5CB07DC20E1678F0022C183 /* WKFormColorControl.h in Headers */ = {isa = PBXBuildFile; fileRef = E5CB07DA20E1678F0022C183 /* WKFormColorControl.h */; }; E5CBA76427A318E100DF7858 /* UnifiedSource120.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA75F27A3187800DF7858 /* UnifiedSource120.cpp */; }; + E5CBA77427A318E100DF7858 /* UnifiedSource121.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76F27A3187800DF7858 /* UnifiedSource121.cpp */; }; + E5CBA78427A318E100DF7858 /* UnifiedSource122.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA77F27A3187800DF7858 /* UnifiedSource122.cpp */; }; E5CBA76527A318E100DF7858 /* UnifiedSource118.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */; }; E5CBA76627A318E100DF7858 /* UnifiedSource116.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */; }; E5CBA76727A318E100DF7858 /* UnifiedSource119.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76027A3187900DF7858 /* UnifiedSource119.cpp */; }; @@ -2546,6 +2561,8 @@ F3EEEE592DB318270038CC1D /* BidiBrowserAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = F3EEEE572DB318270038CC1D /* BidiBrowserAgent.h */; }; F3EEEE5A2DB318270038CC1D /* BidiBrowserAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F3EEEE582DB318270038CC1D /* BidiBrowserAgent.cpp */; }; F404455C2D5CFB56000E587E /* AppKitSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F404455A2D5CFB56000E587E /* AppKitSoftLink.h */; }; + F33C7AC7249AD79C0018BE41 /* libwebrtc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */; }; + F3867F0A24607D4E008F0F31 /* InspectorScreencastAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */; }; F409BA181E6E64BC009DA28E /* WKDragDestinationAction.h in Headers */ = {isa = PBXBuildFile; fileRef = F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; F40C3B712AB401C5007A3567 /* WKDatePickerPopoverController.h in Headers */ = {isa = PBXBuildFile; fileRef = F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */; }; F41145682CD939E0004CDBD1 /* _WKTouchEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = F41145652CD939E0004CDBD1 /* _WKTouchEventGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -6721,6 +6738,7 @@ 5CABDC8522C40FCC001EDE8E /* WKMessageListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMessageListener.h; sourceTree = ""; }; 5CABE07A28F60E8A00D83FD9 /* WebPushMessage.serialization.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebPushMessage.serialization.in; sourceTree = ""; }; 5CADDE0D2151AA010067D309 /* AuthenticationChallengeDisposition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthenticationChallengeDisposition.h; sourceTree = ""; }; + 1D7178FBC4EDB168CDB0B04D /* UnifiedSource116.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource116.cpp; sourceTree = ""; }; 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource115.cpp; sourceTree = ""; }; 5CAF7AA426F93A750003F19E /* adattributiond */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = adattributiond; sourceTree = BUILT_PRODUCTS_DIR; }; 5CAF7AA526F93A950003F19E /* adattributiond.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = adattributiond.cpp; sourceTree = ""; }; @@ -8553,6 +8571,19 @@ DF0C5F24252ECB8D00D921DB /* WKDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownload.h; sourceTree = ""; }; DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadInternal.h; sourceTree = ""; }; DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadDelegate.h; sourceTree = ""; }; + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBrowserInspector.h; sourceTree = ""; }; + D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorPlaywrightAgentClientMac.h; sourceTree = ""; }; + D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorPlaywrightAgentClient.h; sourceTree = ""; }; + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorPipe.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 /* PageInspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PageInspectorTargetProxyMac.mm; sourceTree = ""; }; + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorInputAgentMac.mm; sourceTree = ""; }; + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorPlaywrightAgentClientMac.mm; sourceTree = ""; }; DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKHTTPCookieStorePrivate.h; sourceTree = ""; }; DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKContentWorldPrivate.h; sourceTree = ""; }; DF58C6311371AC5800F9A37C /* NativeWebWheelEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebWheelEvent.h; sourceTree = ""; }; @@ -8748,6 +8779,8 @@ E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource118.cpp; sourceTree = ""; }; E5CBA76227A3187900DF7858 /* UnifiedSource117.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource117.cpp; sourceTree = ""; }; E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource116.cpp; sourceTree = ""; }; + E5CBA76F27A3187800DF7858 /* UnifiedSource121.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource121.cpp; sourceTree = ""; }; + E5CBA77F27A3187800DF7858 /* UnifiedSource122.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource122.cpp; sourceTree = ""; }; E5DEFA6726F8F42600AB68DB /* PhotosUISPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhotosUISPI.h; sourceTree = ""; }; E838FCAF2DE90BF800703353 /* ISO18013MobileDocumentRequest+Extras.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ISO18013MobileDocumentRequest+Extras.swift"; sourceTree = ""; }; E88885662DC914C400C572B8 /* WKISO18013Request.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKISO18013Request.h; sourceTree = ""; }; @@ -8812,6 +8845,9 @@ F404455A2D5CFB56000E587E /* AppKitSoftLink.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppKitSoftLink.h; sourceTree = ""; }; F404455B2D5CFB56000E587E /* AppKitSoftLink.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppKitSoftLink.mm; sourceTree = ""; }; F4063DDE2D71481E00F3FE6E /* LLVMProfiling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLVMProfiling.h; sourceTree = ""; }; + F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libwebrtc.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + F3867F0324607D2B008F0F31 /* InspectorScreencastAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorScreencastAgent.cpp; sourceTree = ""; }; + F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorScreencastAgent.h; sourceTree = ""; }; F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDragDestinationAction.h; sourceTree = ""; }; F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKDatePickerPopoverController.h; sourceTree = ""; }; F40C3B702AB40167007A3567 /* WKDatePickerPopoverController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKDatePickerPopoverController.mm; sourceTree = ""; }; @@ -9345,6 +9381,7 @@ 3766F9EE189A1241003CF19B /* JavaScriptCore.framework in Frameworks */, 3766F9F1189A1254003CF19B /* libicucore.dylib in Frameworks */, 7B9FC5BB28A5233B007570E7 /* libWebKitPlatform.a in Frameworks */, + F33C7AC7249AD79C0018BE41 /* libwebrtc.dylib in Frameworks */, 3766F9EF189A1244003CF19B /* QuartzCore.framework in Frameworks */, 37694525184FC6B600CDE21F /* Security.framework in Frameworks */, 37BEC4DD1948FC6A008B4286 /* WebCore.framework in Frameworks */, @@ -12710,6 +12747,7 @@ 99788ACA1F421DCA00C08000 /* _WKAutomationSessionConfiguration.mm */, 990D28A81C6404B000986977 /* _WKAutomationSessionDelegate.h */, 990D28AF1C65203900986977 /* _WKAutomationSessionInternal.h */, + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */, 5C4609E222430E4C009943C2 /* _WKContentRuleListAction.h */, 5C4609E322430E4D009943C2 /* _WKContentRuleListAction.mm */, 5C4609E422430E4D009943C2 /* _WKContentRuleListActionInternal.h */, @@ -14517,6 +14555,7 @@ E34B110C27C46BC6006D2F2E /* libWebCoreTestShim.dylib */, E34B110F27C46D09006D2F2E /* libWebCoreTestSupport.dylib */, DDE992F4278D06D900F60D26 /* libWebKitAdditions.a */, + F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */, 57A9FF15252C6AEF006A2040 /* libWTF.a */, 5750F32A2032D4E500389347 /* LocalAuthentication.framework */, 570DAAB0230273D200E8FC04 /* NearField.framework */, @@ -15117,6 +15156,8 @@ children = ( 9197940423DBC4BB00257892 /* InspectorBrowserAgent.cpp */, 9197940323DBC4BB00257892 /* InspectorBrowserAgent.h */, + F3867F0324607D2B008F0F31 /* InspectorScreencastAgent.cpp */, + F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */, ); path = Agents; sourceTree = ""; @@ -15932,6 +15973,7 @@ E1513C65166EABB200149FCB /* AuxiliaryProcessProxy.h */, 46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */, 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */, + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */, 5C6D69352AC3935D0099BDAF /* BrowsingContextGroup.cpp */, 5C6D69362AC3935D0099BDAF /* BrowsingContextGroup.h */, 5CA98549210BEB5A0057EB6B /* BrowsingWarning.h */, @@ -15962,6 +16004,8 @@ BC06F43912DBCCFB002D78DE /* GeolocationPermissionRequestProxy.cpp */, BC06F43812DBCCFB002D78DE /* GeolocationPermissionRequestProxy.h */, 2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */, + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */, + D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */, 5CEABA2B2333251400797797 /* LegacyGlobalSettings.cpp */, 5CEABA2A2333247700797797 /* LegacyGlobalSettings.h */, 31607F3819627002009B87DA /* LegacySessionStateCoding.h */, @@ -15992,6 +16036,7 @@ 4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */, 4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */, 411B89CB27B2B89600F9EBD3 /* QueryPermissionResultCallback.h */, + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */, 5CCB54DC2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.cpp */, 5CCB54DB2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.h */, FABBBC802D35AC6800820017 /* RemotePageFullscreenManagerProxy.cpp */, @@ -16113,6 +16158,8 @@ BC7B6204129A0A6700D174A4 /* WebPageGroup.h */, 2D9EA3101A96D9EB002D2807 /* WebPageInjectedBundleClient.cpp */, 2D9EA30E1A96CBFF002D2807 /* WebPageInjectedBundleClient.h */, + D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */, + D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */, 9B7F8A502C785725000057F3 /* WebPageLoadTiming.h */, BC111B0B112F5E4F00337BAB /* WebPageProxy.cpp */, BC032DCB10F4389F0058C15A /* WebPageProxy.h */, @@ -16307,6 +16354,7 @@ BC646C1911DD399F006455B0 /* WKBackForwardListItemRef.h */, BC646C1611DD399F006455B0 /* WKBackForwardListRef.cpp */, BC646C1711DD399F006455B0 /* WKBackForwardListRef.h */, + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */, BCB9E24A1120E15C00A137E0 /* WKContext.cpp */, BCB9E2491120E15C00A137E0 /* WKContext.h */, 1AE52F9319201F6B00A1FA37 /* WKContextConfigurationRef.cpp */, @@ -16890,8 +16938,11 @@ B878B613133428DC006888E9 /* CorrectionPanel.h */, B878B614133428DC006888E9 /* CorrectionPanel.mm */, 7AFA6F682A9F57C50055322A /* DisplayLinkMac.cpp */, + D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */, + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */, 0FCB4E5818BBE3D9000FCFC9 /* PageClientImplMac.h */, 0FCB4E5918BBE3D9000FCFC9 /* PageClientImplMac.mm */, + D79902AF236E9404005D6F7E /* PageInspectorTargetProxyMac.mm */, E18E6909169B563F009B6670 /* SecItemShimProxy.cpp */, E18E690A169B563F009B6670 /* SecItemShimProxy.h */, E18E690D169B57DF009B6670 /* SecItemShimProxy.messages.in */, @@ -16911,6 +16962,8 @@ E568B92120A3AC6A00E3C856 /* WebDataListSuggestionsDropdownMac.mm */, E55CD20124D09F1F0042DB9C /* WebDateTimePickerMac.h */, E55CD20224D09F1F0042DB9C /* WebDateTimePickerMac.mm */, + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */, + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */, BC857E8512B71EBB00EDEB2E /* WebPageProxyMac.mm */, BC5750951268F3C6006F0F12 /* WebPopupMenuProxyMac.h */, BC5750961268F3C6006F0F12 /* WebPopupMenuProxyMac.mm */, @@ -17739,6 +17792,7 @@ 99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */, 990D28AC1C6420CF00986977 /* _WKAutomationSessionDelegate.h in Headers */, 990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */, + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */, CD89ACBD2EA696A300C76423 /* _WKCaptionStyleMenuController.h in Headers */, 97C476282ECD33A6004D1492 /* _WKCaptionStyleMenuControllerInternal.h in Headers */, 5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */, @@ -18059,6 +18113,7 @@ E170876C16D6CA6900F99226 /* BlobRegistryProxy.h in Headers */, 4F601432155C5AA2001FBDE0 /* BlockingResponseMap.h in Headers */, 1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */, + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */, 5CA9854A210BEB640057EB6B /* BrowsingWarning.h in Headers */, A7E69BCC2B2117A100D43D3F /* BufferAndBackendInfo.h in Headers */, BC3065FA1259344E00E71278 /* CacheModel.h in Headers */, @@ -18265,7 +18320,11 @@ BC14DF77120B5B7900826C0C /* InjectedBundleScriptWorld.h in Headers */, CE550E152283752200D28791 /* InsertTextOptions.h in Headers */, 9197940523DBC4BB00257892 /* InspectorBrowserAgent.h in Headers */, + D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */, 996B2B9D25E257FF00719379 /* InspectorExtensionDelegate.h in Headers */, + D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */, + D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */, + F3867F0A24607D4E008F0F31 /* InspectorScreencastAgent.h in Headers */, A5E391FD2183C1F800C8FB31 /* InspectorTargetProxy.h in Headers */, 07AE8FBD2F3BC4F300A4C0CA /* InteractionInformationAtPosition.h in Headers */, 07AE8FC22F3BC58200A4C0CA /* InteractionInformationRequest.h in Headers */, @@ -18550,6 +18609,7 @@ 07E065142F19E01000ECDA2E /* RemoteGPU.h in Headers */, 0F6E7C532C4C386800F1DB85 /* RemoteGraphicsContextMessages.h in Headers */, F451C0FE2703B263002BA03B /* RemoteGraphicsContextProxy.h in Headers */, + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */, 2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */, 2DDF731518E95060004F5A66 /* RemoteLayerBackingStoreCollection.h in Headers */, 5F4D67D682584880B7E5A569 /* RemoteLayerTreeCommitBundle.h in Headers */, @@ -18995,6 +19055,8 @@ 939EF87029D112EE00F23AEE /* WebPageInlines.h in Headers */, 9197940823DBC4CB00257892 /* WebPageInspectorAgentBase.h in Headers */, A513F5402154A5D700662841 /* WebPageInspectorController.h in Headers */, + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */, + D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */, C0CE72A11247E71D00BC0EC4 /* WebPageMessages.h in Headers */, 2D5C9D0619C81D8F00B3C5C1 /* WebPageOverlay.h in Headers */, 939EF86F29D0C17300F23AEE /* WebPageProxy.h in Headers */, @@ -21880,6 +21942,7 @@ 522F792928D50EBB0069B45B /* HidService.mm in Sources */, 2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */, 2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */, + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */, 074D6A652F385435006089F6 /* IntRectCG.swift in Sources */, 5CF250AF2EE06491006A7172 /* IPCTesterReceiver.swift in Sources */, 5C448C662EE06E11008931C7 /* IPCTesterReceiverMessageReceiver.swift in Sources */, @@ -21899,6 +21962,7 @@ FA5AAE9C2E6A217A00FE693D /* NetworkSoftLink.mm in Sources */, EEEEBCBD2EE35A8B000FF6AG /* NSGlassEffectView+Extras.swift in Sources */, DD4BDE7B2CA38213001A3339 /* ObjectiveCBlockConversions.swift in Sources */, + D79902B2236E9404005D6F7E /* PageInspectorTargetProxyMac.mm in Sources */, 1CB9138F2E8C6D500002BCB7 /* PlatformUnifiedSource1-ARC.mm in Sources */, 1CB913932E8C71920002BCB7 /* PlatformUnifiedSource2-ARC.mm in Sources */, A1B849382F3D9F02004256A1 /* PlaybackSessionInterfaceAVKit.mm in Sources */, @@ -22242,6 +22306,8 @@ 078B04A02CF18EAB00B453A6 /* WebPage+NavigationPreferences.swift in Sources */, 071467782DFE84E500F77867 /* WebPage+Transferable.swift in Sources */, 07CB79962CE9435700199C49 /* WebPage.swift in Sources */, + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */, + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */, 0715310F2F3037C100B56C0E /* WebPageProxy.swift in Sources */, 7CE9CE101FA0767A000177DE /* WebPageUpdatePreferences.cpp in Sources */, 079A4DA12D72CC0D00CA387F /* WebPageWebView.swift in Sources */, diff --git a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp index c49360b01f22bed75a9c92b9d4ea0dbbb66d5617..0b6f28c163680d51bfee78e37613fa73b31e05dc 100644 --- a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp +++ b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.cpp @@ -93,4 +93,13 @@ String FrameInspectorTarget::toTargetID(WebCore::FrameIdentifier frameID, WebCor return makeString("frame-"_s, frameID.toUInt64(), '-', processID.toUInt64()); } +void FrameInspectorTarget::didCreateSubframe(WebFrame& frame) +{ + if (!m_channel) + return; + + // Auto connect to the subframe if the parent frame is inspected. + frame.connectInspector(static_cast(m_channel.get())->connectionType()); +} + } // namespace WebKit diff --git a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h index 2b2820a4ded07d459f3342d5457c0747c2db2215..261c255b95071b7e02365904935381c789970d48 100644 --- a/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h +++ b/Source/WebKit/WebProcess/Inspector/FrameInspectorTarget.h @@ -56,6 +56,8 @@ public: static String toTargetID(WebCore::FrameIdentifier, WebCore::ProcessIdentifier); + void didCreateSubframe(WebFrame&); + private: WeakRef m_frame; std::unique_ptr m_channel; diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp index ef050f1bf94dc201a89055164a5c0c9f33b9bbad..2e228513e686dd67e3e8129670b0ad374a5f54d2 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp @@ -273,6 +273,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } #endif + if (m_emulateOfflineState) { + scheduleInternallyFailedLoad(resourceLoader); + return; + } + #if ENABLE(PDFJS) if (tryLoadingUsingPDFJSHandler(resourceLoader, trackingParameters)) return; @@ -294,12 +299,16 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } if (InspectorInstrumentationWebKit::shouldInterceptRequest(resourceLoader)) { - InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource = RefPtr { resource }](const ResourceRequest& request) { - auto& resourceLoader = protectedResourceLoader.get(); - WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: intercepted URL will be scheduled with the NetworkProcess"); - scheduleLoadFromNetworkProcess(resourceLoader, request, *trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource)); - }); - return; + bool isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate; + // Do not intercept navigation request which could already have been intercepted and resumed. + if (!(isMainFrameNavigation && m_existingNetworkResourceLoadIdentifierToResume)) { + InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource = RefPtr { resource }](const ResourceRequest& request) { + auto& resourceLoader = protectedResourceLoader.get(); + WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: intercepted URL will be scheduled with the NetworkProcess"); + scheduleLoadFromNetworkProcess(resourceLoader, request, *trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource)); + }); + return; + } } WEBLOADERSTRATEGY_RELEASE_LOG_FORWARDABLE(WebLoaderStrategyScheduleLoad); @@ -431,7 +440,7 @@ static void addParametersShared(const LocalFrame* frame, NetworkResourceLoadPara parameters.linkPreconnectEarlyHintsEnabled = mainFrame->settings().linkPreconnectEarlyHintsEnabled(); } -void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime) +bool WebLoaderStrategy::fillParametersForNetworkProcessLoad(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime, NetworkResourceLoadParameters& loadParameters) { auto identifier = *resourceLoader.identifier(); @@ -443,10 +452,10 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL && resourceLoader.frameLoader()->notifier().isInitialRequestIdentifier(identifier) ? MainFrameMainResource::Yes : MainFrameMainResource::No; if (!page->allowsLoadFromURL(request.url(), mainFrameMainResource)) { - RunLoop::mainSingleton().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { + RunLoop::mainSingleton().dispatch([resourceLoader = Ref { resourceLoader }, error = platformStrategies()->loaderStrategy()->blockedError(request)] { resourceLoader->didFail(error); }); - return; + return false; } } @@ -456,19 +465,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be scheduled with the NetworkProcess with priority %d, storedCredentialsPolicy %i", resourceLoader.url().string().latin1().data(), static_cast(resourceLoader.request().priority()), (int)storedCredentialsPolicy); - NetworkResourceLoadParameters loadParameters { - trackingParameters.webPageProxyID, - trackingParameters.pageID, - trackingParameters.frameID, - request - }; - if (!loadParameters.createSandboxExtensionHandlesIfNecessary()) { - RunLoop::mainSingleton().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { - resourceLoader->didFail(error); - }); - return; - } - loadParameters.identifier = identifier; loadParameters.parentPID = legacyPresentingApplicationPID(); loadParameters.contentSniffingPolicy = contentSniffingPolicy; @@ -563,14 +559,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL if (loadParameters.options.mode != FetchOptions::Mode::Navigate) { ASSERT(loadParameters.sourceOrigin); - if (!loadParameters.sourceOrigin) { - WEBLOADERSTRATEGY_RELEASE_LOG_ERROR("scheduleLoad: no sourceOrigin (priority=%d)", static_cast(resourceLoader.request().priority())); - scheduleInternallyFailedLoad(resourceLoader); - return; - } + if (!loadParameters.sourceOrigin) + return false; } - loadParameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks(); + loadParameters.shouldRestrictHTTPResponseAccess = true; loadParameters.isMainFrameNavigation = isMainFrameNavigation; if (loadParameters.isMainFrameNavigation && document) { @@ -635,6 +628,30 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL if (RefPtr handle = resourceLoader.cachedResource()) loadParameters.isInitiatorPrefetch = handle->type() == CachedResource::Type::LinkPrefetch; + return true; +} + +void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime) +{ + NetworkResourceLoadParameters loadParameters { + trackingParameters.webPageProxyID, + trackingParameters.pageID, + trackingParameters.frameID, + request + }; + if (!loadParameters.createSandboxExtensionHandlesIfNecessary()) { + RunLoop::mainSingleton().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { + resourceLoader->didFail(error); + }); + return; + } + + if (!fillParametersForNetworkProcessLoad(resourceLoader, request, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime, loadParameters)) { + WEBLOADERSTRATEGY_RELEASE_LOG_ERROR("scheduleLoad: no sourceOrigin (priority=%d)", static_cast(resourceLoader.request().priority())); + scheduleInternallyFailedLoad(resourceLoader); + return; + } + std::optional existingNetworkResourceLoadIdentifierToResume; if (loadParameters.isMainFrameNavigation) existingNetworkResourceLoadIdentifierToResume = std::exchange(m_existingNetworkResourceLoadIdentifierToResume, std::nullopt); @@ -650,7 +667,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } auto loader = WebResourceLoader::create(resourceLoader, trackingParameters); - m_webResourceLoaders.set(identifier, WTF::move(loader)); + m_webResourceLoaders.set(*resourceLoader.identifier(), WTF::move(loader)); } void WebLoaderStrategy::scheduleInternallyFailedLoad(WebCore::ResourceLoader& resourceLoader) @@ -1070,7 +1087,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier bool WebLoaderStrategy::isOnLine() const { - return m_isOnLine; + return m_emulateOfflineState ? false : m_isOnLine; } void WebLoaderStrategy::addOnlineStateChangeListener(Function&& listener) @@ -1096,6 +1113,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet void WebLoaderStrategy::setOnLineState(bool isOnLine) { + if (m_emulateOfflineState) { + m_isOnLine = isOnLine; + return; + } + if (m_isOnLine == isOnLine) return; @@ -1104,6 +1126,12 @@ void WebLoaderStrategy::setOnLineState(bool isOnLine) listener(isOnLine); } +void WebLoaderStrategy::setEmulateOfflineState(bool offline) { + m_emulateOfflineState = offline; + for (auto& listener : m_onlineStateChangeListeners) + listener(offline ? false : m_isOnLine); +} + void WebLoaderStrategy::setCaptureExtraNetworkLoadMetricsEnabled(bool enabled) { WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCaptureExtraNetworkLoadMetricsEnabled(enabled), 0); diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h index ab7f322fc4e1b340bb0acdc84d4f7ba39a6e0df0..d79aea95dc4e2ead71a161b24c0e1f081fad4404 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h @@ -26,6 +26,7 @@ #pragma once #include "NetworkResourceLoadIdentifier.h" +#include "NetworkResourceLoadParameters.h" #include "WebResourceLoader.h" #include #include @@ -98,6 +99,9 @@ public: bool isOnLine() const final; void addOnlineStateChangeListener(Function&&) final; void setOnLineState(bool); + void setEmulateOfflineState(bool) final; + + bool fillParametersForNetworkProcessLoad(WebCore::ResourceLoader&, const WebCore::ResourceRequest&, const WebResourceLoader::TrackingParameters&, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime, NetworkResourceLoadParameters&); void setExistingNetworkResourceLoadIdentifierToResume(std::optional existingNetworkResourceLoadIdentifierToResume) { m_existingNetworkResourceLoadIdentifierToResume = existingNetworkResourceLoadIdentifierToResume; } @@ -166,6 +170,7 @@ private: Vector> m_onlineStateChangeListeners; std::optional m_existingNetworkResourceLoadIdentifierToResume; bool m_isOnLine { true }; + bool m_emulateOfflineState { false }; }; } // namespace WebKit diff --git a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp index 24c2649b31ce74a91911c8d8ff9be630dc29d576..11e1b09f7fe0573374f887bcbe57e25e4a8f6b87 100644 --- a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp +++ b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp @@ -236,9 +236,6 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR coreLoader->didReceiveResponse(ResourceResponse { inspectorResponse }, [this, protectedThis = Ref { *this }, interceptedRequestIdentifier, policyDecisionCompletionHandler = WTF::move(policyDecisionCompletionHandler), overrideData = WTF::move(overrideData)]() mutable { RefPtr coreLoader = m_coreLoader; - if (policyDecisionCompletionHandler) - policyDecisionCompletionHandler(); - if (!m_coreLoader || !coreLoader->identifier()) { m_interceptController.continueResponse(interceptedRequestIdentifier); return; @@ -255,6 +252,8 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR } }); }); + if (policyDecisionCompletionHandler) + policyDecisionCompletionHandler(); return; } diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp index 83519d3b8b16ad84a162f99ec6e3c9f9a0525e73..5cb5b17e983ef538c12bcaa81fe9e425cd622f06 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp @@ -503,6 +503,9 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev if (!page) return; + if (level == MessageLevel::Error) + page->send(Messages::WebPageProxy::LogToStderr(message)); + #if !PLATFORM(COCOA) page->injectedBundleUIClient().willAddMessageToConsole(page.get(), source, level, message, lineNumber, columnNumber, sourceID); #endif diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp index b3f2fc81270244d1e52568f2355b7e4390ce4ae3..7e34067a3c7dc61a355ac1ddd7c7a874d6bc0771 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp @@ -53,7 +53,7 @@ OptionSet WebDragClient::dragSourceActionMaskForPoint(const In return m_page.get()->allowedDragSourceActions(); } -#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE) +#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE) && !PLATFORM(WIN) void WebDragClient::startDrag(DragItem, DataTransfer&, Frame&, const std::optional&) { } diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebUserMediaClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebUserMediaClient.cpp index 23fdfa0d3d98fc703324372684208e5c4b190dbd..529870b21ab6f2ecd41eaea822186b325d7e1ff7 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebUserMediaClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebUserMediaClient.cpp @@ -26,6 +26,7 @@ #include "UserMediaPermissionRequestManager.h" #include "WebPage.h" #include "WebPageProxyMessages.h" +#include #include #include #include diff --git a/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm b/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm index bad45b79e581bd66fabf6c09189ed05317a1946e..08cbd2fa2d6283b29168ee3d0140bd35bb878098 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm +++ b/Source/WebKit/WebProcess/WebCoreSupport/cocoa/WebDragClientCocoa.mm @@ -131,7 +131,8 @@ static RefPtr cachedImage(Element& element) void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, Element& element, const URL& url, const String& label, LocalFrame*) { - ASSERT(pasteboardName == String(NSPasteboardNameDrag)); + if (pasteboardName != String(NSPasteboardNameDrag)) + return; RefPtr image = cachedImage(element); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..741ef5b11fe8718529105339cda0fab597bad9de --- /dev/null +++ b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebDragClient.h" + +#if ENABLE(DRAG_SUPPORT) + +#include "MessageSenderInlines.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include +#include +#include +#include +#include +#include + +#include + +namespace WebKit { +using namespace WebCore; + +void WebDragClient::didConcludeEditDrag() +{ +} + +void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame& frame, const std::optional&) +{ + m_page->willStartDrag(); + m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().createDragDataMap())); +} + +}; // namespace WebKit. + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp index 5ac78eb5880335f49a9a6f2690626e46fbcac7f4..aa12d9c96279054e01cc9e82e78547a75702a85f 100644 --- a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp +++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp @@ -27,6 +27,7 @@ #include "DrawingArea.h" #include "DrawingAreaMessages.h" +#include "DrawingAreaProxyMessages.h" #include "Logging.h" #include "WebPage.h" #include "WebPageCreationParameters.h" diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp index 42644873c3a43e84452298c131d1d356eed6b36c..9718fb79e8918809099bc3eedd1cdfc7d751a575 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -446,6 +447,12 @@ void WebCookieJar::setOptInCookiePartitioningEnabled(bool enabled) } #endif +void WebCookieJar::setCookieFromResponse(ResourceLoader& loader, const String& setCookieValue) +{ + const auto& request = loader.request(); + WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCookieFromResponse(request.firstPartyForCookies(), SameSiteInfo::create(request), request.url(), setCookieValue), 0); +} + #if !PLATFORM(COCOA) String WebCookieJar::cookiesInPartitionedCookieStorage(const WebCore::Document&, const URL&, const WebCore::SameSiteInfo&) const diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h index a7ad18fc1201e5de2cc1528539a765599ecfc41e..ebea233bc54ab6e56fb7093ff63e2368e8670ccd 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h @@ -81,6 +81,8 @@ public: void setOptInCookiePartitioningEnabled(bool); #endif + void setCookieFromResponse(WebCore::ResourceLoader&, const String& setCookieValue); + private: WebCookieJar(); diff --git a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp index 2a3aa30f08da8e00e790dbdbac574c986a3a4f0a..9b70be2682defadef10da8b69af50ca115878cf6 100644 --- a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp @@ -181,6 +181,9 @@ Ref WebFrame::createSubframe(WebPage& page, WebFrame& parent, const At ASSERT(ownerElement.document().frame()); coreFrame->init(); + if (parent.m_inspectorTarget) + parent.m_inspectorTarget->didCreateSubframe(frame); + return frame; } diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index ead5b0db7cebdf2053358cc3a45c8298d0b0ad83..7b92d1d6e59cb5fbaaf9b0f638e25e7b2b2f2d63 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -264,6 +264,7 @@ #include #include #include +#include #include #include #include @@ -1227,6 +1228,14 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) setLinkDecorationFilteringData(WTF::move(parameters.linkDecorationFilteringData)); setAllowedQueryParametersForAdvancedPrivacyProtections(WTF::move(parameters.allowedQueryParametersForAdvancedPrivacyProtections)); #endif + if (parameters.deviceOrientationOverride) + page->setOverrideOrientation(parameters.deviceOrientationOverride); + // For popup windows WebPage::Show() maybe called in the next lines from the constructor, + // at which point the page is not in the WebProcess's map yet and it is not safe to + // dispatch nested message loop and receive IPC messages. To mitigate that, the actual + // pause is postponed until the page is added to the map. + if (parameters.shouldPauseInInspectorWhenShown) + m_page->inspectorController().pauseOnStart(parameters.windowFeatures ? PageInspectorController::PauseCondition::WHEN_CREATION_FINISHED : PageInspectorController::PauseCondition::WHEN_SHOWN); if (parameters.windowFeatures) { page->applyWindowFeatures(*parameters.windowFeatures); page->chrome().show(); @@ -2217,6 +2226,22 @@ void WebPage::loadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, st frame->loadDidCommitInAnotherProcess(layerHostingContextIdentifier); } +void WebPage::loadRequestInFrameForInspector(LoadParameters&& loadParameters, WebCore::FrameIdentifier frameID) +{ + WebFrame* frame = WebProcess::singleton().webFrame(frameID); + if (!frame) { + send(Messages::WebPageProxy::DidDestroyNavigation(*loadParameters.navigationID)); + return; + } + + // FIXME: use m_pendingNavigationID instead? + m_pendingFrameNavigationID = loadParameters.navigationID; + + FrameLoadRequest frameLoadRequest { *frame->coreLocalFrame(), WTF::move(loadParameters.request) }; + frame->coreLocalFrame()->loader().load(WTF::move(frameLoadRequest)); + ASSERT(!m_pendingFrameNavigationID); +} + void WebPage::loadRequest(LoadParameters&& loadParameters) { WEBPAGE_RELEASE_LOG_FORWARDABLE(Loading, WebPageLoadRequest, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), loadParameters.existingNetworkResourceLoadIdentifierToResume ? loadParameters.existingNetworkResourceLoadIdentifierToResume->toUInt64() : 0); @@ -2408,7 +2433,9 @@ void WebPage::stopLoading() void WebPage::stopLoadingDueToProcessSwap() { SetForScope isStoppingLoadingDueToProcessSwap(m_isStoppingLoadingDueToProcessSwap, true); + InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(m_page.get(), true); stopLoading(); + InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(m_page.get(), false); } bool WebPage::defersLoading() const @@ -2997,7 +3024,7 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum #if PLATFORM(IOS_FAMILY) if (m_viewportConfiguration.setViewportArguments(viewportArguments)) viewportConfigurationChanged(); -#elif PLATFORM(GTK) || PLATFORM(WPE) +#elif PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN) || PLATFORM(MAC) // Adjust view dimensions when using fixed layout. RefPtr localMainFrame = this->localMainFrame(); RefPtr view = localMainFrame ? localMainFrame->view() : nullptr; @@ -3858,6 +3885,13 @@ void WebPage::flushDeferredIntersectionObservations() protect(corePage())->flushDeferredIntersectionObservations(); } +#if ENABLE(ORIENTATION_EVENTS) +void WebPage::setDeviceOrientation(WebCore::IntDegrees deviceOrientation) +{ + m_page->setOverrideOrientation(deviceOrientation); +} +#endif + void WebPage::flushDeferredDidReceiveMouseEvent() { if (auto info = std::exchange(m_deferredDidReceiveMouseEvent, std::nullopt)) @@ -4147,6 +4181,100 @@ void WebPage::touchEvent(const WebTouchEvent& touchEvent, CompletionHandler&& completionHandler) +{ + SetForScope userIsInteractingChange { m_userIsInteracting, true }; + + bool handled = false; + + uint32_t id = 0; + float radiusX = 1.0; + float radiusY = 1.0; + float rotationAngle = 0.0; + float force = 1.0; + const WebCore::DoubleSize radius(radiusX,radiusY); + const WebCore::DoublePoint screenPosition = position; + OptionSet eventModifiers; + eventModifiers = eventModifiers.fromRaw(modifiers); + + { + Vector touchPoints; + WebPlatformTouchPoint::State state = WebPlatformTouchPoint::State::Pressed; + touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force)); + + WebTouchEvent touchEvent({WebEventType::TouchStart, eventModifiers, MonotonicTime::now()}, WTF::move(touchPoints), {}, {}); + + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(m_page->mainFrame().frameID(), touchEvent, m_page.get()).value_or(false); + } + { + Vector touchPoints; + WebPlatformTouchPoint::State state = WebPlatformTouchPoint::State::Released; + touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force)); + + WebTouchEvent touchEvent({WebEventType::TouchEnd, eventModifiers, MonotonicTime::now()}, WTF::move(touchPoints), {}, {}); + + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(m_page->mainFrame().frameID(), touchEvent, m_page.get()).value_or(false) || handled; + } + if (!handled) { + FloatPoint adjustedPoint; + + auto* localMainFrame = dynamicDowncast(m_page->mainFrame()); + if (!localMainFrame) + return; + + RefPtr nodeRespondingToClick = localMainFrame->nodeRespondingToClickEvents(position, adjustedPoint); + Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr; + IntPoint adjustedIntPoint = roundedIntPoint(adjustedPoint); + if (!frameRespondingToClick) { + completionHandler(); + return; + } + double force = 0.0; + SyntheticClickType syntheticClickType = SyntheticClickType::OneFingerTap; + + auto modifiers = PlatformKeyboardEvent::currentStateOfModifierKeys(); + localMainFrame->eventHandler().mouseMoved(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::None, + PlatformEvent::Type::MouseMoved, + 0, + modifiers, + MonotonicTime::now(), + force, + syntheticClickType, + MouseEventInputSource::UserDriven + )); + localMainFrame->eventHandler().handleMousePressEvent(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::Left, + PlatformEvent::Type::MousePressed, + 1, + modifiers, + MonotonicTime::now(), + force, + syntheticClickType, + MouseEventInputSource::UserDriven + )); + localMainFrame->eventHandler().handleMouseReleaseEvent(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::Left, + PlatformEvent::Type::MouseReleased, + 1, + modifiers, + MonotonicTime::now(), + force, + syntheticClickType, + MouseEventInputSource::UserDriven + )); + } + completionHandler(); +} #endif void WebPage::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint) @@ -4247,6 +4375,16 @@ void WebPage::sendMessageToTargetBackend(const String& message) ensureInspectorTarget()->sendMessageToTargetBackend(message); } +void WebPage::resumeInspectorIfPausedInNewWindow() +{ + m_page->inspectorController().resumeIfPausedInNewWindow(); +} + +void WebPage::didAddWebPageToWebProcess() +{ + m_page->inspectorController().didFinishPageCreation(); +} + void WebPage::insertNewlineInQuotedContent() { RefPtr frame = corePage()->focusController().focusedOrMainFrame(); @@ -4489,6 +4627,7 @@ void WebPage::setMainFrameDocumentVisualUpdatesAllowed(bool allowed) void WebPage::show() { send(Messages::WebPageProxy::ShowPage()); + m_page->inspectorController().didShowPage(); } void WebPage::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension) @@ -5561,7 +5700,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana #if ENABLE(DRAG_SUPPORT) -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) void WebPage::performDragControllerAction(DragControllerAction action, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet draggingSourceOperationMask, SelectionData&& selectionData, OptionSet flags, CompletionHandler, DragHandlingMethod, bool, unsigned, IntRect, IntRect, std::optional)>&& completionHandler) { if (!m_page) @@ -7932,6 +8071,10 @@ void WebPage::didCommitLoad(WebFrame* frame) if (frame && frame->isMainFrame()) m_networkResourceRequestIdentifiersForPageLoadTiming.clear(); +// Playwright begin + if (frame->isMainFrame()) + send(Messages::WebPageProxy::ViewScaleFactorDidChange(viewScaleFactor())); +// Playwright end } void WebPage::didFinishDocumentLoad(WebFrame& frame) @@ -8234,6 +8377,9 @@ Ref WebPage::createDocumentLoader(LocalFrame& frame, ResourceReq m_allowsContentJavaScriptFromMostRecentNavigation = m_internals->pendingWebsitePolicies->allowsContentJavaScript; WebsitePoliciesData::applyToDocumentLoader(*std::exchange(m_internals->pendingWebsitePolicies, std::nullopt), documentLoader); } + } else if (m_pendingFrameNavigationID) { + documentLoader->setNavigationID(*m_pendingFrameNavigationID); + m_pendingFrameNavigationID = std::nullopt; } return documentLoader; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h index 122efe1deb60835d3b834995d672374bae5ad557..1e9ad7f9665bb9256b3036e1dcb471d2bbe0f081 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1403,11 +1404,11 @@ public: void clearSelection(); void restoreSelectionInFocusedEditableElement(); -#if ENABLE(DRAG_SUPPORT) && PLATFORM(GTK) +#if ENABLE(DRAG_SUPPORT) && (PLATFORM(GTK) || PLATFORM(WPE)) void performDragControllerAction(DragControllerAction, const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, OptionSet draggingSourceOperationMask, WebCore::SelectionData&&, OptionSet, CompletionHandler, WebCore::DragHandlingMethod, bool, unsigned, WebCore::IntRect, WebCore::IntRect, std::optional)>&&); #endif -#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) +#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) && !PLATFORM(WPE) void performDragControllerAction(std::optional, DragControllerAction, WebCore::DragData&&, CompletionHandler, WebCore::DragHandlingMethod, bool, unsigned, WebCore::IntRect, WebCore::IntRect, std::optional)>&&); void performDragOperation(std::optional, WebCore::DragData&&, SandboxExtension::Handle&&, Vector&&, CompletionHandler&&); #endif @@ -1425,6 +1426,9 @@ public: #if ENABLE(MODEL_PROCESS) void modelDragEnded(WebCore::NodeIdentifier); #endif +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_page->setDragPasteboardName(pasteboardName); } +#endif #endif #if ENABLE(MODEL_PROCESS) @@ -1526,8 +1530,11 @@ public: void gestureEvent(WebCore::FrameIdentifier, const WebGestureEvent&, CompletionHandler, bool, std::optional)>&&); #endif -#if PLATFORM(IOS_FAMILY) +#if ENABLE(ORIENTATION_EVENTS) void setDeviceOrientation(WebCore::IntDegrees); +#endif + +#if PLATFORM(IOS_FAMILY) void dynamicViewportSizeUpdate(const DynamicViewportSizeUpdate&); bool scaleWasSetByUIProcess() const { return m_scaleWasSetByUIProcess; } void willStartUserTriggeredZooming(); @@ -1688,6 +1695,8 @@ public: void connectInspector(Inspector::FrontendChannel::ConnectionType); void disconnectInspector(); void sendMessageToTargetBackend(const String& message); + void resumeInspectorIfPausedInNewWindow(); + void didAddWebPageToWebProcess(); void insertNewlineInQuotedContent(); @@ -2126,6 +2135,7 @@ public: void showContextMenuFromFrame(const FrameInfoData&, const ContextMenuContextData&, const UserData&); #endif void loadRequest(LoadParameters&&); + void loadRequestInFrameForInspector(LoadParameters&&, WebCore::FrameIdentifier); void setObscuredContentInsets(const WebCore::FloatBoxExtent&); @@ -2348,6 +2358,7 @@ private: void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled); #elif ENABLE(TOUCH_EVENTS) void touchEvent(const WebTouchEvent&, CompletionHandler, bool)>&&); + void fakeTouchTap(const WebCore::IntPoint& position, uint8_t modifiers, CompletionHandler&& completionHandler); #endif void cancelPointer(WebCore::PointerID, const WebCore::IntPoint&); @@ -3171,6 +3182,7 @@ private: bool m_isAppNapEnabled { true }; Markable m_pendingNavigationID; + Markable m_pendingFrameNavigationID; bool m_mainFrameProgressCompleted { false }; bool m_shouldDispatchFakeMouseMoveEvents { true }; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in index 7ae88ddd41930501d121e488a5e2d96693a87865..323373fdcb1c47583b05ced86bc96a9ff3080ed7 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in @@ -84,10 +84,13 @@ messages -> WebPage WantsAsyncDispatchMessage { CancelPotentialTap() #endif +#if ENABLE(ORIENTATION_EVENTS) + SetDeviceOrientation(WebCore::IntDegrees deviceOrientation) +#endif + #if PLATFORM(IOS_FAMILY) SetSceneIdentifier(String sceneIdentifier) SetViewportConfigurationViewLayoutSize(WebCore::FloatSize size, double scaleFactor, double minimumEffectiveDeviceWidth) - SetDeviceOrientation(WebCore::IntDegrees deviceOrientation) SetOverrideViewportArguments(struct std::optional arguments) DynamicViewportSizeUpdate(struct WebKit::DynamicViewportSizeUpdate target) @@ -174,6 +177,7 @@ messages -> WebPage WantsAsyncDispatchMessage { ConnectInspector(Inspector::FrontendChannel::ConnectionType connectionType) DisconnectInspector() SendMessageToTargetBackend(String message) + ResumeInspectorIfPausedInNewWindow(); #if ENABLE(REMOTE_INSPECTOR) SetIndicating(bool indicating); @@ -184,6 +188,7 @@ messages -> WebPage WantsAsyncDispatchMessage { #endif #if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS) TouchEvent(WebKit::WebTouchEvent event) -> (enum:uint32_t std::optional eventType, bool handled) + FakeTouchTap(WebCore::IntPoint position, uint8_t modifiers) -> () Async #endif CancelPointer(WebCore::PointerID pointerId, WebCore::IntPoint documentPoint) @@ -210,6 +215,7 @@ messages -> WebPage WantsAsyncDispatchMessage { LoadDataInFrame(std::span data, String MIMEType, String encodingName, URL baseURL, WebCore::FrameIdentifier frameID) LoadRequest(struct WebKit::LoadParameters loadParameters) LoadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, std::optional layerHostingContextIdentifier) + LoadRequestInFrameForInspector(struct WebKit::LoadParameters loadParameters, WebCore::FrameIdentifier frameID) LoadRequestWaitingForProcessLaunch(struct WebKit::LoadParameters loadParameters, URL resourceDirectoryURL, WebKit::WebPageProxyIdentifier pageID, bool checkAssumedReadAccessToResourceURL) LoadData(struct WebKit::LoadParameters loadParameters) LoadSimulatedRequestAndResponse(struct WebKit::LoadParameters loadParameters, WebCore::ResourceResponse simulatedResponse) @@ -376,10 +382,10 @@ messages -> WebPage WantsAsyncDispatchMessage { RemoveLayerForFindOverlay() -> () # Drag and drop. -#if PLATFORM(GTK) && ENABLE(DRAG_SUPPORT) +#if (PLATFORM(GTK) || PLATFORM(WPE)) && ENABLE(DRAG_SUPPORT) PerformDragControllerAction(enum:uint8_t WebKit::DragControllerAction action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet draggingSourceOperationMask, WebCore::SelectionData selection, OptionSet flags) -> (enum:uint8_t std::optional dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect, WebCore::IntRect editableElementRect, struct std::optional remoteUserInputEventData) #endif -#if !PLATFORM(GTK) && ENABLE(DRAG_SUPPORT) +#if !PLATFORM(GTK) && !PLATFORM(WPE) && ENABLE(DRAG_SUPPORT) PerformDragControllerAction(std::optional frameID, enum:uint8_t WebKit::DragControllerAction action, WebCore::DragData dragData) -> (enum:uint8_t std::optional dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect, WebCore::IntRect editableElementRect, struct std::optional remoteUserInputEventData) PerformDragOperation(std::optional frameID, WebCore::DragData dragData, WebKit::SandboxExtensionHandle sandboxExtensionHandle, Vector sandboxExtensionsForUpload) -> (WebKit::DragOperationResult dragOperationResult) #endif @@ -399,6 +405,10 @@ messages -> WebPage WantsAsyncDispatchMessage { ModelDragEnded(WebCore::NodeIdentifier nodeID) #endif +#if PLATFORM(MAC) && ENABLE(DRAG_SUPPORT) + SetDragPasteboardName(String pasteboardName) +#endif + #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT) RequestDragStart(std::optional remoteFrameID, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) -> (struct WebKit::DragInitiationResult result) RequestAdditionalItemsForDragSession(std::optional rootFrameID, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) -> (struct WebKit::DragInitiationResult result) diff --git a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp index 081c8dd9bc9402d909fba5359f90c686deb9987a..b9e548e8886861fa8013f5d8af1c893f5f4a3b99 100644 --- a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp +++ b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp @@ -224,16 +224,23 @@ String WebPage::platformUserAgent(const URL& url) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { + if (screenHasTouchDeviceOverride()) + return !screenHasTouchDeviceOverride().value(); return WebProcess::singleton().primaryPointingDevice() == AvailableInputDevices::Mouse; } bool WebPage::hoverSupportedByAnyAvailablePointingDevice() const { + if (screenHasTouchDeviceOverride()) + return !screenHasTouchDeviceOverride().value(); return WebProcess::singleton().availableInputDevices().contains(AvailableInputDevices::Mouse); } std::optional WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const { + if (screenHasTouchDeviceOverride() && screenHasTouchDeviceOverride().value()) + return PointerCharacteristics::Coarse; + const auto& primaryPointingDevice = WebProcess::singleton().primaryPointingDevice(); if (primaryPointingDevice == AvailableInputDevices::Mouse) return PointerCharacteristics::Fine; @@ -244,6 +251,9 @@ std::optional WebPage::pointerCharacteristicsOfPrimaryPo OptionSet WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const { + if (screenHasTouchDeviceOverride() && screenHasTouchDeviceOverride().value()) + return PointerCharacteristics::Coarse; + OptionSet pointerCharacteristics; const auto& availableInputs = WebProcess::singleton().availableInputDevices(); if (availableInputs.contains(AvailableInputDevices::Mouse)) diff --git a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm index 497cb8e358ace370d15803fda7c62bc51021e9e0..37a0f3a170729652cd74fd11d8e7e994c1305736 100644 --- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm +++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm @@ -732,21 +732,37 @@ String WebPage::platformUserAgent(const URL&) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenHasTouchDevice(); +#else return true; +#endif } bool WebPage::hoverSupportedByAnyAvailablePointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenHasTouchDevice(); +#else return true; +#endif } std::optional WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + if (screenHasTouchDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } OptionSet WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const { +#if ENABLE(TOUCH_EVENTS) + if (screenHasTouchDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } diff --git a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp index d32f7d2dd108647aeba05007a371b8c7381232a7..00da787b3ac4d312006a92475701c13366a1d740 100644 --- a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp +++ b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -83,21 +84,37 @@ String WebPage::platformUserAgent(const URL&) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenHasTouchDevice(); +#else return true; +#endif } bool WebPage::hoverSupportedByAnyAvailablePointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenHasTouchDevice(); +#else return true; +#endif } std::optional WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + if (screenHasTouchDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } OptionSet WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const { +#if ENABLE(TOUCH_EVENTS) + if (screenHasTouchDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp index 09651c68a3694eda504e88f3dda0cad5cd97a3c6..f4a0d15d58a30b4fa059659ba99bd4aa91ed327d 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp @@ -95,6 +95,7 @@ #include "WebsiteData.h" #include "WebsiteDataStoreParameters.h" #include "WebsiteDataType.h" +#include #include #include #include @@ -427,6 +428,14 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter { JSC::Options::AllowUnfinalizedAccessScope scope; JSC::Options::allowNonSPTagging() = false; + // Playwright begin + // SharedBufferArray is enabled only on Mac via XPC sercvice "enable-shared-array-buffer" option. + // For other platforms, enable it here. +#if !PLATFORM(COCOA) + if (parameters.shouldEnableSharedArrayBuffer) + JSC::Options::useSharedArrayBuffer() = true; +#endif + // Playwright end JSC::Options::notifyOptionsChanged(); } @@ -434,6 +443,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter platformInitializeProcess(parameters); updateCPULimit(); + + Inspector::IdentifiersFactory::initializeWithProcessID(parameters.processIdentifier->toUInt64()); } void WebProcess::initializeConnection(IPC::Connection* connection) @@ -1058,6 +1069,7 @@ void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters& m_hasPendingAccessibilityUnsuspension = false; accessibilityRelayProcessSuspended(false); } + page->didAddWebPageToWebProcess(); } Awaitable WebProcess::countWebPagesForTesting() diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm index ba7911b2efe2ffdde8ab90f3c81817f65a43b2f0..259418a4eca2bb6ed9af2a62fbda155849c2f349 100644 --- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm @@ -4207,7 +4207,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END _private->handlingMouseDownEvent = NO; } -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(IOS_TOUCH_EVENTS) - (void)touch:(WebEvent *)event { diff --git a/Source/WebKitLegacy/mac/WebView/WebView.mm b/Source/WebKitLegacy/mac/WebView/WebView.mm index bec7313812c922a7175d0f9aca27818066d54df8..8af7c061efe469493d5e2f38679b7038fb483c34 100644 --- a/Source/WebKitLegacy/mac/WebView/WebView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebView.mm @@ -3976,7 +3976,7 @@ + (void)_doNotStartObservingNetworkReachability } #endif // PLATFORM(IOS_FAMILY) -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(IOS_TOUCH_EVENTS) - (NSArray *)_touchEventRegions { @@ -4018,7 +4018,7 @@ - (NSArray *)_touchEventRegions }).autorelease(); } -#endif // ENABLE(TOUCH_EVENTS) +#endif // ENABLE(IOS_TOUCH_EVENTS) // For backwards compatibility with the WebBackForwardList API, we honor both // a per-WebView and a per-preferences setting for whether to use the back/forward cache. diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake index 1f1b576f84c8ad254868d8e2b2f4f0429ea59d06..11e5f0d982166f5f5c6e44984d48b912409cfff4 100644 --- a/Source/cmake/OptionsGTK.cmake +++ b/Source/cmake/OptionsGTK.cmake @@ -9,6 +9,10 @@ set(USER_AGENT_BRANDING "" CACHE STRING "Branding to add to user agent string") # Update Source/WTF/wtf/Platform.h to match required GLib versions. find_package(GLib 2.70.0 REQUIRED COMPONENTS GioUnix Thread Module) + +set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +set(THREADS_PREFER_PTHREAD_FLAG TRUE) + find_package(Cairo 1.16.0 REQUIRED) find_package(LibGcrypt 1.7.0 REQUIRED) find_package(Soup3 3.0.0 REQUIRED) @@ -72,6 +76,10 @@ WEBKIT_OPTION_DEFINE(USE_SYSTEM_UNIFDEF "Whether to use a system-provided unifde WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE) +# Playwright begin. +WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SYSTEM_SYSPROF_CAPTURE PRIVATE OFF) +# Playwright end. + SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) if (DEVELOPER_MODE) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_API_TESTS PRIVATE ON) @@ -150,6 +158,21 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SKIA PRIVATE ON) WEBKIT_OPTION_DEPEND(ENABLE_GPU_PROCESS USE_GBM) +# Playwright begin. +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_PDFJS PUBLIC OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_RECORDER PRIVATE OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_THUNDER PRIVATE OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR PRIVATE OFF) + +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_APPLICATION_MANIFEST PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CURSOR_VISIBILITY PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPEECH_SYNTHESIS PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_LOCK PRIVATE ON) +# Playwright end. + include(GStreamerDependencies) WEBKIT_OPTION_DEPEND(ENABLE_WEBXR ENABLE_GAMEPAD) diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 9be932f3cc9a86cc27ff355409f96a8e0501eba0..f89f186c5986a702b25bf844be36fbe293cbf43b 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -37,6 +37,9 @@ else () set(ENABLE_MEDIA_SESSION_DEFAULT ON) endif () +set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +set(THREADS_PREFER_PTHREAD_FLAG TRUE) + WEBKIT_OPTION_BEGIN() SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE}) @@ -94,6 +97,22 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR PRIVATE ${ENABLE_EXPERIMENTAL_FEAT WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR_HIT_TEST PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR_LAYERS PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) +# Playwright begin. +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MINIBROWSER PUBLIC ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_PDFJS PUBLIC OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_RECORDER PRIVATE OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_THUNDER PRIVATE OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR PRIVATE OFF) + +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_APPLICATION_MANIFEST PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CURSOR_VISIBILITY PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DARK_MODE_CSS PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DRAG_SUPPORT PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPEECH_SYNTHESIS PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_LOCK PRIVATE ON) +# Playwright end. + # Public options specific to the WPE port. Do not add any options here unless # there is a strong reason we should support changing the value of the option, # and the option is not relevant to other WebKit ports. @@ -132,6 +151,11 @@ WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATION ENABLE_INTROSPECTION) WEBKIT_OPTION_DEPEND(ENABLE_WPE_QT_API ENABLE_WPE_PLATFORM) WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE) +# Playwright begin. +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WPE_QT_API PUBLIC OFF) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SYSTEM_SYSPROF_CAPTURE PRIVATE OFF) +# Playwright end. + if (CMAKE_SYSTEM_NAME MATCHES "Linux") WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_BUBBLEWRAP_SANDBOX PUBLIC ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEMORY_SAMPLER PRIVATE ON) diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake index da6c3b5fd4901b64c616d2b38cb1d9b70c810e71..99380f834b6b3ac5b4afdf68dfa002c0cdf606d3 100644 --- a/Source/cmake/OptionsWin.cmake +++ b/Source/cmake/OptionsWin.cmake @@ -113,6 +113,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF) SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_KEYBOARD_INTERACTIONS ON) SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS ON) +# Plawright begin +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DARK_MODE_CSS PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NOTIFICATIONS PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_LOCK PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_TOUCH_EVENTS PRIVATE ON) +# Playwright end + WEBKIT_OPTION_END() set(USE_ANGLE_EGL ON) diff --git a/Source/cmake/WebKitCompilerFlags.cmake b/Source/cmake/WebKitCompilerFlags.cmake index 5a9e12cee71f979e15f686f89a9bec6d992a2faf..1a79d778c8a36050fc2b0b42388bb050fa612d49 100644 --- a/Source/cmake/WebKitCompilerFlags.cmake +++ b/Source/cmake/WebKitCompilerFlags.cmake @@ -152,7 +152,7 @@ macro(WEBKIT_ADD_TARGET_CXX_FLAGS _target) endmacro() -option(DEVELOPER_MODE_FATAL_WARNINGS "Build with warnings as errors if DEVELOPER_MODE is also enabled" ON) +option(DEVELOPER_MODE_FATAL_WARNINGS "Build with warnings as errors if DEVELOPER_MODE is also enabled" OFF) set(DEVELOPER_MODE_CXX_FLAGS) if (DEVELOPER_MODE AND DEVELOPER_MODE_FATAL_WARNINGS) if (MSVC) diff --git a/Tools/DumpRenderTree/DerivedSources.make b/Tools/DumpRenderTree/DerivedSources.make index e5859ed734046a3dc37a5c184e8a43fc9f858004..1235b8315d2ce5d6990474e525857770a7660e61 100644 --- a/Tools/DumpRenderTree/DerivedSources.make +++ b/Tools/DumpRenderTree/DerivedSources.make @@ -73,8 +73,8 @@ $(IDL_FILE_NAMES_LIST) : $(UICONTEXT_INTERFACES:%=%.idl) JS%.h JS%.cpp : %.idl $(SCRIPTS) $(IDL_ATTRIBUTES_FILE) $(IDL_FILE_NAMES_LIST) $(FEATURE_AND_PLATFORM_FLAGS_RESPONSE_FILE) @echo Generating bindings for $*... $(PERL) -I $(WebCoreScripts) -I $(UISCRIPTCONTEXT_DIR) -I $(DumpRenderTree)/Bindings $(WebCoreScripts)/generate-bindings.pl --defines "$(FEATURE_AND_PLATFORM_DEFINES)" --idlFileNamesList $(IDL_FILE_NAMES_LIST) --outputDir . --generator DumpRenderTree --idlAttributesFile $(IDL_ATTRIBUTES_FILE) $< -# +# WEB_PREFERENCES_GENERATED_FILES = \ TestOptionsGeneratedWebKitLegacyKeyMapping.cpp \ diff --git a/Tools/MiniBrowser/gtk/BrowserTab.c b/Tools/MiniBrowser/gtk/BrowserTab.c index 0e7f9c7bb7ccb52ccb579ff464a5904aaab2baed..65999b8d7c2dfd1aecc58fe93504aa9cb6965dd8 100644 --- a/Tools/MiniBrowser/gtk/BrowserTab.c +++ b/Tools/MiniBrowser/gtk/BrowserTab.c @@ -118,19 +118,38 @@ static void isLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, Brow } } +static gboolean response_policy_decision_can_show(WebKitResponsePolicyDecision *responseDecision) +{ + if (webkit_response_policy_decision_is_mime_type_supported(responseDecision)) + return TRUE; + WebKitURIResponse* response = webkit_response_policy_decision_get_response(responseDecision); + const guint statusCode = webkit_uri_response_get_status_code(response); + if (statusCode == 205 || statusCode == 204) + return TRUE; + const gchar* mimeType = webkit_uri_response_get_mime_type(response); + if (!mimeType || mimeType[0] == '\0') + return FALSE; + // https://bugs.webkit.org/show_bug.cgi?id=277204 / Ubuntu 24.04 / glib 2.76+ or higher + if (g_ascii_strcasecmp(mimeType, "application/x-zerosize") == 0) + return TRUE; + return FALSE; +} + static gboolean decidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserTab *tab) { if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE) return FALSE; WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision); - if (webkit_response_policy_decision_is_mime_type_supported(responseDecision)) - return FALSE; - if (!webkit_response_policy_decision_is_main_frame_main_resource(responseDecision)) return FALSE; - webkit_policy_decision_download(decision); + if (!response_policy_decision_can_show(responseDecision)) { + webkit_policy_decision_download(decision); + return TRUE; + } + + webkit_policy_decision_use(decision); return TRUE; } @@ -181,6 +200,11 @@ static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, Brows #endif } +static gboolean loadFailed() +{ + return TRUE; +} + static GtkWidget *createInfoBarQuestionMessage(const char *title, const char *text) { GtkWidget *dialog = gtk_info_bar_new_with_buttons("No", GTK_RESPONSE_NO, "Yes", GTK_RESPONSE_YES, NULL); @@ -806,6 +830,7 @@ static void browserTabConstructed(GObject *gObject) g_signal_connect(tab->webView, "notify::is-loading", G_CALLBACK(isLoadingChanged), tab); g_signal_connect(tab->webView, "decide-policy", G_CALLBACK(decidePolicy), tab); g_signal_connect(tab->webView, "load-changed", G_CALLBACK(loadChanged), tab); + g_signal_connect(tab->webView, "load-failed", G_CALLBACK(loadFailed), tab); g_signal_connect(tab->webView, "load-failed-with-tls-errors", G_CALLBACK(loadFailedWithTLSerrors), tab); g_signal_connect(tab->webView, "permission-request", G_CALLBACK(decidePermissionRequest), tab); g_signal_connect(tab->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), tab); @@ -861,6 +886,9 @@ static char *getInternalURI(const char *uri) if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank")) return g_strconcat(BROWSER_ABOUT_SCHEME, uri + strlen ("about"), NULL); + if (!g_str_has_prefix(uri, "http://") && !g_str_has_prefix(uri, "https://") && !g_str_has_prefix(uri, "file://")) + return g_strconcat("http://", uri, NULL); + return g_strdup(uri); } diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.c b/Tools/MiniBrowser/gtk/BrowserWindow.c index d39b809a879babcdbbf4b5f7687204df5ccc43f3..a784ea4e693332aee731c4b8949ddb33af7dff9f 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.c +++ b/Tools/MiniBrowser/gtk/BrowserWindow.c @@ -73,7 +73,7 @@ struct _BrowserWindowClass { GtkApplicationWindowClass parent; }; -static const char *defaultWindowTitle = "WebKitGTK MiniBrowser"; +static const char *defaultWindowTitle = "🎭 Playwright"; static const gdouble minimumZoomLevel = 0.5; static const gdouble maximumZoomLevel = 3; static const gdouble defaultZoomLevel = 1; @@ -157,17 +157,11 @@ static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, Browser static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window) { const char *title = webkit_web_view_get_title(webView); + char *privateTitle = NULL; if (!title) title = defaultWindowTitle; - char *privateTitle = NULL; - if (webkit_web_view_is_controlled_by_automation(webView)) - privateTitle = g_strdup_printf("[Automation] %s", title); -#if GTK_CHECK_VERSION(3, 98, 0) - else if (webkit_network_session_is_ephemeral(webkit_web_view_get_network_session(webView))) -#else - else if (webkit_web_view_is_ephemeral(webView)) -#endif - privateTitle = g_strdup_printf("[Private] %s", title); + else + privateTitle = g_strdup_printf("🎭 Playwright: %s", title); gtk_window_set_title(GTK_WINDOW(window), privateTitle ? privateTitle : title); g_free(privateTitle); } @@ -524,8 +518,12 @@ static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision return FALSE; WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision)); - if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED - || webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE) + if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) + return FALSE; + + guint modifiers = webkit_navigation_action_get_modifiers(navigationAction); + if (webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE && + (webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_PRIMARY || (modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == 0)) return FALSE; /* Multiple tabs are not allowed in editor mode. */ @@ -1502,6 +1500,20 @@ static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event) } #endif +static void zero_widget_measure (GtkWidget *widget, + GtkOrientation orientation, + int for_size, + int *minimum_size, + int *natural_size, + int *minimum_baseline, + int *natural_baseline) +{ + *minimum_size = 10; + *natural_size = 10; + // *minimum_baseline = 10; + // *natural_baseline = 10; +} + static void browser_window_class_init(BrowserWindowClass *klass) { GObjectClass *gobjectClass = G_OBJECT_CLASS(klass); @@ -1515,6 +1527,13 @@ static void browser_window_class_init(BrowserWindowClass *klass) GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass); widgetClass->delete_event = browserWindowDeleteEvent; #endif + +// Playwrigth begin +// Override preferred (which is minimum :-) size to 0 so that we can +// emulate arbitrary resolution. + GtkWidgetClass* browserWidgetClass = GTK_WIDGET_CLASS(klass); + browserWidgetClass->measure = zero_widget_measure; +// Playwrigth end } /* Public API. */ diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.h b/Tools/MiniBrowser/gtk/BrowserWindow.h index 1fd07efb828b85b6d8def6c6cd92a0c11debfe1b..da9fac7975d477857ead2adb1d67108d51716d15 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.h +++ b/Tools/MiniBrowser/gtk/BrowserWindow.h @@ -42,7 +42,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 dc20509081346978e0da4a7833f6d4ce733717ac..817bd32756f0c8279beb4c23bee4b1e6f2ded960 100644 --- a/Tools/MiniBrowser/gtk/main.c +++ b/Tools/MiniBrowser/gtk/main.c @@ -66,9 +66,15 @@ static char* timeZone; static gboolean enableITP; static gboolean exitAfterLoad; static gboolean webProcessCrashed; +static gboolean inspectorPipe; +static gint remoteDebuggingPort = -1; +static gboolean headless; +static gboolean noStartupWindow; +static const char *userDataDir; static gboolean printVersion; static char *configFile; static GSettings *interfaceSettings; +static GtkApplication *browserApplication = NULL; #if !GTK_CHECK_VERSION(3, 98, 0) static gboolean enableSandbox; @@ -174,6 +180,11 @@ static const GOptionEntry commandLineOptions[] = { "time-zone", 't', 0, G_OPTION_ARG_STRING, &timeZone, "Set time zone", "TIMEZONE" }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WebKitGTK version", NULL }, { "config", 'C', 0, G_OPTION_ARG_FILENAME, &configFile, "Path to a configuration file", "PATH" }, + { "inspector-pipe", 0, 0, G_OPTION_ARG_NONE, &inspectorPipe, "Open pipe connection to the remote inspector", NULL }, + { "remote-debugging-port", 0, 0, G_OPTION_ARG_INT, &remoteDebuggingPort, "Start remote debugging server on the specified port", NULL }, + { "user-data-dir", 0, 0, G_OPTION_ARG_STRING, &userDataDir, "Default profile persistence folder location", NULL }, + { "headless", 0, 0, G_OPTION_ARG_NONE, &headless, "Noop headless operation", NULL }, + { "no-startup-window", 0, 0, G_OPTION_ARG_NONE, &noStartupWindow, "Do not open default page", NULL }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" }, { 0, 0, 0, 0, 0, 0, 0 } }; @@ -730,6 +741,64 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } +static WebKitSettings* createPlaywrightSettings() { + WebKitSettings* webkitSettings = webkit_settings_new(); + // FIXME(Playwright): in GTK4, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS is the default, but the page content is just black in that case. + webkit_settings_set_hardware_acceleration_policy(webkitSettings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER); + return webkitSettings; +} + +static WebKitWebContext *persistentWebContext = NULL; + +static WebKitWebView *createNewPage(WebKitBrowserInspector *browser_inspector, WebKitWebContext *context) +{ + if (context == NULL) + context = persistentWebContext; + + WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "web-context", context, + "settings", createPlaywrightSettings(), + "network-session", webkit_web_context_get_network_session_for_automation(context), + "is-controlled-by-automation", TRUE, + NULL)); + GtkWidget *newWindow = browser_window_new(NULL, context, webkit_web_context_get_network_session_for_automation(context)); + gtk_window_set_application(GTK_WINDOW(newWindow), browserApplication); + 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 quitBroserApplication(WebKitBrowserInspector* browser_inspector) +{ + g_application_release(G_APPLICATION(browserApplication)); +} + +static void keepApplicationAliveUntilQuit(GApplication *application) +{ + // Reference the application, it will be released in quitBroserApplication. + g_application_hold(application); + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "quit-application", G_CALLBACK(quitBroserApplication), NULL); +} + +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(proxy, ignoreHosts); +} + +static void configureBrowserInspectorPort() +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + + webkit_browser_inspector_initialize_web_socket(remoteDebuggingPort, proxy, ignoreHosts); +} + static void startup(GApplication *application) { const char *actionAccels[] = { @@ -788,22 +857,39 @@ static void setupDarkMode(GtkSettings *settings) static void activate(GApplication *application, WebKitSettings *webkitSettings) { + if (inspectorPipe) + configureBrowserInspectorPipe(); + else if (remoteDebuggingPort != -1) + configureBrowserInspectorPort(); + + if (noStartupWindow) { + keepApplicationAliveUntilQuit(application); + g_clear_object(&webkitSettings); + return; + } #if GTK_CHECK_VERSION(3, 98, 0) WebKitWebContext *webContext = g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "time-zone-override", timeZone, NULL); webkit_web_context_set_automation_allowed(webContext, automationMode); g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), application); WebKitNetworkSession *networkSession; - if (automationMode) - networkSession = g_object_ref(webkit_web_context_get_network_session_for_automation(webContext)); - else if (privateMode) + if (userDataDir) { + char *dataDirectory = g_build_filename(userDataDir, "data", NULL); + char *cacheDirectory = g_build_filename(userDataDir, "cache", NULL); + networkSession = webkit_network_session_new(dataDirectory, cacheDirectory); + g_free(dataDirectory); + g_free(cacheDirectory); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL); + } else if (inspectorPipe || remoteDebuggingPort != -1 || privateMode || automationMode) { networkSession = webkit_network_session_new_ephemeral(); - else { + } else { g_autofree char *dataDirectory = profileDirectory ? g_build_filename(profileDirectory, "data", NULL) : g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); g_autofree char *cacheDirectory = profileDirectory ? g_build_filename(profileDirectory, "cache", NULL) : g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); networkSession = webkit_network_session_new(dataDirectory, cacheDirectory); } + webkit_web_context_set_network_session_for_automation(webContext, networkSession); + webkit_network_session_set_itp_enabled(networkSession, enableITP); if (!automationMode) { @@ -838,9 +924,12 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) } #else WebKitWebsiteDataManager *manager; - if (privateMode || automationMode) + if (userDataDir) { + manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL); + } else if (inspectorPipe || remoteDebuggingPort != -1 || privateMode || automationMode) { manager = webkit_website_data_manager_new_ephemeral(); - else { + } else { g_autofree char *dataDirectory = profileDirectory ? g_build_filename(profileDirectory, "data", NULL) : g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); g_autofree char *cacheDirectory = profileDirectory ? g_build_filename(profileDirectory, "cache", NULL) : g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); manager = webkit_website_data_manager_new("base-data-directory", dataDirectory, "base-cache-directory", cacheDirectory, NULL); @@ -888,6 +977,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) // Enable the favicon database. webkit_web_context_set_favicon_database_directory(webContext, NULL); #endif + persistentWebContext = webContext; webkit_web_context_register_uri_scheme(webContext, BROWSER_ABOUT_SCHEME, (WebKitURISchemeRequestCallback)aboutURISchemeRequestCallback, NULL, NULL); @@ -952,9 +1042,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) if (exitAfterLoad) exitAfterWebViewLoadFinishes(webView, application); } - gchar *url = argumentToURL(uriArguments[i]); - webkit_web_view_load_uri(webView, url); - g_free(url); + webkit_web_view_load_uri(webView, uriArguments[i]); } } else { WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings, userContentManager, defaultWebsitePolicies); @@ -1004,7 +1092,7 @@ int main(int argc, char *argv[]) g_option_context_add_group(context, gst_init_get_option_group()); #endif - WebKitSettings *webkitSettings = webkit_settings_new(); + WebKitSettings *webkitSettings = createPlaywrightSettings(); webkit_settings_set_enable_developer_extras(webkitSettings, TRUE); webkit_settings_set_enable_webgl(webkitSettings, TRUE); webkit_settings_set_enable_media_stream(webkitSettings, TRUE); @@ -1056,9 +1144,11 @@ int main(int argc, char *argv[]) } GtkApplication *application = gtk_application_new("org.webkitgtk.MiniBrowser", G_APPLICATION_NON_UNIQUE); + browserApplication = application; g_signal_connect(application, "startup", G_CALLBACK(startup), NULL); g_signal_connect(application, "activate", G_CALLBACK(activate), webkitSettings); g_application_run(G_APPLICATION(application), 0, NULL); + browserApplication = NULL; g_object_unref(application); g_clear_object(&interfaceSettings); diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp index c8cd8719368bc3be7b97b315c64162ced5b7c351..7a7b2d3b0ebc31690f5877694118ddfc311ee5cf 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp @@ -56,6 +56,9 @@ static gboolean privateMode; static const char* profileDirectory; static gboolean automationMode; static gboolean ignoreTLSErrors; +static gboolean inspectorPipe; +static gboolean noStartupWindow; +static const char* userDataDir; static const char* contentFilter; static const char* cookiesFile; static const char* cookiesPolicy; @@ -141,6 +144,9 @@ static const GOptionEntry commandLineOptions[] = { "config-file", 0, 0, G_OPTION_ARG_FILENAME, &configFile, "Config file to load for settings", "FILE" }, { "size", 's', 0, G_OPTION_ARG_CALLBACK, reinterpret_cast(parseWindowSize), "Specify the window size to use, e.g. --size=\"800x600\"", nullptr }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WPE version", nullptr }, + { "inspector-pipe", 'v', 0, G_OPTION_ARG_NONE, &inspectorPipe, "Expose remote debugging protocol over pipe", nullptr }, + { "user-data-dir", 0, 0, G_OPTION_ARG_STRING, &userDataDir, "Default profile persistence folder location", "FILE" }, + { "no-startup-window", 0, 0, G_OPTION_ARG_NONE, &noStartupWindow, "Do not open default page", nullptr }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, nullptr, "[URL]" }, { nullptr, 0, 0, G_OPTION_ARG_NONE, nullptr, nullptr, nullptr } }; @@ -331,15 +337,38 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } +static gboolean webViewLoadFailed() +{ + return TRUE; +} + static void webViewClose(WebKitWebView* webView, gpointer user_data) { // Hash table key delete func takes care of unref'ing the view g_hash_table_remove(openViews, webView); - if (!g_hash_table_size(openViews)) + if (!g_hash_table_size(openViews) && user_data) g_application_quit(G_APPLICATION(user_data)); } -static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data) +static gboolean scriptDialog(WebKitWebView*, WebKitScriptDialog* dialog, gpointer) +{ + if (inspectorPipe) + webkit_script_dialog_ref(dialog); + return TRUE; +} + +static gboolean scriptDialogHandled(WebKitWebView*, WebKitScriptDialog* dialog, gpointer) +{ + if (inspectorPipe) + webkit_script_dialog_unref(dialog); + return TRUE; +} + +static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, gpointer); + +static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data); + +static WebKitWebView* createWebViewImpl(WebKitWebView* webView, WebKitWebContext *webContext, gpointer user_data) { #if defined(USE_LIBWPE) && USE_LIBWPE auto backend = createViewBackend(defaultWindowWidthLegacyAPI, defaultWindowHeightLegacyAPI); @@ -356,14 +385,31 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi } #endif - auto* newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, +// Playwright begin + if (headlessMode) { + webkit_web_view_backend_set_screenshot_callback(viewBackend, + [](gpointer data) { + return static_cast(data)->snapshot(); + }); + } +// Playwright end + WebKitWebView* newWebView; + if (webView) { + newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, #if defined(USE_LIBWPE) && USE_LIBWPE - "backend", viewBackend, + "backend", viewBackend, #endif - "related-view", webView, - "settings", webkit_web_view_get_settings(webView), - "user-content-manager", webkit_web_view_get_user_content_manager(webView), - nullptr)); + "related-view", webView, + nullptr)); + } else { + newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, +#if defined(USE_LIBWPE) && USE_LIBWPE + "backend", viewBackend, +#endif + "web-context", webContext, + "is-controlled-by-automation", TRUE, + nullptr)); + } #if ENABLE_WPE_PLATFORM if (auto* wpeView = webkit_web_view_get_wpe_view(newWebView)) { @@ -375,9 +421,13 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi g_signal_connect(newWebView, "create", G_CALLBACK(createWebView), user_data); g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), user_data); - +// Playwright begin + g_signal_connect(newWebView, "load-failed", G_CALLBACK(webViewLoadFailed), nullptr); + g_signal_connect(newWebView, "script-dialog", G_CALLBACK(scriptDialog), nullptr); + g_signal_connect(newWebView, "script-dialog-handled", G_CALLBACK(scriptDialogHandled), nullptr); + g_signal_connect(newWebView, "decide-policy", G_CALLBACK(webViewDecidePolicy), nullptr); +// Playwright end g_hash_table_add(openViews, newWebView); - return newWebView; } @@ -468,24 +518,112 @@ static void loadConfigFile(WebKitSettings* webkitSettings } #if defined(USE_LIBWPE) && USE_LIBWPE +static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data) +{ + return createWebViewImpl(webView, nullptr, user_data); +} + +inline bool response_policy_decision_can_show(WebKitResponsePolicyDecision* responseDecision) +{ + if (webkit_response_policy_decision_is_mime_type_supported(responseDecision)) + return true; + auto response = webkit_response_policy_decision_get_response(responseDecision); + const auto statusCode = webkit_uri_response_get_status_code(response); + if (statusCode == 205 || statusCode == 204) + return true; + const gchar* mimeType = webkit_uri_response_get_mime_type(response); + if (!mimeType || mimeType[0] == '\0') + return false; + // https://bugs.webkit.org/show_bug.cgi?id=277204 / Ubuntu 24.04 / glib 2.76+ or higher + if (g_ascii_strcasecmp(mimeType, "application/x-zerosize") == 0) + return true; + return false; +} + +static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, gpointer user_data) +{ + if (decisionType == WEBKIT_POLICY_DECISION_TYPE_RESPONSE) { + WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision); + if (!webkit_response_policy_decision_is_main_frame_main_resource(responseDecision)) + return FALSE; + + if (!response_policy_decision_can_show(responseDecision)) { + webkit_policy_decision_download(decision); + return TRUE; + } + + webkit_policy_decision_use(decision); + return TRUE; + } + + if (decisionType != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) + return FALSE; + + WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision)); + if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) + return FALSE; + + guint modifiers = webkit_navigation_action_get_modifiers(navigationAction); + if (webkit_navigation_action_get_mouse_button(navigationAction) != 2 /* GDK_BUTTON_MIDDLE */ && + (webkit_navigation_action_get_mouse_button(navigationAction) != 1 /* GDK_BUTTON_PRIMARY */ || (modifiers & (wpe_input_keyboard_modifier_control | wpe_input_keyboard_modifier_shift)) == 0)) + return FALSE; + + /* Open a new tab if link clicked with the middle button, shift+click or ctrl+click. */ + WebKitWebView* newWebView = createWebViewImpl(nullptr, webkit_web_view_get_context(webView), user_data); + webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction)); + + webkit_policy_decision_ignore(decision); + return TRUE; +} + +static WebKitWebContext *persistentWebContext = NULL; + +static WebKitWebView* createNewPage(WebKitBrowserInspector*, WebKitWebContext *webContext) +{ + if (!webContext) + webContext = persistentWebContext; + WebKitWebView* webView = createWebViewImpl(nullptr, webContext, nullptr); + webkit_web_view_load_uri(webView, "about:blank"); + return webView; +} + +static void quitBroserApplication(WebKitBrowserInspector*, gpointer data) +{ + GApplication* application = static_cast(data); + g_application_quit(application); +} + +static void configureBrowserInspector(GApplication* application) +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + g_signal_connect(browserInspector, "quit-application", G_CALLBACK(quitBroserApplication), application); + webkit_browser_inspector_initialize_pipe(proxy, ignoreHosts); +} + static void activate(GApplication* application, WPEToolingBackends::ViewBackend* backend) #else static void activate(GApplication* application, gpointer) #endif { g_application_hold(application); + if (noStartupWindow) + return; #if ENABLE_2022_GLIB_API WebKitNetworkSession* networkSession = nullptr; if (!automationMode) { - if (privateMode) + if (userDataDir) { + networkSession = webkit_network_session_new(userDataDir, userDataDir); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", nullptr); + } else if (inspectorPipe || privateMode || automationMode) { networkSession = webkit_network_session_new_ephemeral(); - else if (profileDirectory) { + } else if (profileDirectory) { g_autofree char* dataDirectory = g_build_filename(profileDirectory, "data", nullptr); g_autofree char* cacheDirectory = g_build_filename(profileDirectory, "cache", nullptr); networkSession = webkit_network_session_new(dataDirectory, cacheDirectory); - } else + } else { networkSession = webkit_network_session_new(nullptr, nullptr); - + } webkit_network_session_set_itp_enabled(networkSession, enableITP); if (proxy) { @@ -512,19 +650,22 @@ static void activate(GApplication* application, gpointer) webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesFile, storageType); } } - auto* webContext = WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "time-zone-override", timeZone, nullptr)); + webkit_web_context_set_network_session_for_automation(webContext, networkSession); #else - WebKitWebsiteDataManager* manager; - if (privateMode || automationMode) + WebKitWebsiteDataManager *manager; + if (userDataDir) { + manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL); + } else if (inspectorPipe || privateMode || automationMode) { manager = webkit_website_data_manager_new_ephemeral(); - else if (profileDirectory) { + } else if (profileDirectory) { g_autofree char* dataDirectory = g_build_filename(profileDirectory, "data", nullptr); g_autofree char* cacheDirectory = g_build_filename(profileDirectory, "cache", nullptr); webkit_website_data_manager_new("base-data-directory", dataDirectory, "base-cache-directory", cacheDirectory, nullptr); - } else - webkit_website_data_manager_new(nullptr); - + } else { + manager = webkit_website_data_manager_new(NULL); + } webkit_website_data_manager_set_itp_enabled(manager, enableITP); if (proxy) { @@ -555,6 +696,7 @@ static void activate(GApplication* application, gpointer) } #endif + persistentWebContext = webContext; g_autoptr(WebKitUserContentManager) userContentManager = nullptr; if (contentFilter) { g_autoptr(GFile) contentFilterFile = g_file_new_for_commandline_arg(contentFilter); @@ -637,6 +779,15 @@ static void activate(GApplication* application, gpointer) "autoplay", WEBKIT_AUTOPLAY_ALLOW, nullptr); +// Playwright begin + if (headlessMode) { + webkit_web_view_backend_set_screenshot_callback(viewBackend, + [](gpointer data) { + return static_cast(data)->snapshot(); + }); + } +// Playwright end + auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, #if defined(USE_LIBWPE) && USE_LIBWPE "backend", viewBackend, @@ -699,12 +850,16 @@ static void activate(GApplication* application, gpointer) #endif } - openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr); - g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), webView); g_signal_connect(webView, "permission-request", G_CALLBACK(decidePermissionRequest), nullptr); g_signal_connect(webView, "create", G_CALLBACK(createWebView), application); g_signal_connect(webView, "close", G_CALLBACK(webViewClose), application); +// Playwright begin + g_signal_connect(webView, "load-failed", G_CALLBACK(webViewLoadFailed), nullptr); + g_signal_connect(webView, "script-dialog", G_CALLBACK(scriptDialog), nullptr); + g_signal_connect(webView, "script-dialog-handled", G_CALLBACK(scriptDialogHandled), nullptr); + g_signal_connect(webView, "decide-policy", G_CALLBACK(webViewDecidePolicy), nullptr); +// Playwright end g_hash_table_add(openViews, webView); WebKitColor color; @@ -712,16 +867,11 @@ static void activate(GApplication* application, gpointer) webkit_web_view_set_background_color(webView, &color); if (uriArguments) { - const char* uri = uriArguments[0]; - if (g_str_equal(uri, "about:gpu")) - uri = "webkit://gpu"; - - GFile* file = g_file_new_for_commandline_arg(uri); - char* url = g_file_get_uri(file); - g_object_unref(file); - webkit_web_view_load_uri(webView, url); - g_free(url); - } else if (!automationMode) + // Playwright: avoid weird url transformation like http://trac.webkit.org/r240840 + webkit_web_view_load_uri(webView, uriArguments[0]); + } else if (automationMode || inspectorPipe) + webkit_web_view_load_uri(webView, "about:blank"); + else webkit_web_view_load_uri(webView, "https://wpewebkit.org"); g_object_unref(webContext); @@ -816,12 +966,18 @@ int main(int argc, char *argv[]) } #endif + openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr); + GApplication* application = g_application_new("org.wpewebkit.MiniBrowser", G_APPLICATION_NON_UNIQUE); #if defined(USE_LIBWPE) && USE_LIBWPE g_signal_connect(application, "activate", G_CALLBACK(activate), backend.release()); #else g_signal_connect(application, "activate", G_CALLBACK(activate), nullptr); #endif + + if (inspectorPipe) + configureBrowserInspector(application); + g_application_run(application, 0, nullptr); g_object_unref(application); diff --git a/Tools/PlatformWin.cmake b/Tools/PlatformWin.cmake index 1067b31bc989748dfcc5502209d36d001b9b239e..7629263fb8bc93dca6dfc01c75eed8d2921fce1f 100644 --- a/Tools/PlatformWin.cmake +++ b/Tools/PlatformWin.cmake @@ -1,3 +1,7 @@ if (ENABLE_MINIBROWSER) add_subdirectory(MiniBrowser/win) endif () + +if (ENABLE_WEBKIT) + add_subdirectory(Playwright/win) +endif () diff --git a/Tools/Scripts/generate-bundle b/Tools/Scripts/generate-bundle index 2050bc1c4e2f94461cfe25dbc53762afdc6b9f53..cd43f62318d661bf2558a1b8005f37de19eb0f15 100755 --- a/Tools/Scripts/generate-bundle +++ b/Tools/Scripts/generate-bundle @@ -41,7 +41,6 @@ sys.path.insert(0, os.path.join(top_level_directory, 'Tools', 'flatpak')) sys.path.insert(0, os.path.join(top_level_directory, 'Tools', 'jhbuild')) sys.path.insert(0, os.path.join(top_level_directory, 'Tools', 'Scripts', 'webkitpy')) import jhbuildutils -import flatpakutils from binary_bundling.ldd import SharedObjectResolver from binary_bundling.bundle import BinaryBundler @@ -896,7 +895,7 @@ class BundleCreator(object): _log.info('Copy basic GTK icons.') icons_target_dir = os.path.join(target_sys_share_dir, 'icons') os.makedirs(icons_target_dir) - gtk_icon_basedir = '/run/host/share/icons' if flatpakutils.is_sandboxed() else '/usr/share/icons' + gtk_icon_basedir = '/usr/share/icons' gtk_target_icon_dir = os.path.join(icons_target_dir, 'hicolor') gtk_icon_dirs_copied = 0 for gtk_icon_theme in ['Adwaita', 'hicolor', 'gnome']: @@ -975,9 +974,7 @@ def main(): parser.add_argument('--builder-name', action='store', dest='builder_name') options = parser.parse_args() - flatpakutils.run_in_sandbox_if_available([sys.argv[0], '--flatpak-' + options.platform] + sys.argv[1:]) - if not flatpakutils.is_sandboxed(): - jhbuildutils.enter_jhbuild_environment_if_available(options.platform) + jhbuildutils.enter_jhbuild_environment_if_available(options.platform) configure_logging(options.log_level) bundle_creator = BundleCreator(options.configuration, options.platform, options.bundle_binary, options.syslibs, options.ldd, diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt index ba703658cf8c56ad1768333b70938e67e8b36777..804487a7082024733d5012dcc62b9784c268bb55 100644 --- a/Tools/WebKitTestRunner/CMakeLists.txt +++ b/Tools/WebKitTestRunner/CMakeLists.txt @@ -99,6 +99,10 @@ set(TestRunnerInjectedBundle_PRIVATE_LIBRARIES ) set(TestRunnerInjectedBundle_FRAMEWORKS ${WebKitTestRunner_FRAMEWORKS}) +if (NOT USE_SYSTEM_MALLOC) + list(APPEND WebKitTestRunnerInjectedBundle_LIBRARIES bmalloc) +endif () + set(TestRunnerInjectedBundle_IDL_FILES "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityController.idl" "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityTextMarker.idl" diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 9a61e6421c74f12bc565fad0f706cbb246bb784f..0a2bf450b5577c39c8e3645205d9e6f3ff470d93 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -792,6 +792,7 @@ PlatformWebView* TestController::createOtherPlatformWebView(PlatformWebView* par nullptr, // requestStorageAccessConfirm nullptr, // shouldAllowDeviceOrientationAndMotionAccess nullptr, // runWebAuthenticationPanel + 0, // handleJavaScriptDialog nullptr, // decidePolicyForSpeechRecognitionPermissionRequest nullptr, // decidePolicyForMediaKeySystemPermissionRequest nullptr, // queryPermission @@ -1272,6 +1273,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options) nullptr, // requestStorageAccessConfirm shouldAllowDeviceOrientationAndMotionAccess, runWebAuthenticationPanel, + 0, // handleJavaScriptDialog nullptr, // decidePolicyForSpeechRecognitionPermissionRequest decidePolicyForMediaKeySystemPermissionRequest, queryPermission, diff --git a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm index 12a89be783e49c44edfca8d27f1fc3ddd24255e9..2ba827c958fa3558b0cd36f9e5b7537493fef362 100644 --- a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm +++ b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm @@ -1031,4 +1031,51 @@ void EventSenderProxy::scaleGestureEnd(double scale) #endif // ENABLE(MAC_GESTURE_EVENTS) +#if ENABLE(TOUCH_EVENTS) +void EventSenderProxy::addTouchPoint(int, int) +{ +} + +void EventSenderProxy::updateTouchPoint(int, int, int) +{ +} + +void EventSenderProxy::touchStart() +{ +} + +void EventSenderProxy::touchMove() +{ +} + +void EventSenderProxy::touchEnd() +{ +} + +void EventSenderProxy::touchCancel() +{ +} + +void EventSenderProxy::clearTouchPoints() +{ +} + +void EventSenderProxy::releaseTouchPoint(int) +{ +} + +void EventSenderProxy::cancelTouchPoint(int) +{ +} + +void EventSenderProxy::setTouchPointRadius(int, int) +{ +} + +void EventSenderProxy::setTouchModifier(WKEventModifiers, bool) +{ +} +#endif // ENABLE(TOUCH_EVENTS) + + } // namespace WTR diff --git a/Tools/jhbuild/jhbuild-minimal.modules b/Tools/jhbuild/jhbuild-minimal.modules index d526231f288ca82f4928d75ee9847b919b72bbfb..c904fac94196a8eb9888abf83b0db5ab69b3a993 100644 --- a/Tools/jhbuild/jhbuild-minimal.modules +++ b/Tools/jhbuild/jhbuild-minimal.modules @@ -69,8 +69,8 @@ + version="1.16.0" + hash="sha256:c7f3a3c6b3d006790d486dc7cceda2b6d2e329de07f33bc47dfc53f00f334b2a"/> @@ -79,8 +79,8 @@ + version="1.14.3" + hash="sha256:10121842595a850291db3e82f3db0b9984df079022d386ce42c2b8508159dc6c"> @@ -188,7 +188,6 @@ - libsoup-3.0.pc @@ -196,8 +195,8 @@ diff --git a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp index 6186d81869dbbb346ec5a62f2bbba88e2320d5e7..25b5615339b74cd56042b89f723993023cbb58ca 100644 --- a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp +++ b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp @@ -175,28 +175,27 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) return; } - auto info = SkImageInfo::MakeN32Premul(m_width, m_height, SkColorSpace::MakeSRGB()); + uint32_t width = std::max(0, wl_shm_buffer_get_width(shmBuffer)); + uint32_t height = std::max(0, wl_shm_buffer_get_height(shmBuffer)); + if (!width || !height) { + fprintf(stderr, "HeadlessViewBackend::updateSnapshot shmBuffer is empty: %ux%u\n", width, height); + return; + } + + auto info = SkImageInfo::MakeN32Premul(width, height, SkColorSpace::MakeSRGB()); uint32_t bufferStride = info.minRowBytes(); - uint8_t* buffer = new uint8_t[bufferStride * m_height]; - memset(buffer, 0, bufferStride * m_height); + uint32_t stride = std::max(0, wl_shm_buffer_get_stride(shmBuffer)); + if (bufferStride != stride) { + fprintf(stderr, "bufferStride != stride: %u != %u\n", bufferStride, stride); + return; + } + uint8_t* buffer = new uint8_t[bufferStride * height]; { - uint32_t width = std::min(m_width, std::max(0, wl_shm_buffer_get_width(shmBuffer))); - uint32_t height = std::min(m_height, std::max(0, wl_shm_buffer_get_height(shmBuffer))); - uint32_t stride = std::max(0, wl_shm_buffer_get_stride(shmBuffer)); - wl_shm_buffer_begin_access(shmBuffer); auto* data = static_cast(wl_shm_buffer_get_data(shmBuffer)); - for (uint32_t y = 0; y < height; ++y) { - for (uint32_t x = 0; x < width; ++x) { - buffer[bufferStride * y + 4 * x + 0] = data[stride * y + 4 * x + 0]; - buffer[bufferStride * y + 4 * x + 1] = data[stride * y + 4 * x + 1]; - buffer[bufferStride * y + 4 * x + 2] = data[stride * y + 4 * x + 2]; - buffer[bufferStride * y + 4 * x + 3] = data[stride * y + 4 * x + 3]; - } - } - + memcpy(buffer, data, bufferStride * height); wl_shm_buffer_end_access(shmBuffer); } diff --git a/WebKit.xcworkspace/contents.xcworkspacedata b/WebKit.xcworkspace/contents.xcworkspacedata index 5d6492124eb520ce2b25f5c62775438103050ed3..1c0ea8a3258b5676b81fb00360e2c0589cc93e18 100644 --- a/WebKit.xcworkspace/contents.xcworkspacedata +++ b/WebKit.xcworkspace/contents.xcworkspacedata @@ -4,6 +4,9 @@ + + diff --git a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme index 30f8a76f6050c407ab563814f614b3b848c168ff..d5fd599e4865f147d7ca8cfbcd6a4bedf6baa9e5 100644 --- a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme +++ b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme @@ -202,6 +202,20 @@ ReferencedContainer = "container:Tools/SwiftBrowser/SwiftBrowser.xcodeproj"> + + + +