diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 27178e3306f1a1957516fbf90e101d1da144a8bd..ed99032196ff06fbe32cc3d88cdca110d0a29d30 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -1405,21 +1405,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 4ebffbf7b080143afc4d9da6c516174cd08ffb5c..ddf59a7c8f336d9ee13b052c3ff685f1cadacd30 100644 --- a/Source/JavaScriptCore/DerivedSources-input.xcfilelist +++ b/Source/JavaScriptCore/DerivedSources-input.xcfilelist @@ -97,20 +97,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 a37d9dfd55e0d0e20db0c984e594b685fbb96a9e..11e68adc7db68a30be854177a93984d074dbac85 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make @@ -300,21 +300,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 4113ddb45d4a8d08379d4dc56c44cde56162accf..e00cb9cb01a7a241f3f25b1e4cdc2fcaee92b3ac 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.h +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.h @@ -31,6 +31,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 8b39848154ecab9f7daa2d21c85562a319cd06d7..c8a1f44cb4516993899ffe1404b6c3865d42433a 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp @@ -85,7 +85,10 @@ static RefPtr jsToInspectorValue(JSC::JSGlobalObject* globalObject, JSC::PropertyNameArray 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 1f5d0adbf624bd24ef1e525967e6e82e8c37b4e5..4fe0f364b4ccd11774bf29f772e0a568549a4322 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp @@ -102,7 +102,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple m_dispatchers.set(domain, dispatcher); } -void BackendDispatcher::dispatch(const String& message) +void BackendDispatcher::dispatch(const String& message, Interceptor&& interceptor) { Ref protect(*this); @@ -147,6 +147,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 28f4cdacf6ebd7037a42a75872618436332d90ec..463f014be2bd29a75bee7b2113b6f929da13aca5 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h @@ -95,8 +95,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 d408d364f1986983161f9d44efbc8bc6f6898676..1375ce9990f0c63d7e6f33ee62930051d6cd44cb 100644 --- a/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp +++ b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp @@ -49,7 +49,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 0cc2127c9c12c2d82dea9550bad73f4ffb99ba24..8ca65cc042d435cbc0e05dcc5c5dfc958eb24f5a 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.cpp +++ b/Source/JavaScriptCore/inspector/InspectorTarget.cpp @@ -44,6 +44,8 @@ void InspectorTarget::resume() ASSERT(m_isPaused); m_isPaused = false; + willResume(); + if (m_resumeCallback) { m_resumeCallback(); m_resumeCallback = nullptr; @@ -52,7 +54,6 @@ void InspectorTarget::resume() void InspectorTarget::setResumeCallback(WTF::Function&& callback) { - ASSERT(!m_resumeCallback); m_resumeCallback = WTFMove(callback); } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h index b555c2e5a071d0a6a016061cc60755449557556d..d019346f0932296d15212c76a4a9b56beb565ff4 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.h +++ b/Source/JavaScriptCore/inspector/InspectorTarget.h @@ -66,8 +66,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 c33e236f5228e21c6d5e0ea9bd97d07cdcb70640..7f160aec0f13e8c936aa7dea769d4e160d716452 100644 --- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp +++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp @@ -222,6 +222,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 6bbd0729a65b4a901e7da4dc50cc47c669bd9897..452b25d0e8eba3df1d5f6623dc222048bef120cd 100644 --- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h +++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h @@ -64,6 +64,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 0cb6efeef2430faa5dbd812f71d4abfd5f6eb9df..787ec6a5f8413c0a9dc133cb0e51ccdab58d40d0 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp @@ -194,9 +194,8 @@ void InspectorRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObject void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const Protocol::Runtime::RemoteObjectId& objectId, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& /* emulateUserGesture */, std::optional&& awaitPromise, Ref&& callback) { ASSERT(!injectedScript.hasNoValue()); - JSC::Debugger::TemporarilyDisableExceptionBreakpoints temporarilyDisableExceptionBreakpoints(m_debugger); - + bool pauseAndMute = doNotPauseOnExceptionsAndMuteConsole.value_or(false); if (pauseAndMute) { temporarilyDisableExceptionBreakpoints.replace(); @@ -215,6 +214,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 816633a6dfc75a1248f6edb44807e5d4f602568c..687fb7dadfad9357e15a27e0869fa145c46fb39a 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h @@ -64,6 +64,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 e47c6ca59f37fbf18ca8a393df72e0472363fabd..b393465540595220561ae00afb85408279710864 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) { ASSERT_WITH_MESSAGE(m_targets.get(targetId), "Sending a message from an untracked target to the frontend."); @@ -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 04377b714a6ccb5294c65d592e74350621d470ba..b6de937bfa3e6185ce29f4e432d327a3cedee6df 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 3fbb38e3ce2676cc569dc706d74b3fc7431eb3fb..e1dec7287ce55077bfeaa1a601c7ffdea0a61008 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", @@ -717,7 +727,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": [ @@ -794,6 +807,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 96af27ece2ac200e11c4311b3ca0d9d3b5a048da..3168f7806fcbdabec07acc5e304bae1e3736240a 100644 --- a/Source/JavaScriptCore/inspector/protocol/Network.json +++ b/Source/JavaScriptCore/inspector/protocol/Network.json @@ -352,6 +352,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 3d032713a7f3bb9645bfc7d42455a0494b5376c0..913dda5e90b86cc5f8e4ca6881f6db57520a7f66 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,50 @@ { "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": "AXNode", + "type": "object", + "description": "Accessibility Node", + "properties": [ + { "name": "role", "type": "string", "description": "The role."}, + { "name": "name", "type": "string","optional": true, "description": "A human readable name for the node."}, + { "name": "value", "type": "any", "optional": true, "description": "The current value of the node."}, + { "name": "description", "type": "string", "optional": true, "description": "An additional human readable description of the node."}, + { "name": "keyshortcuts", "type": "string", "optional": true, "description": "Keyboard shortcuts associated with this node."}, + { "name": "roledescription", "type": "string", "optional": true, "description": "A human readable alternative to the role."}, + { "name": "valuetext", "type": "string", "optional": true, "description": "A description of the current value."}, + { "name": "disabled", "type": "boolean", "optional": true, "description": "Whether the node is disabled."}, + { "name": "expanded", "type": "boolean", "optional": true, "description": "Whether the node is expanded or collapsed."}, + { "name": "focused", "type": "boolean", "optional": true, "description": "Whether the node is focused."}, + { "name": "modal", "type": "boolean", "optional": true, "description": "Whether the node is modal."}, + { "name": "multiselectable", "type": "boolean", "optional": true, "description": "Whether more than one child can be selected."}, + { "name": "readonly", "type": "boolean", "optional": true, "description": "Whether the node is read only."}, + { "name": "required", "type": "boolean", "optional": true, "description": "Whether the node is required."}, + { "name": "selected", "type": "boolean", "optional": true, "description": "Whether the node is selected in its parent node."}, + { "name": "checked", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Whether the checkbox is checked, or \"mixed\"."}, + { "name": "pressed", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Whether the toggle button is checked, or \"mixed\"."}, + { "name": "level", "type": "integer", "optional": true, "description": "The level of a heading."}, + { "name": "valuemin", "type": "number", "optional": true, "description": "The minimum value in a node."}, + { "name": "valuemax", "type": "number", "optional": true, "description": "The maximum value in a node."}, + { "name": "autocomplete", "type": "string", "optional": true, "description": "What kind of autocomplete is supported by a control."}, + { "name": "haspopup", "type": "string", "optional": true, "description": "What kind of popup is currently being shown for a node."}, + { "name": "invalid", "type": "string", "optional": true, "enum": ["true", "false", "grammar", "spelling"], "description": "Whether and in what way this node's value is invalid."}, + { "name": "orientation", "type": "string", "optional": true, "description": "Whether the node is oriented horizontally or vertically."}, + { "name": "focusable", "type": "boolean", "optional": true, "description": "Whether the node is focusable."}, + { "name": "children", "type": "array", "optional": true, "items": { "$ref": "AXNode"}, "description": "Child AXNodes of this node, if any."}, + { "name": "found", "type": "boolean", "optional": true, "description": "True if this AXNode corresponds with the ObjectId passed into acessibilitySnapshot."} + ] + }, + { + "id": "Insets", + "type": "object", + "properties": [ + { "name": "top", "type": "number" }, + { "name": "right", "type": "number" }, + { "name": "bottom", "type": "number" }, + { "name": "left", "type": "number" } + ] } ], "commands": [ @@ -145,6 +203,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": "navigate", "description": "Navigates current page to the given URL.", @@ -161,6 +227,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.", @@ -285,6 +359,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.", @@ -305,7 +401,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)." } @@ -323,12 +420,64 @@ { "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": "accessibilitySnapshot", + "description": "Serializes and returns all of the accessibility nodes of the page.", + "parameters": [ + { "name": "objectId", "type": "string", "optional": true, "description": "Object Id of a node to find in the accessibility tree."} + ], + "returns": [ + { "name": "axNode", "$ref": "AXNode", "description": "The root AXNode."} + ] + }, + { + "name": "setInterceptFileChooserDialog", + "description": "Intercepts file chooser dialog", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "True to enable." } + ] + }, + { + "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": [ @@ -336,14 +485,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." } ] }, { @@ -353,6 +504,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.", @@ -381,7 +540,8 @@ "targetTypes": ["page"], "parameters": [ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has scheduled a navigation." }, - { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." } + { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." }, + { "name": "targetIsCurrentFrame", "type": "boolean", "description": "Whether the naviation will happen in the same frame." } ] }, { @@ -392,6 +552,22 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ] }, + { + "name": "navigatedWithinDocument", + "description": "Fired when same-document navigation happens, e.g. due to history API usage or anchor navigation.", + "parameters": [ + { + "name": "frameId", + "description": "Id of the frame.", + "$ref": "Network.FrameId" + }, + { + "name": "url", + "description": "Frame's new url.", + "type": "string" + } + ] + }, { "name": "defaultUserPreferencesDidChange", "description": "Fired when the default value of a user preference changes at the system level.", @@ -399,6 +575,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..440dd95173e066a886de120fb3dab7597d85feb6 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Playwright.json @@ -0,0 +1,315 @@ +{ + "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" } + ], + "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": false, "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" } + ] + }, + { + "name": "screencastFinished", + "parameters": [ + { "name": "screencastId", "$ref": "Screencast.ScreencastId", "description": "Unique identifier of the screencast." } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json index 301b88eb1607b0975c3fa81d91045eb5403378ec..0e2ae5d96b3cdcc20ecc95ddc7b49538dcb3c302 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..73a4e53ced3acc41316bb8d4c787306d3f28a27e --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Screencast.json @@ -0,0 +1,64 @@ +{ + "domain": "Screencast", + "availability": ["web"], + "types": [ + { + "id": "ScreencastId", + "type": "string", + "description": "Unique identifier of the screencast." + } + ], + "commands": [ + { + "name": "startVideo", + "description": "Starts recoring video to speified file.", + "parameters": [ + { "name": "file", "type": "string", "description": "Output file location." }, + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" }, + { "name": "toolbarHeight", "type": "integer" } + ], + "returns": [ + { "name": "screencastId", "$ref": "ScreencastId", "description": "Unique identifier of the screencast." } + ] + }, + { + "name": "stopVideo", + "async": true, + "description": "Stops recoding video. Returns after the file has been closed." + }, + { + "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": "deviceWidth", "type": "integer" }, + { "name": "deviceHeight", "type": "integer" } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Target.json b/Source/JavaScriptCore/inspector/protocol/Target.json index 52920cded24a9c6b0ef6fb4e518664955db4f9fa..bbbabc4e7259088b9404e8cc07eecd6f45077da0 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", "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 24891ad836086fd23024fcb4d08ca63f6974c812..29f4b6b1923383fec7a99d28a4e815dc4536d160 100644 --- a/Source/JavaScriptCore/runtime/ConsoleClient.h +++ b/Source/JavaScriptCore/runtime/ConsoleClient.h @@ -78,6 +78,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 ArgumentRequirement { ArgumentRequired, ArgumentNotRequired }; diff --git a/Source/ThirdParty/libwebrtc/CMakeLists.txt b/Source/ThirdParty/libwebrtc/CMakeLists.txt index ca4f3508a44e3c6677a72fbe3d7c853714b4f2c6..ae117f5f402a7eb259e376ca9440e00062e22d9f 100644 --- a/Source/ThirdParty/libwebrtc/CMakeLists.txt +++ b/Source/ThirdParty/libwebrtc/CMakeLists.txt @@ -532,6 +532,11 @@ set(webrtc_SOURCES Source/third_party/crc32c/src/src/crc32c.cc Source/third_party/crc32c/src/src/crc32c_portable.cc Source/third_party/crc32c/src/src/crc32c_sse42.cc +# Playwright begin + Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc + Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc + Source/third_party/libwebm/mkvmuxer/mkvwriter.cc +# Playwright end Source/third_party/libyuv/source/compare.cc Source/third_party/libyuv/source/compare_common.cc Source/third_party/libyuv/source/compare_gcc.cc @@ -2348,6 +2353,11 @@ set(webrtc_INCLUDE_DIRECTORIES PRIVATE Source/third_party/libsrtp/config Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include +# Playwright begin + Source/third_party/libwebm + Source/third_party/libvpx/source/libvpx + Source/third_party/libvpx/source/libvpx/third_party/googletest/src/include +# Playwright end Source/third_party/libyuv/include Source/third_party/opus/src/celt Source/third_party/opus/src/include diff --git a/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig index 0c5c8e689bdddec766f9de5bffd4444a5e068d77..330dd1f585e530722178c65c883641a2b8c0f1bd 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig +++ b/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig @@ -24,6 +24,8 @@ HEADER_SEARCH_PATHS = Source Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/webrtc/webkit_sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/webkit_sdk/objc Source/webrtc/webkit_sdk/objc/base Source/webrtc/webkit_sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/webkit_sdk/objc/Framework/Classes/Common Source/webrtc/webkit_sdk/objc/Framework/Classes/Video Source/webrtc/webkit_sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include Source/third_party/crc32c/config Source/third_party/crc32c/include Source/third_party/crc32c/src/include Source/third_party/libaom/source/libaom; USE_HEADERMAP = NO; +HEADER_SEARCH_PATHS = ${HEADER_SEARCH_PATHS} Source/third_party/libwebm/mkvmuxer Source/third_party/libvpx/source/libvpx/third_party/libwebm; + WARNING_CFLAGS = -Wno-deprecated-declarations $(inherited); // FIXME: Set WEBRTC_USE_BUILTIN_ISAC_FIX and WEBRTC_USE_BUILTIN_ISAC_FLOAT for iOS and Mac diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp index f7995f8f8b7af9fb6b28fe81b371a16700549cdf..c372447fbe21912803997876f95b5ca263cb47b5 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp @@ -425,3 +425,16 @@ __ZN6webrtc21SdpSerializeCandidateERKN7cricket9CandidateE __ZNK6webrtc18VideoFrameMetadata8GetCsrcsEv __ZN6webrtc15CloneAudioFrameEPNS_32TransformableAudioFrameInterfaceE __ZN6webrtc15CloneVideoFrameEPNS_32TransformableVideoFrameInterfaceE +__ZN8mkvmuxer11SegmentInfo4InitEv +__ZN8mkvmuxer9MkvWriterC1EP7__sFILE +_ARGBToI420 +_vpx_codec_destroy +_vpx_codec_enc_config_default +_vpx_codec_enc_init_ver +_vpx_codec_encode +_vpx_codec_err_to_string +_vpx_codec_error +_vpx_codec_get_cx_data +_vpx_codec_iface_name +_vpx_codec_version_str +_vpx_codec_vp8_cx diff --git a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj index 7585b2e5e9bffdc8cabd888dd822313d53b30141..5909d33b9726cdc7d2d53b538f7da18bc221e30b 100644 --- a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj +++ b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj @@ -56,6 +56,20 @@ }; /* End PBXAggregateTarget section */ +/* Begin PBXAggregateTarget section */ + F31720AC27FE215900EEE407 /* Copy libvpx headers */ = { + isa = PBXAggregateTarget; + buildConfigurationList = F31720B027FE215900EEE407 /* Build configuration list for PBXAggregateTarget "Copy libvpx headers" */; + buildPhases = ( + F31720B127FE216400EEE407 /* ShellScript */, + ); + dependencies = ( + ); + name = "Copy libvpx headers"; + productName = "Copy libvpx headers"; + }; +/* End PBXAggregateTarget section */ + /* Begin PBXBuildFile section */ 2D6BFF60280A93DF00A1A74F /* video_coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45B234C81710028A615 /* video_coding.h */; settings = {ATTRIBUTES = (Public, ); }; }; 2D6BFF61280A93EC00A1A74F /* video_codec_initializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45E234C81720028A615 /* video_codec_initializer.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -5786,6 +5800,13 @@ remoteGlobalIDString = DDF30D0527C5C003006A526F; remoteInfo = absl; }; + F31720B327FE273100EEE407 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = FB39D0701200ED9200088E69 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F31720AC27FE215900EEE407; + remoteInfo = "Copy libvpx headers"; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -24271,6 +24292,7 @@ ); dependencies = ( 410B3827292B73E90003E515 /* PBXTargetDependency */, + F31720B427FE273100EEE407 /* PBXTargetDependency */, DD2E76E827C6B69A00F2A74C /* PBXTargetDependency */, CDEBB4CC24C01AB400ADBD44 /* PBXTargetDependency */, 411ED040212E0811004320BA /* PBXTargetDependency */, @@ -24364,6 +24386,7 @@ 4460B8B92B155B6A00392062 /* vp9_qp_parser_fuzzer */, 444A6EF02AEADFC9005FE121 /* vp9_replay_fuzzer */, 44945C512B9BA1C300447FFD /* webm_fuzzer */, + F31720AC27FE215900EEE407 /* Copy libvpx headers */, ); }; /* End PBXProject section */ @@ -24467,6 +24490,23 @@ shellPath = /bin/sh; shellScript = "[ -z \"${WK_DERIVED_SDK_HEADERS_DIR}\" -o -d \"${WK_DERIVED_SDK_HEADERS_DIR}\" ] && touch \"${SCRIPT_OUTPUT_FILE_0}\"\n"; }; + F31720B127FE216400EEE407 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "PRIVATE_HEADERS_FOLDER_PATH=usr/local/include\n\nif [[ \"${DEPLOYMENT_LOCATION}\" == \"NO\" ]]; then\n PRIVATE_HEADERS_PATH=\"${TARGET_BUILD_DIR%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nelse\n PRIVATE_HEADERS_PATH=\"${DSTROOT}${INSTALL_PATH_PREFIX%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nfi;\n\necho \"#### PRIVATE_HEADERS_PATH = ${PRIVATE_HEADERS_PATH}\"\necho\n\nmkdir -p \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libyuv/include/\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --exclude \"src\" --exclude \"internal\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libvpx/source/libvpx/vpx\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libwebm/\" \"${PRIVATE_HEADERS_PATH}\"\n\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -27437,6 +27477,11 @@ target = DDF30D0527C5C003006A526F /* absl */; targetProxy = DD2E76E727C6B69A00F2A74C /* PBXContainerItemProxy */; }; + F31720B427FE273100EEE407 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F31720AC27FE215900EEE407 /* Copy libvpx headers */; + targetProxy = F31720B327FE273100EEE407 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ @@ -28204,6 +28249,27 @@ }; name = Production; }; + F31720AD27FE215900EEE407 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + F31720AE27FE215900EEE407 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + F31720AF27FE215900EEE407 /* Production */ = { + isa = XCBuildConfiguration; + buildSettings = { + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Production; + }; FB39D0711200ED9200088E69 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */; @@ -28586,6 +28652,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Production; }; + F31720B027FE215900EEE407 /* Build configuration list for PBXAggregateTarget "Copy libvpx headers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F31720AD27FE215900EEE407 /* Debug */, + F31720AE27FE215900EEE407 /* Release */, + F31720AF27FE215900EEE407 /* Production */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Production; + }; FB39D0731200ED9200088E69 /* Build configuration list for PBXProject "libwebrtc" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Source/ThirdParty/skia/CMakeLists.txt b/Source/ThirdParty/skia/CMakeLists.txt index 6bfc5cba986488f3d808ebd0583c476cd93da70e..f4c4222d17bce640355ba52e00152069d5b14432 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 () @@ -948,6 +950,7 @@ endif () target_link_libraries(Skia PRIVATE JPEG::JPEG PNG::PNG + Threads::Threads ) WEBKIT_ADD_TARGET_CXX_FLAGS(Skia diff --git a/Source/ThirdParty/skia/src/opts/SkOpts_SetTarget.h b/Source/ThirdParty/skia/src/opts/SkOpts_SetTarget.h index 525cfcb862ae96bf8573d00b67dc9e5e23c10d22..f2debc0444cb8f5b80a0e99a2214bceaab3960c1 100644 --- a/Source/ThirdParty/skia/src/opts/SkOpts_SetTarget.h +++ b/Source/ThirdParty/skia/src/opts/SkOpts_SetTarget.h @@ -65,6 +65,7 @@ // Each of the specific intrinsic headers also checks to ensure that immintrin.h has been // included, so do that here, first. #if defined(__clang__) && defined(_MSC_VER) + #define __RTMINTRIN_H // Workaround for https://github.com/llvm/llvm-project/issues/95133 #include #endif diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml index e6e1af5d1973c991229948e0b1eb0d5c456f846f..7fb6e2455bd489c5b5f9f2169fea5a2f9865bf91 100644 --- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml @@ -602,6 +602,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 @@ -612,7 +613,7 @@ AsyncClipboardAPIEnabled: default: false WebKit: "PLATFORM(COCOA) || PLATFORM(GTK)" : 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 BlobRegistryTopOriginPartitioningEnabled: @@ -2312,6 +2310,7 @@ CrossOriginEmbedderPolicyEnabled: WebCore: default: false +# Playwright: disable setting. CrossOriginOpenerPolicyEnabled: type: bool status: stable @@ -2352,7 +2351,7 @@ CustomPasteboardDataEnabled: WebKitLegacy: default: false WebKit: - "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WIN)": true + "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true default: false DOMAudioSessionEnabled: @@ -2385,6 +2384,7 @@ DOMAudioSessionFullEnabled: WebCore: default: false +# Playwright: enable on all platforms to align with Safari. DOMPasteAccessRequestsEnabled: type: bool status: internal @@ -2396,7 +2396,7 @@ DOMPasteAccessRequestsEnabled: default: false WebKit: "PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(VISION)": true - default: false + default: true WebCore: default: false @@ -2462,10 +2462,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 @@ -2478,7 +2478,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 @@ -2734,7 +2734,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 @@ -3202,10 +3202,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 @@ -3811,7 +3811,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 @@ -3844,7 +3844,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 @@ -3860,7 +3860,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 @@ -3892,7 +3892,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 @@ -3953,6 +3953,7 @@ InspectorMaximumResourcesContentSize: "PLATFORM(WPE)": 50 default: 200 +# Playwright: disable setting. InspectorStartsAttached: type: bool status: embedder @@ -3960,7 +3961,7 @@ InspectorStartsAttached: exposed: [ WebKit ] defaultValue: WebKit: - default: true + default: false InspectorSupportsShowingCertificate: type: bool @@ -5911,7 +5912,7 @@ PermissionsAPIEnabled: 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 @@ -5990,6 +5991,19 @@ PitchCorrectionAlgorithm: WebCore: default: MediaPlayerEnums::PitchCorrectionAlgorithm::BestAllAround +# Playwright: add preference 'PointerLockEnabled'. +PointerLockEnabled: + type: bool + status: embedder + condition: ENABLE(POINTER_LOCK) + defaultValue: + WebKitLegacy: + default: true + WebKit: + default: true + WebCore: + default: true + PointerLockOptionsEnabled: type: bool status: stable @@ -6586,7 +6600,7 @@ ScreenOrientationAPIEnabled: WebKitLegacy: default: false WebKit: - default: WebKit::defaultShouldEnableScreenOrientationAPI() + default: true WebCore: default: false sharedPreferenceForWebProcess: true @@ -8063,6 +8077,7 @@ UseCGDisplayListsForDOMRendering: default: true sharedPreferenceForWebProcess: true +# Playwright: force-disable on Windows. UseGPUProcessForCanvasRenderingEnabled: type: bool status: stable @@ -8075,7 +8090,7 @@ UseGPUProcessForCanvasRenderingEnabled: defaultValue: WebKit: "ENABLE(GPU_PROCESS_BY_DEFAULT)": true - "USE(GRAPHICS_LAYER_WC)": true + "USE(GRAPHICS_LAYER_WC)": false default: false UseGPUProcessForDOMRenderingEnabled: @@ -8120,6 +8135,7 @@ UseGPUProcessForMediaEnabled: sharedPreferenceForWebProcess: true mediaPlaybackRelated: true +# Playwright: force-disable on Windows. UseGPUProcessForWebGLEnabled: type: bool status: internal @@ -8131,7 +8147,7 @@ UseGPUProcessForWebGLEnabled: default: false WebKit: "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true - "USE(GRAPHICS_LAYER_WC)": true + "USE(GRAPHICS_LAYER_WC)": false default: false WebCore: "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h index 0652dc379f7322cd7af4078cf1b6c54588565aea..51ce8260d8889c6e3dbef09bfff48177b9cf9f0a 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h @@ -387,7 +387,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 !defined(ENABLE_OVERFLOW_SCROLLING_TOUCH) @@ -504,7 +504,7 @@ #endif #if !defined(ENABLE_TOUCH_EVENTS) -#define ENABLE_TOUCH_EVENTS 0 +#define ENABLE_TOUCH_EVENTS 1 #endif #if !defined(ENABLE_TOUCH_ACTION_REGIONS) diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h index e416fc014aa5731d77f7a3a440b762a9814f6ef5..00a67ad2516627e982763f4684fb951741517817 100644 --- a/Source/WTF/wtf/PlatformEnableCocoa.h +++ b/Source/WTF/wtf/PlatformEnableCocoa.h @@ -817,7 +817,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/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h index e4a8591c4a4e0d682cdf3d4232e25e6af963ba16..96a65e06d788995714bafc95bde3ad8bf21bc2e8 100644 --- a/Source/WTF/wtf/PlatformHave.h +++ b/Source/WTF/wtf/PlatformHave.h @@ -1198,7 +1198,8 @@ #endif #if PLATFORM(MAC) -#define HAVE_GPU_AVAILABILITY_CHECK 1 +// Playwright: disable the check to make WebGL always work. +#define HAVE_GPU_AVAILABILITY_CHECK 0 #endif #if !defined(HAVE_LOCKDOWN_MODE_PDF_ADDITIONS) && \ diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.h b/Source/WTF/wtf/unicode/UTF8Conversion.h index 007b8fe3292f326504013be8198ae020f7aacf35..1c722c473732ffe05fdb61010fa4417e3e399d1f 100644 --- a/Source/WTF/wtf/unicode/UTF8Conversion.h +++ b/Source/WTF/wtf/unicode/UTF8Conversion.h @@ -27,6 +27,11 @@ #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 d0e3444bd9699dfe2bc1c85dde2ad5543d71b0df..b624441883bfa4ea04ee22fef2c38ad0daabe479 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make @@ -1229,6 +1229,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 \ @@ -1829,9 +1833,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 05091a46212f00333ed97939a6ec18d8656657e9..3fb779a3eba806cf416d0dd7586be871d4782651 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp @@ -361,8 +361,9 @@ bool Geolocation::shouldBlockGeolocationRequests() bool isSecure = SecurityOrigin::isSecure(document->url()) || document->isSecureContext(); bool hasMixedContent = !document->foundMixedContent().isEmpty(); bool isLocalOrigin = securityOrigin()->isLocal(); + bool isPotentiallyTrustworthy = securityOrigin()->isPotentiallyTrustworthy(); if (document->canAccessResource(ScriptExecutionContext::ResourceType::Geolocation) != ScriptExecutionContext::HasResourceAccess::No) { - if (isLocalOrigin || (isSecure && !hasMixedContent)) + if (isLocalOrigin || (isSecure && !hasMixedContent) || isPotentiallyTrustworthy) return false; } diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm index b2b0391c120d527a9ab4bc6daf8bff7ea5d03cf7..d490a95f89f21536fce4f403b86399160abefc23 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm @@ -195,6 +195,7 @@ - (void)sendEndIfNeeded - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available { + UNUSED_PARAM(speechRecognizer); ASSERT(isMainThread()); if (available || !_task) @@ -208,6 +209,7 @@ - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidC - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self sendSpeechStartIfNeeded]; @@ -216,6 +218,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)) @@ -229,6 +232,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecogniti - (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self sendSpeechEndIfNeeded]; diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake index 7bbcd501126a7b83986f5d1f5a077779441dc1fe..13e68ac853603d8e7da1b42f5c8073ebdab83264 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake @@ -60,6 +60,8 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/gbm/PlatformDisplayGBM.h platform/graphics/libwpe/PlatformDisplayLibWPE.h + + platform/wpe/SelectionData.h ) set(WebCore_USER_AGENT_SCRIPTS_DEPENDENCIES ${WEBCORE_DIR}/platform/wpe/RenderThemeWPE.cpp) diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt index 06a9accfc8e6c46493733663b5d76b07fc80db22..4946d012d166c84b25d4d954266c4dc528f7d8ad 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt @@ -734,3 +734,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify platform/graphics/cocoa/GraphicsContextGLCocoa.mm @no-unify platform/graphics/cv/GraphicsContextGLCVCocoa.mm @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 9cc9f51e48b3058ea29da389629c021bcf05e202..978ac405073534ba6fa79f483d885643a4722fd8 100644 --- a/Source/WebCore/SourcesGTK.txt +++ b/Source/WebCore/SourcesGTK.txt @@ -112,3 +112,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 5fd26e859ef215fccd597ca475a320abcad83b98..f422c4023eb1c9f101d989ce56e4b4b42e203c83 100644 --- a/Source/WebCore/SourcesWPE.txt +++ b/Source/WebCore/SourcesWPE.txt @@ -46,6 +46,8 @@ editing/libwpe/EditorLibWPE.cpp loader/soup/ResourceLoaderSoup.cpp +page/wpe/DragControllerWPE.cpp + page/linux/ResourceUsageOverlayLinux.cpp page/linux/ResourceUsageThreadLinux.cpp @@ -91,6 +93,17 @@ platform/android/SharedMemoryAndroid.cpp platform/unix/LoggingUnix.cpp platform/unix/SharedMemoryUnix.cpp +platform/wpe/DragDataWPE.cpp +platform/wpe/DragImageWPE.cpp platform/wpe/PlatformScreenWPE.cpp platform/xdg/MIMETypeRegistryXdg.cpp + +// Playwright: begin. +platform/wpe/SelectionData.cpp + +JSSpeechSynthesisErrorCode.cpp +JSSpeechSynthesisErrorEvent.cpp +JSSpeechSynthesisErrorEventInit.cpp +JSSpeechSynthesisEventInit.cpp +// Playwright: end. diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj index 656e474f969c44c344c87d53aca6981071b39ef5..c8cf5ab6da2a5d2a2c2a723e52a32e2bee261846 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj @@ -6432,6 +6432,13 @@ EE0C7E042CE845CB0043DAF8 /* CSSPositionTryRule.h in Headers */ = {isa = PBXBuildFile; fileRef = EE0C7E002CE845CB0043DAF8 /* CSSPositionTryRule.h */; }; EE0D3C492D2F4B4C00072978 /* StageModeOperations.h in Headers */ = {isa = PBXBuildFile; fileRef = EE0D3C482D2F4AE600072978 /* StageModeOperations.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 */; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; F344C7141125B82C00F26EEE /* InspectorFrontendClient.h in Headers */ = {isa = PBXBuildFile; fileRef = F344C7121125B82C00F26EEE /* InspectorFrontendClient.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -21095,6 +21102,14 @@ EE7A169F2C607BFA0057B563 /* StartViewTransitionOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StartViewTransitionOptions.h; sourceTree = ""; }; EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasActivityRecord.cpp; sourceTree = ""; }; EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; 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 = ""; }; F32BDCD52363AAC90073B6AE /* UserGestureEmulationScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserGestureEmulationScope.cpp; sourceTree = ""; }; @@ -28876,6 +28891,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 */, F4E1965F21F26E4E00285078 /* UndoItem.cpp */, 2ECDBAD521D8906300F00ECD /* UndoItem.h */, @@ -35855,6 +35875,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 */, @@ -38674,6 +38696,7 @@ AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, + F050E17323AD6A800011CE47 /* DocumentTouch.cpp */, 7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */, 7CE7FA591EF882300060C9D6 /* DocumentTouch.h */, A8185F3209765765005826D9 /* DocumentType.cpp */, @@ -43613,6 +43636,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 */, @@ -44969,6 +44994,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 */, BE88E0C21715CE2600658D98 /* TrackListBase.h in Headers */, @@ -46169,6 +46195,8 @@ 2D22830323A8470700364B7E /* CursorMac.mm in Sources */, 5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */, 07E4BDBF2A3A5FAB000D5509 /* DictationCaretAnimator.cpp in Sources */, + F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */, + 329C0C2528BD96EB00F187D2 /* ElementName.cpp in Sources */, 7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */, 4667EA3E2968D9DA00BAB1E2 /* GameControllerHapticEffect.mm in Sources */, 46FE73D32968E52000B8064C /* GameControllerHapticEngines.mm in Sources */, @@ -46260,6 +46288,9 @@ CE88EE262414467B007F29C2 /* TextAlternativeWithRange.mm 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 */, 538EC8031F96AF81004D22A8 /* UnifiedSource1-mm.mm in Sources */, 538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */, 538EC8051F96AF81004D22A8 /* UnifiedSource2-mm.mm in Sources */, diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp index a38a54553f430b96fa7744a442676d6136f5eda9..4ff2eaeab053a186e5e6bacab94a6b3b129eb7ab 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp @@ -71,6 +71,7 @@ #include "HTMLTableSectionElement.h" #include "HTMLTextAreaElement.h" #include "HitTestResult.h" +#include "InspectorInstrumentation.h" #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MathMLNames.h" @@ -3910,7 +3911,12 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const if (roleValue() == AccessibilityRole::ApplicationDialog) return AccessibilityObjectInclusion::IncludeObject; - return accessibilityPlatformIncludesObject(); + AccessibilityObjectInclusion platformBehavior = accessibilityPlatformIncludesObject(); + if (platformBehavior != AccessibilityObjectInclusion::DefaultBehavior) { + if (auto* page = this->page()) + InspectorInstrumentation::maybeOverrideDefaultObjectInclusion(*page, platformBehavior); + } + return platformBehavior; } bool AccessibilityObject::isWithinHiddenWebArea() const diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h index a9d9ee8f0cb26fd47f9fea85e0856d2849362e6c..e2c58e571f41da4f65388fd36a9de56c92a404a8 100644 --- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h +++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h @@ -189,6 +189,8 @@ namespace WebCore { macro(DelayNode) \ macro(DeprecationReportBody) \ macro(DigitalCredential) \ + macro(DeviceMotionEvent) \ + macro(DeviceOrientationEvent) \ macro(DocumentTimeline) \ macro(DynamicsCompressorNode) \ macro(ElementInternals) \ diff --git a/Source/WebCore/css/query/MediaQueryFeatures.cpp b/Source/WebCore/css/query/MediaQueryFeatures.cpp index aec43490053f95341ef979385b5e6c1daf03a090..4e44b7e341c8247f916f8597092248d8ec884518 100644 --- a/Source/WebCore/css/query/MediaQueryFeatures.cpp +++ b/Source/WebCore/css/query/MediaQueryFeatures.cpp @@ -498,7 +498,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 }; } }; @@ -686,6 +690,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 c6f2dca0d4aede2bea015d1cca45dff434425938..e6f41af39befe69f47d0e0953f7d689c338ca184 100644 --- a/Source/WebCore/dom/DataTransfer.cpp +++ b/Source/WebCore/dom/DataTransfer.cpp @@ -523,6 +523,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 34ef2f454a732d39acae04987584cab5638b8c60..5e7b788612718dffe3423c89d96141b5b53621fb 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 d59cba0b1c3e1876614476cd887fa1b2a9619d0c..565987a3f9ef7dc29edf8315cebe51b00953dc84 100644 --- a/Source/WebCore/dom/DeviceMotionEvent.idl +++ b/Source/WebCore/dom/DeviceMotionEvent.idl @@ -25,6 +25,7 @@ [ Conditional=DEVICE_ORIENTATION, + EnabledBySetting=DeviceOrientationEventEnabled, Exposed=Window ] interface DeviceMotionEvent : Event { readonly attribute Acceleration? acceleration; diff --git a/Source/WebCore/dom/DeviceOrientationEvent.idl b/Source/WebCore/dom/DeviceOrientationEvent.idl index 9043052540b13d8120fb641de6337af46c3b36ef..a0f89e64b64640d2d4dbc14734868c4d4b03fc6f 100644 --- a/Source/WebCore/dom/DeviceOrientationEvent.idl +++ b/Source/WebCore/dom/DeviceOrientationEvent.idl @@ -25,6 +25,7 @@ [ Conditional=DEVICE_ORIENTATION, + EnabledBySetting=DeviceOrientationEventEnabled, Exposed=Window ] interface DeviceOrientationEvent : Event { readonly attribute unrestricted double? alpha; diff --git a/Source/WebCore/dom/Document+PointerLock.idl b/Source/WebCore/dom/Document+PointerLock.idl index 2e9c9fda6a920cd8904432bd1bdbfbf32d01c085..2fd33597e905b0544665ff765f310945305a0c4a 100644 --- a/Source/WebCore/dom/Document+PointerLock.idl +++ b/Source/WebCore/dom/Document+PointerLock.idl @@ -25,6 +25,7 @@ // https://w3c.github.io/pointerlock/#extensions-to-the-document-interface [ + EnabledBySetting=PointerLockEnabled, Conditional=POINTER_LOCK ] partial interface Document { attribute EventHandler onpointerlockchange; diff --git a/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl b/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl index 9b8dbfc15ce078702321abcd6c0e636df7a60510..2956f7098e87af10ab8f5584b456ce9a6d432a20 100644 --- a/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl +++ b/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl @@ -25,6 +25,7 @@ // https://w3c.github.io/pointerlock/#extensions-to-the-documentorshadowroot-mixin [ + EnabledBySetting=PointerLockEnabled, Conditional=POINTER_LOCK ] partial interface mixin DocumentOrShadowRoot { readonly attribute Element? pointerLockElement; diff --git a/Source/WebCore/dom/Element+PointerLock.idl b/Source/WebCore/dom/Element+PointerLock.idl index 9b344003de17b96d8b9ca8c7f32143a27543b1ea..2208a3f2b7d930bcd291e65b474d4c3023d2a7e4 100644 --- a/Source/WebCore/dom/Element+PointerLock.idl +++ b/Source/WebCore/dom/Element+PointerLock.idl @@ -24,6 +24,7 @@ */ [ + EnabledBySetting=PointerLockEnabled, Conditional=POINTER_LOCK ] partial interface Element { // Returns Promise if PointerLockOptionsEnabled Runtime Flag is set, otherwise returns undefined. diff --git a/Source/WebCore/dom/PointerEvent.cpp b/Source/WebCore/dom/PointerEvent.cpp index e0a0916f197cd80b728b89f95fb240374acdb78a..54eb987c3b53784263de9bdc2ee05c6ca8d68f53 100644 --- a/Source/WebCore/dom/PointerEvent.cpp +++ b/Source/WebCore/dom/PointerEvent.cpp @@ -28,9 +28,12 @@ #include "EventNames.h" #include "MouseEventTypes.h" +#include "MouseEvent.h" #include "Node.h" +#include "PlatformTouchEvent.h" #include "PointerEventTypeNames.h" #include +#include namespace WebCore { @@ -292,4 +295,59 @@ void PointerEvent::receivedTarget() predictedEvent->setTarget(this->target()); } +#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) && !PLATFORM(WPE) + +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 IntPoint& touchDelta) +{ + const auto& type = pointerEventType(event.touchPoints().at(touchIndex).state()); + return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, typeCanBubble(type), typeIsCancelable(type), touchIndex, isPrimary, WTFMove(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 IntPoint& touchDelta) +{ + const auto& type = pointerEventType(event.touchPoints().at(touchIndex).state()); + return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, canBubble, isCancelable, touchIndex, isPrimary, WTFMove(view), touchDelta)); +} + +Ref PointerEvent::create(const AtomString& type, const PlatformTouchEvent& event, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&& view, const IntPoint& touchDelta) +{ + return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, typeCanBubble(type), typeIsCancelable(type), touchIndex, isPrimary, WTFMove(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 IntPoint& touchDelta) + : MouseEvent(EventInterfaceType::PointerEvent, type, canBubble, isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTFMove(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, { }, { }, IsSimulated::No, IsTrusted::Yes) + , m_pointerId(event.touchPoints().at(touchIndex).id()) + , m_width(2 * event.touchPoints().at(touchIndex).radiusX()) + , m_height(2 * event.touchPoints().at(touchIndex).radiusY()) + , 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) + } // namespace WebCore diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h index b034595d01bb63f3d72183c427fcc14695339ae2..1886e4bbba04c6177fad1562c891f2aeff0a8247 100644 --- a/Source/WebCore/dom/PointerEvent.h +++ b/Source/WebCore/dom/PointerEvent.h @@ -34,6 +34,8 @@ #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) #include "PlatformTouchEventIOS.h" +#else +#include "PlatformTouchEvent.h" #endif #if ENABLE(TOUCH_EVENTS) && PLATFORM(WPE) @@ -94,7 +96,7 @@ 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)) +#if ENABLE(TOUCH_EVENTS) static Ref create(const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&&, const IntPoint& touchDelta = { }); static Ref create(const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, CanBubble, IsCancelable, unsigned touchIndex, bool isPrimary, Ref&& view, const IntPoint& touchDelta = { }); static Ref create(const AtomString& type, const PlatformTouchEvent&, const Vector>& coalescedEvents, const Vector>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref&&, const IntPoint& touchDelta = { }); @@ -173,7 +175,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)) +#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 IntPoint& touchDelta = { }); #endif diff --git a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp index 7813532cc52d582c42aebc979a1ecd1137765f08..c01cbd53ad2430a6ffab9a80fc73e74a8523800a 100644 --- a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp +++ b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp @@ -34,6 +34,7 @@ #include "NotImplemented.h" #include "Pasteboard.h" #include "Settings.h" +#include "WebContentReader.h" #include "markup.h" namespace WebCore { @@ -99,6 +100,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 75de5d5611953b830cf07d940ca1eedb789d2a9c..6adabe7a8250e02bc6b1e9fa28b0575d6a5e4dd7 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp @@ -37,6 +37,7 @@ #include "HTMLNames.h" #include "Icon.h" #include "InputTypeNames.h" +#include "InspectorInstrumentation.h" #include "LocalFrame.h" #include "LocalizedStrings.h" #include "MIMETypeRegistry.h" @@ -160,6 +161,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) if (protectedElement()->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/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp index dac15af852ff335ffba6b4bff717682a99b52b48..29bceeebb5a3e1c6c5d9d782dd62530d75b57d9a 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp @@ -295,6 +295,8 @@ void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel) // Unplug all instrumentations since they aren't needed now. InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get()); + + m_pauseOnStart = PauseCondition::DONT_PAUSE; } m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount()); @@ -314,6 +316,8 @@ void InspectorController::disconnectAllFrontends() // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow(). ASSERT(!m_inspectorFrontendClient); + m_pauseOnStart = PauseCondition::DONT_PAUSE; + if (!m_frontendRouter->hasFrontends()) return; @@ -397,8 +401,8 @@ void InspectorController::inspect(Node* node) if (!enabled()) return; - if (!hasRemoteFrontend()) - show(); + // HACK: Always attempt to show inspector even if there is a remote connection. + show(); ensureDOMAgent().inspect(node); } @@ -541,4 +545,34 @@ void InspectorController::didComposite(LocalFrame& frame) InspectorInstrumentation::didComposite(frame); } +void InspectorController::pauseOnStart(PauseCondition condition) +{ + m_pauseOnStart = condition; +} + +void InspectorController::resumeIfPausedInNewWindow() +{ + m_pauseOnStart = PauseCondition::DONT_PAUSE; +} + +void InspectorController::didFinishPageCreation() +{ + if (m_pauseOnStart == PauseCondition::WHEN_CREATION_FINISHED) + runLoopWhilePaused(); +} + +void InspectorController::didShowPage() +{ + if (m_pauseOnStart == PauseCondition::WHEN_SHOWN) + runLoopWhilePaused(); +} + +void InspectorController::runLoopWhilePaused() +{ + while (m_pauseOnStart != PauseCondition::DONT_PAUSE) { + if (RunLoop::cycle() == RunLoop::CycleResult::Stop) + break; + } +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorController.h b/Source/WebCore/inspector/InspectorController.h index 4f5c1e836876710a554455ec53733f72db63de58..774c4a66af84664a7a83ba0790d147f7bbb4236a 100644 --- a/Source/WebCore/inspector/InspectorController.h +++ b/Source/WebCore/inspector/InspectorController.h @@ -106,6 +106,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; } @@ -136,6 +142,7 @@ private: PageAgentContext pageAgentContext(); void createLazyAgents(); + void runLoopWhilePaused(); WeakRef m_page; Ref m_instrumentingAgents; @@ -159,6 +166,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/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp index 3d97cbaf887e52fe5c269cd4bc8cf750de41ddcb..46dc1872991560e41cff9c8b1ede2b73708c3736 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -595,6 +595,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 (auto* pageAgent = instrumentingAgents.enabledPageAgent()) @@ -678,6 +684,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()) @@ -710,20 +722,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { - if (!frame.isMainFrame()) - return; - if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->domContentEventFired(); + pageAgent->domContentEventFired(frame); } void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame* frame) { - if (!frame || !frame->isMainFrame()) + if (!frame) return; if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->loadEventFired(); + pageAgent->loadEventFired(*frame); } void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) @@ -803,12 +812,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins pageDOMDebuggerAgent->frameDocumentUpdated(frame); } -void InspectorInstrumentation::loaderDetachedFromFrameImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader& loader) -{ - if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) - inspectorPageAgent->loaderDetachedFromFrame(loader); -} - void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) { if (frame.isMainFrame()) { @@ -839,10 +842,10 @@ void InspectorInstrumentation::frameStoppedLoadingImpl(InstrumentingAgents& inst inspectorPageAgent->frameStoppedLoading(frame); } -void InspectorInstrumentation::frameScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, Seconds delay) +void InspectorInstrumentation::frameScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, Seconds delay, bool targetIsCurrentFrame) { if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) - inspectorPageAgent->frameScheduledNavigation(frame, delay); + inspectorPageAgent->frameScheduledNavigation(frame, delay, targetIsCurrentFrame); } void InspectorInstrumentation::frameClearedScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) @@ -857,6 +860,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) { @@ -909,6 +918,12 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru networkAgent->interceptResponse(response, identifier, WTFMove(handler)); } +void InspectorInstrumentation::setStoppingLoadingDueToProcessSwapImpl(InstrumentingAgents& instrumentingAgents, bool value) +{ + if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) + networkAgent->setStoppingLoadingDueToProcessSwap(value); +} + // JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes. static bool isConsoleAssertMessage(MessageSource source, MessageType type) { @@ -1027,6 +1042,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()) @@ -1317,6 +1338,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; @@ -1333,6 +1384,13 @@ InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(Page& page) return page.inspectorController().m_instrumentingAgents.get(); } +void InspectorInstrumentation::maybeOverrideDefaultObjectInclusion(Page& page, AccessibilityObjectInclusion& inclusion) { + if (InspectorPageAgent* pageAgent = instrumentingAgents(page).enabledPageAgent()) { + if (pageAgent->doingAccessibilitySnapshot()) + inclusion = AccessibilityObjectInclusion::DefaultBehavior; + } +} + InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext& context) { // Using RefPtr makes us hit the m_inRemovedLastRefFunction assert. diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index 0fb5a57841daca73bbc452b6bbe97d8bbb25500e..7aac51c58d0fc3640fcaf7f9cdf0776367020f9e 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -31,6 +31,7 @@ #pragma once +#include "AXCoreObject.h" #include "CSSSelector.h" #include "CanvasBase.h" #include "CanvasRenderingContext.h" @@ -44,6 +45,7 @@ #include "LocalFrame.h" #include "LocalFrameView.h" #include "Page.h" +#include "ResourceError.h" #include "ResourceLoader.h" #include "ResourceLoaderIdentifier.h" #include "StorageArea.h" @@ -77,6 +79,7 @@ class DOMWrapperWorld; class Document; class DocumentLoader; class EventListener; +class HTMLInputElement; class HTTPHeaderMap; class InspectorTimelineAgent; class InstrumentingAgents; @@ -196,6 +199,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&); @@ -208,6 +212,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&); @@ -234,13 +239,13 @@ 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(Frame&); - static void frameScheduledNavigation(Frame&, Seconds delay); + static void frameScheduledNavigation(Frame&, Seconds delay, bool targetIsCurrentFrame); static void frameClearedScheduledNavigation(Frame&); static void accessibilitySettingsDidChange(Page&); + static void didNavigateWithinPage(LocalFrame&); #if ENABLE(DARK_MODE_CSS) static void defaultAppearanceDidChange(Page&); #endif @@ -251,6 +256,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(Page&, std::unique_ptr); static void addMessageToConsole(WorkerOrWorkletGlobalScope&, std::unique_ptr); @@ -272,6 +278,7 @@ public: static void stopProfiling(Page&, 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); @@ -325,6 +332,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(); } @@ -341,6 +354,8 @@ public: static void registerInstrumentingAgents(InstrumentingAgents&); static void unregisterInstrumentingAgents(InstrumentingAgents&); + static void maybeOverrideDefaultObjectInclusion(Page&, AccessibilityObjectInclusion&); + private: static void didClearWindowObjectInWorldImpl(InstrumentingAgents&, LocalFrame&, DOMWrapperWorld&); static bool isDebuggerPausedImpl(InstrumentingAgents&); @@ -422,6 +437,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&); @@ -436,6 +452,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); @@ -446,13 +463,13 @@ 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 frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay); + static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay, bool targetIsCurrentFrame); static void frameClearedScheduledNavigationImpl(InstrumentingAgents&, Frame&); static void accessibilitySettingsDidChangeImpl(InstrumentingAgents&); + static void didNavigateWithinPageImpl(InstrumentingAgents&, LocalFrame&); #if ENABLE(DARK_MODE_CSS) static void defaultAppearanceDidChangeImpl(InstrumentingAgents&); #endif @@ -463,6 +480,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); @@ -477,6 +495,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); @@ -530,6 +549,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& instrumentingAgents(Page&); static InstrumentingAgents& instrumentingAgents(WorkerOrWorkletGlobalScope&); static InstrumentingAgents& instrumentingAgents(ServiceWorkerGlobalScope&); @@ -1089,6 +1114,13 @@ inline void InspectorInstrumentation::applyUserAgentOverride(LocalFrame& frame, applyUserAgentOverrideImpl(*agents, userAgent); } +inline void InspectorInstrumentation::applyPlatformOverride(LocalFrame& frame, String& platform) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + applyPlatformOverrideImpl(*agents, platform); +} + inline void InspectorInstrumentation::applyEmulatedMedia(LocalFrame& frame, AtomString& media) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1191,6 +1223,13 @@ 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()); + if (auto* agents = instrumentingAgents(frame)) + didReceiveMainResourceErrorImpl(*agents, frame, error); +} + inline void InspectorInstrumentation::continueAfterXFrameOptionsDenied(LocalFrame& frame, ResourceLoaderIdentifier identifier, DocumentLoader& loader, const ResourceResponse& response) { // Treat the same as didReceiveResponse. @@ -1281,13 +1320,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(LocalFrame& frame) frameDocumentUpdatedImpl(*agents, frame); } -inline void InspectorInstrumentation::loaderDetachedFromFrame(LocalFrame& frame, DocumentLoader& loader) -{ - FAST_RETURN_IF_NO_FRONTENDS(void()); - if (auto* agents = instrumentingAgents(frame)) - loaderDetachedFromFrameImpl(*agents, loader); -} - inline void InspectorInstrumentation::frameStartedLoading(LocalFrame& frame) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1309,11 +1341,11 @@ inline void InspectorInstrumentation::frameStoppedLoading(LocalFrame& frame) frameStoppedLoadingImpl(*agents, frame); } -inline void InspectorInstrumentation::frameScheduledNavigation(Frame& frame, Seconds delay) +inline void InspectorInstrumentation::frameScheduledNavigation(Frame& frame, Seconds delay, bool targetIsCurrentFrame) { FAST_RETURN_IF_NO_FRONTENDS(void()); if (auto* agents = instrumentingAgents(frame)) - frameScheduledNavigationImpl(*agents, frame, delay); + frameScheduledNavigationImpl(*agents, frame, delay, targetIsCurrentFrame); } inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& frame) @@ -1329,6 +1361,13 @@ inline void InspectorInstrumentation::accessibilitySettingsDidChange(Page& page) accessibilitySettingsDidChangeImpl(instrumentingAgents(page)); } +inline void InspectorInstrumentation::didNavigateWithinPage(LocalFrame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + didNavigateWithinPageImpl(*agents, frame); +} + #if ENABLE(DARK_MODE_CSS) inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page) { @@ -1381,6 +1420,13 @@ inline void InspectorInstrumentation::interceptResponse(const LocalFrame& frame, interceptResponseImpl(*agents, response, identifier, WTFMove(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()); @@ -1697,6 +1743,11 @@ inline void InspectorInstrumentation::performanceMark(ScriptExecutionContext& co performanceMarkImpl(*agents, label, WTFMove(startTime)); } +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()); @@ -1753,6 +1804,42 @@ 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()); + if (auto* agents = instrumentingAgents(*frame)) + runOpenPanelImpl(*agents, 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()); + if (auto* agents = instrumentingAgents(frame)) + willCheckNavigationPolicyImpl(*agents, frame); +} + +inline void InspectorInstrumentation::didCheckNavigationPolicy(LocalFrame& frame, bool cancel) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + didCheckNavigationPolicyImpl(*agents, 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 a67a1244fa526ad5759068e97e0d220f59565d6e..0048589109fccb9472fe35a410337771b1063d72 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, WTFMove(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 c028341e84e59a6b1b16107fd74feb21f70b12ab..d385418ac34e8f315f201801a2c65226c8f6fee2 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, WTFMove(handler)); } +inline void InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(Page* page, bool value) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + setStoppingLoadingDueToProcessSwapInternal(page, value); +} + } diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp index 5bd7a42c19fd11234eea0520ebf61f7f820f765e..a70339c639682820de7ff09d62e8cfd42a7d7060 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -56,6 +56,7 @@ #include "Cookie.h" #include "CookieJar.h" #include "CustomElementRegistry.h" +#include "DirectoryFileListCreator.h" #include "DOMEditor.h" #include "DOMException.h" #include "DOMPatchSupport.h" @@ -67,9 +68,14 @@ #include "Event.h" #include "EventListener.h" #include "EventNames.h" +#include "File.h" +#include +#include "FileList.h" +#include "FloatQuad.h" #include "FrameTree.h" #include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "HTMLScriptElement.h" @@ -104,12 +110,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" @@ -151,7 +159,8 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const UChar horizontalEllipsisUChar[] = { horizontalEllipsis, 0 }; -static std::optional parseColor(RefPtr&& colorObject) +// static +std::optional InspectorDOMAgent::parseColor(RefPtr&& colorObject) { if (!colorObject) return std::nullopt; @@ -170,7 +179,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) @@ -197,6 +206,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); @@ -477,6 +500,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin return node.get(); } +Node* InspectorDOMAgent::assertNode(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); @@ -1595,16 +1632,7 @@ Inspector::Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::o Inspector::Protocol::ErrorStringOr InspectorDOMAgent::highlightNode(std::optional&& nodeId, const Inspector::Protocol::Runtime::RemoteObjectId& objectId, Ref&& highlightInspectorObject, RefPtr&& gridOverlayInspectorObject, RefPtr&& flexOverlayInspectorObject, std::optional&& showRulers) { Inspector::Protocol::ErrorString errorString; - - Node* node = nullptr; - 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; - + Node* node = assertNode(errorString, WTFMove(nodeId), objectId); if (!node) return makeUnexpected(errorString); @@ -1859,15 +1887,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 } }; +} + +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 { }; +} + +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; + Node* node = nullptr; + if (!!frameId) { + auto* pageAgent = m_instrumentingAgents.enabledPageAgent(); + if (!pageAgent) + return makeUnexpected("Page domain must be enabled"_s); - Node* node = assertNode(errorString, nodeId); + auto* frame = pageAgent->assertFrame(errorString, frameId); + if (!frame) + return makeUnexpected(errorString); + + node = frame->ownerElement(); + } else { + node = assertNode(errorString, WTFMove(nodeId), objectId); + } if (!node) return makeUnexpected(errorString); - auto object = resolveNode(node, objectGroup); + auto object = resolveNode(node, objectGroup, WTFMove(contextId)); if (!object) return makeUnexpected("Missing injected script for given nodeId"_s); @@ -3133,7 +3305,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) { Document* document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) @@ -3142,12 +3314,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) @@ -3255,4 +3433,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() != Node::ELEMENT_NODE || 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 = WTFMove(callback)](Ref&& fileList) mutable { + ASSERT(isMainThread()); + element->setFiles(WTFMove(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(WTFMove(fileObjects)); + element->setFiles(WTFMove(fileList)); + callback->sendSuccess(); + } +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h index c8602dd6236d299df04b28b456b4d4ab6348c6eb..15128978fa8d64b6413b82ce9991dd708d50271b 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -59,6 +59,7 @@ namespace WebCore { class AXCoreObject; class CharacterData; +class Color; class DOMEditor; class Document; class Element; @@ -94,6 +95,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. @@ -139,7 +141,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); @@ -176,6 +178,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&); @@ -217,7 +223,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*); @@ -229,12 +235,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(); @@ -264,7 +273,6 @@ private: void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf&); Node* 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 263890779b1a012b1ae1fe9145f4a7af494a581c..dc83cf514b03a80ceff036248147203898a4e113 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp @@ -58,6 +58,7 @@ #include "LocalFrame.h" #include "MIMETypeRegistry.h" #include "MemoryCache.h" +#include "NetworkStateNotifier.h" #include "Page.h" #include "PlatformStrategies.h" #include "ProgressTracker.h" @@ -343,8 +344,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) { @@ -397,6 +398,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)); @@ -683,6 +686,9 @@ void InspectorNetworkAgent::didFailLoading(ResourceLoaderIdentifier identifier, String requestId = IdentifiersFactory::requestId(identifier.toUInt64()); if (loader && m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) { + if (m_stoppingLoadingDueToProcessSwap) + return; + auto* frame = loader->frame(); if (frame && frame->loader().documentLoader() && frame->document()) { m_resourcesData->addResourceSharedBuffer(requestId, @@ -912,6 +918,7 @@ Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::disable() m_instrumentingAgents.setEnabledNetworkAgent(nullptr); m_resourcesData->clear(); m_extraRequestHeaders.clear(); + m_stoppingLoadingDueToProcessSwap = false; continuePendingRequests(); continuePendingResponses(); @@ -957,6 +964,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) @@ -1206,6 +1214,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) { @@ -1235,6 +1248,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)); @@ -1330,14 +1346,23 @@ 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(WTFMove(explicitHeaders)); response.setHTTPHeaderField(HTTPHeaderName::ContentType, response.mimeType()); - loader->didReceiveResponse(response, [loader, buffer = data.releaseNonNull()]() { + + auto* frame = loader->frame(); + if (!setCookieValue.isEmpty() && frame && frame->page()) + frame->page()->cookieJar().setCookieFromResponse(*loader.get(), setCookieValue); + + loader->didReceiveResponse(response, [loader, buffer = data.releaseNonNull()]() mutable { if (loader->reachedTerminalState()) return; @@ -1400,6 +1425,12 @@ Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::setEmulatedCondi #endif // ENABLE(INSPECTOR_NETWORK_THROTTLING) +Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::setEmulateOfflineState(bool offline) +{ + platformStrategies()->loaderStrategy()->setEmulateOfflineState(offline); + return { }; +} + bool InspectorNetworkAgent::shouldTreatAsText(const String& mimeType) { return startsWithLettersIgnoringASCIICase(mimeType, "text/"_s) diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h index de6b2dd844943074c5a383c7b9b8ccba1c96419a..7a3404f2380b5e62f1c0523a70f8ef442014759d 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 @@ -104,6 +106,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 willRecalculateStyle(); @@ -135,6 +138,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>&); @@ -275,6 +279,7 @@ private: bool m_enabled { false }; bool m_loadingXHRSynchronously { false }; bool m_interceptionEnabled { false }; + bool m_stoppingLoadingDueToProcessSwap { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp index c7c930db458419ffdf3d10b9a7db0d3c2b9615a1..6253804039ea38105bb7647082752cafdd08d895 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp @@ -32,19 +32,27 @@ #include "config.h" #include "InspectorPageAgent.h" +#include "AXCoreObject.h" +#include "AXObjectCache.h" +#include "BackForwardController.h" #include "CachedResource.h" #include "CachedResourceLoader.h" #include "Cookie.h" #include "CookieJar.h" +#include "CustomHeaderFields.h" #include "DOMWrapperWorld.h" #include "DocumentInlines.h" #include "DocumentLoader.h" +#include "Editor.h" #include "ElementInlines.h" +#include "FocusController.h" #include "ForcedAccessibilityValue.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" +#include "FrameLoaderClient.h" #include "FrameSnapshotting.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" #include "InspectorClient.h" @@ -57,24 +65,38 @@ #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "Page.h" +#include "PageRuntimeAgent.h" +#include "PlatformScreen.h" #include "RenderObject.h" #include "RenderTheme.h" +#include "DeprecatedGlobalSettings.h" +#include "SimpleRange.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 +#include "TextIterator.h" +#include "TypingCommand.h" #include "UserGestureIndicator.h" #include #include +#include #include +#include #include +#include +#include +#include +#include #include #include #include +#include #include #if ENABLE(APPLICATION_MANIFEST) @@ -96,6 +118,11 @@ using namespace Inspector; WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorPageAgent); +static UncheckedKeyHashMap>& createdUserWorlds() { + static NeverDestroyed>> nameToWorld; + return nameToWorld; +} + static bool decodeBuffer(std::span buffer, const String& textEncodingName, String* result) { if (buffer.data()) { @@ -348,6 +375,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien , m_frontendDispatcher(makeUnique(context.frontendRouter)) , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this)) , m_inspectedPage(context.inspectedPage) + , m_injectedScriptManager(context.injectedScriptManager) , m_client(client) , m_overlay(overlay) { @@ -377,12 +405,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() { m_instrumentingAgents.setEnabledPageAgent(nullptr); + m_interceptFileChooserDialog = false; + m_bypassCSP = false; setShowPaintRects(false); #if !PLATFORM(IOS_FAMILY) @@ -435,6 +471,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::navigate(const String& url) { RefPtr localMainFrame = m_inspectedPage->localMainFrame(); @@ -461,6 +513,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(); @@ -474,6 +533,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value); return { }; +#if ENABLE(DEVICE_ORIENTATION) + case Protocol::Page::Setting::DeviceOrientationEventEnabled: + inspectedPageSettings.setDeviceOrientationEventEnabled(value.value_or(false)); + return { }; +#endif + case Inspector::Protocol::Page::Setting::ICECandidateFilteringEnabled: inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value); return { }; @@ -500,6 +565,39 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins m_client->setDeveloperPreferenceOverride(InspectorClient::DeveloperPreference::NeedsSiteSpecificQuirks, value); return { }; +#if ENABLE(NOTIFICATIONS) + case Protocol::Page::Setting::NotificationsEnabled: + inspectedPageSettings.setNotificationsEnabled(value.value_or(false)); + return { }; +#endif + +#if ENABLE(FULLSCREEN_API) + case Protocol::Page::Setting::FullScreenEnabled: + inspectedPageSettings.setFullScreenEnabled(value.value_or(false)); + return { }; +#endif + + case Protocol::Page::Setting::InputTypeMonthEnabled: + inspectedPageSettings.setInputTypeMonthEnabled(value.value_or(false)); + return { }; + + case Protocol::Page::Setting::InputTypeWeekEnabled: + inspectedPageSettings.setInputTypeWeekEnabled(value.value_or(false)); + return { }; + + case 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 Protocol::Page::Setting::PointerLockEnabled: + inspectedPageSettings.setPointerLockEnabled(value.value_or(false)); + return { }; +#endif + case Inspector::Protocol::Page::Setting::ScriptEnabled: inspectedPageSettings.setScriptEnabledInspectorOverride(value); return { }; @@ -512,6 +610,12 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Ins inspectedPageSettings.setShowRepaintCounterInspectorOverride(value); return { }; +#if ENABLE(MEDIA_STREAM) + case Protocol::Page::Setting::SpeechRecognitionEnabled: + inspectedPageSettings.setSpeechRecognitionEnabled(value.value_or(false)); + return { }; +#endif + case Inspector::Protocol::Page::Setting::WebSecurityEnabled: inspectedPageSettings.setWebSecurityEnabledInspectorOverride(value); return { }; @@ -920,15 +1024,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) @@ -936,13 +1041,29 @@ 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_frameToIdentifier.take(frame); - if (identifier.isNull()) + String identifier = serializeFrameID(frame.frameID()); + if (!m_identifierToFrame.take(identifier)) return; + m_frontendDispatcher->frameDetached(identifier); - m_identifierToFrame.remove(identifier); } Frame* InspectorPageAgent::frameForId(const Inspector::Protocol::Network::FrameId& frameId) @@ -954,20 +1075,21 @@ String InspectorPageAgent::frameId(Frame* frame) { if (!frame) return emptyString(); - return m_frameToIdentifier.ensure(*frame, [this, frame] { - auto identifier = IdentifiersFactory::createIdentifier(); - m_identifierToFrame.set(identifier, frame); - return identifier; - }).iterator->value; + String identifier = serializeFrameID(frame->frameID()); + m_identifierToFrame.set(identifier, frame); + return identifier; } String InspectorPageAgent::loaderId(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()); } LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& errorString, const Inspector::Protocol::Network::FrameId& frameId) @@ -978,11 +1100,6 @@ LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& er return frame; } -void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader) -{ - m_loaderToIdentifier.remove(&loader); -} - void InspectorPageAgent::frameStartedLoading(LocalFrame& frame) { m_frontendDispatcher->frameStartedLoading(frameId(&frame)); @@ -993,9 +1110,9 @@ void InspectorPageAgent::frameStoppedLoading(LocalFrame& frame) m_frontendDispatcher->frameStoppedLoading(frameId(&frame)); } -void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay) +void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay, bool targetIsCurrentFrame) { - m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value()); + m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value(), targetIsCurrentFrame); } void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame) @@ -1042,6 +1159,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange() m_frontendDispatcher->defaultUserPreferencesDidChange(WTFMove(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() { @@ -1055,6 +1178,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 })); @@ -1102,6 +1228,51 @@ void InspectorPageAgent::didRecalculateStyle() protectedOverlay()->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); @@ -1195,6 +1366,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()) @@ -1222,11 +1399,13 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Insp return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } -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 { { }, ImageBufferPixelFormat::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(); @@ -1240,6 +1419,43 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } +Protocol::ErrorStringOr InspectorPageAgent::setForcedColors(std::optional&& forcedColors) +{ + if (!forcedColors) { + m_inspectedPage->setUseForcedColorsOverride(std::nullopt); + return { }; + } + + switch (*forcedColors) { + case Protocol::Page::ForcedColors::Active: + m_inspectedPage->setUseForcedColorsOverride(true); + return { }; + case Protocol::Page::ForcedColors::None: + m_inspectedPage->setUseForcedColorsOverride(false); + return { }; + } + + ASSERT_NOT_REACHED(); + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::setTimeZone(const String& timeZone) +{ + bool success = WTF::setTimeZoneOverride(timeZone); + if (!success) + return makeUnexpected(makeString("Invalid time zone "_s, timeZone)); + + return { }; +} + +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() { @@ -1256,7 +1472,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()) @@ -1274,6 +1489,496 @@ Inspector::Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverri localMainFrame->setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); return { }; } -#endif + +Protocol::ErrorStringOr InspectorPageAgent::insertText(const String& text) +{ + UserGestureIndicator indicator { IsProcessingUserGesture::Yes }; + RefPtr frame = m_inspectedPage->checkedFocusController()->focusedOrMainFrame(); + if (!frame) + return { }; + + if (frame->editor().hasComposition()) { + frame->editor().confirmComposition(text); + } else { + Document* focusedDocument = frame->document(); + TypingCommand::insertText(*focusedDocument, text, nullptr, { }); + } + return { }; +} + +static String roleFromObject(RefPtr axObject) +{ + String computedRoleString = axObject->computedRoleString(); + if (!computedRoleString.isEmpty()) + return computedRoleString; + AccessibilityRole role = axObject->roleValue(); + switch(role) { + case AccessibilityRole::Application: + return "Application"_s; + case AccessibilityRole::ApplicationAlert: + return "ApplicationAlert"_s; + case AccessibilityRole::ApplicationAlertDialog: + return "ApplicationAlertDialog"_s; + case AccessibilityRole::ApplicationDialog: + return "ApplicationDialog"_s; + case AccessibilityRole::ApplicationLog: + return "ApplicationLog"_s; + case AccessibilityRole::ApplicationMarquee: + return "ApplicationMarquee"_s; + case AccessibilityRole::ApplicationStatus: + return "ApplicationStatus"_s; + case AccessibilityRole::ApplicationTimer: + return "ApplicationTimer"_s; + case AccessibilityRole::Audio: + return "Audio"_s; + case AccessibilityRole::Blockquote: + return "Blockquote"_s; + case AccessibilityRole::Button: + return "Button"_s; + case AccessibilityRole::Canvas: + return "Canvas"_s; + case AccessibilityRole::Caption: + return "Caption"_s; + case AccessibilityRole::Cell: + return "Cell"_s; + case AccessibilityRole::Checkbox: + return "CheckBox"_s; + case AccessibilityRole::Code: + return "Code"_s; + case AccessibilityRole::ColorWell: + return "ColorWell"_s; + case AccessibilityRole::Column: + return "Column"_s; + case AccessibilityRole::ColumnHeader: + return "ColumnHeader"_s; + case AccessibilityRole::ComboBox: + return "ComboBox"_s; + case AccessibilityRole::DateTime: + return "DateTime"_s; + case AccessibilityRole::Definition: + return "Definition"_s; + case AccessibilityRole::Deletion: + return "Deletion"_s; + case AccessibilityRole::DescriptionList: + return "DescriptionList"_s; + case AccessibilityRole::DescriptionListTerm: + return "DescriptionListTerm"_s; + case AccessibilityRole::DescriptionListDetail: + return "DescriptionListDetail"_s; + case AccessibilityRole::Details: + return "Details"_s; + case AccessibilityRole::Directory: + return "Directory"_s; + case AccessibilityRole::Document: + return "Document"_s; + case AccessibilityRole::DocumentArticle: + return "DocumentArticle"_s; + case AccessibilityRole::DocumentMath: + return "DocumentMath"_s; + case AccessibilityRole::DocumentNote: + return "DocumentNote"_s; + case AccessibilityRole::Emphasis: + return "Emphasis"_s; + case AccessibilityRole::Feed: + return "Feed"_s; + case AccessibilityRole::Figure: + return "Figure"_s; + case AccessibilityRole::Footer: + return "Footer"_s; + case AccessibilityRole::Footnote: + return "Footnote"_s; + case AccessibilityRole::Form: + return "Form"_s; + case AccessibilityRole::Generic: + return "Generic"_s; + case AccessibilityRole::GraphicsDocument: + return "GraphicsDocument"_s; + case AccessibilityRole::GraphicsObject: + return "GraphicsObject"_s; + case AccessibilityRole::GraphicsSymbol: + return "GraphicsSymbol"_s; + case AccessibilityRole::Grid: + return "Grid"_s; + case AccessibilityRole::GridCell: + return "GridCell"_s; + case AccessibilityRole::Group: + return "Group"_s; + case AccessibilityRole::Heading: + return "Heading"_s; + case AccessibilityRole::HorizontalRule: + return "HorizontalRule"_s; + case AccessibilityRole::Ignored: + return "Ignored"_s; + case AccessibilityRole::Inline: + return "Inline"_s; + case AccessibilityRole::Image: + return "Image"_s; + case AccessibilityRole::ImageMap: + return "ImageMap"_s; + case AccessibilityRole::Insertion: + return "Insertion"_s; + case AccessibilityRole::Label: + return "Label"_s; + case AccessibilityRole::LandmarkBanner: + return "LandmarkBanner"_s; + case AccessibilityRole::LandmarkComplementary: + return "LandmarkComplementary"_s; + case AccessibilityRole::LandmarkContentInfo: + return "LandmarkContentInfo"_s; + case AccessibilityRole::LandmarkDocRegion: + return "LandmarkDocRegion"_s; + case AccessibilityRole::LandmarkMain: + return "LandmarkMain"_s; + case AccessibilityRole::LandmarkNavigation: + return "LandmarkNavigation"_s; + case AccessibilityRole::LandmarkRegion: + return "LandmarkRegion"_s; + case AccessibilityRole::LandmarkSearch: + return "LandmarkSearch"_s; + case AccessibilityRole::Legend: + return "Legend"_s; + case AccessibilityRole::LineBreak: + return "LineBreak"_s; + case AccessibilityRole::Link: + return "Link"_s; + case AccessibilityRole::List: + return "List"_s; + case AccessibilityRole::ListBox: + return "ListBox"_s; + case AccessibilityRole::ListBoxOption: + return "ListBoxOption"_s; + case AccessibilityRole::ListItem: + return "ListItem"_s; + case AccessibilityRole::ListMarker: + return "ListMarker"_s; + case AccessibilityRole::Mark: + return "Mark"_s; + case AccessibilityRole::MathElement: + return "MathElement"_s; + case AccessibilityRole::Menu: + return "Menu"_s; + case AccessibilityRole::MenuBar: + return "MenuBar"_s; + case AccessibilityRole::MenuItem: + return "MenuItem"_s; + case AccessibilityRole::MenuItemCheckbox: + return "MenuItemCheckbox"_s; + case AccessibilityRole::MenuItemRadio: + return "MenuItemRadio"_s; + case AccessibilityRole::MenuListPopup: + return "MenuListPopup"_s; + case AccessibilityRole::MenuListOption: + return "MenuListOption"_s; + case AccessibilityRole::Meter: + return "Meter"_s; + case AccessibilityRole::Model: + return "Model"_s; + case AccessibilityRole::Paragraph: + return "Paragraph"_s; + case AccessibilityRole::PopUpButton: + return "PopUpButton"_s; + case AccessibilityRole::Pre: + return "Pre"_s; + case AccessibilityRole::Presentational: + return "Presentational"_s; + case AccessibilityRole::ProgressIndicator: + return "ProgressIndicator"_s; + case AccessibilityRole::RadioButton: + return "RadioButton"_s; + case AccessibilityRole::RadioGroup: + return "RadioGroup"_s; + case AccessibilityRole::RemoteFrame: + return "RemoteFrame"_s; + case AccessibilityRole::RowHeader: + return "RowHeader"_s; + case AccessibilityRole::Row: + return "Row"_s; + case AccessibilityRole::RowGroup: + return "RowGroup"_s; + case AccessibilityRole::RubyInline: + return "RubyInline"_s; + case AccessibilityRole::RubyText: + return "RubyText"_s; + case AccessibilityRole::ScrollArea: + return "ScrollArea"_s; + case AccessibilityRole::ScrollBar: + return "ScrollBar"_s; + case AccessibilityRole::SearchField: + return "SearchField"_s; + case AccessibilityRole::Slider: + return "Slider"_s; + case AccessibilityRole::SliderThumb: + return "SliderThumb"_s; + case AccessibilityRole::SpinButton: + return "SpinButton"_s; + case AccessibilityRole::SpinButtonPart: + return "SpinButtonPart"_s; + case AccessibilityRole::Splitter: + return "Splitter"_s; + case AccessibilityRole::StaticText: + return "StaticText"_s; + case AccessibilityRole::Strong: + return "Strong"_s; + case AccessibilityRole::Subscript: + return "Subscript"_s; + case AccessibilityRole::Suggestion: + return "Suggestion"_s; + case AccessibilityRole::Summary: + return "Summary"_s; + case AccessibilityRole::Superscript: + return "Superscript"_s; + case AccessibilityRole::Switch: + return "Switch"_s; + case AccessibilityRole::SVGRoot: + return "SVGRoot"_s; + case AccessibilityRole::SVGText: + return "SVGText"_s; + case AccessibilityRole::SVGTSpan: + return "SVGTSpan"_s; + case AccessibilityRole::SVGTextPath: + return "SVGTextPath"_s; + case AccessibilityRole::TabGroup: + return "TabGroup"_s; + case AccessibilityRole::TabList: + return "TabList"_s; + case AccessibilityRole::TabPanel: + return "TabPanel"_s; + case AccessibilityRole::Tab: + return "Tab"_s; + case AccessibilityRole::Table: + return "Table"_s; + case AccessibilityRole::TableHeaderContainer: + return "TableHeaderContainer"_s; + case AccessibilityRole::TextArea: + return "TextArea"_s; + case AccessibilityRole::TextGroup: + return "TextGroup"_s; + case AccessibilityRole::Term: + return "Term"_s; + case AccessibilityRole::Time: + return "Time"_s; + case AccessibilityRole::Tree: + return "Tree"_s; + case AccessibilityRole::TreeGrid: + return "TreeGrid"_s; + case AccessibilityRole::TreeItem: + return "TreeItem"_s; + case AccessibilityRole::TextField: + return "TextField"_s; + case AccessibilityRole::ToggleButton: + return "ToggleButton"_s; + case AccessibilityRole::Toolbar: + return "Toolbar"_s; + case AccessibilityRole::Unknown: + return "Unknown"_s; + case AccessibilityRole::UserInterfaceTooltip: + return "UserInterfaceTooltip"_s; + case AccessibilityRole::Video: + return "Video"_s; + case AccessibilityRole::WebApplication: + return "WebApplication"_s; + case AccessibilityRole::WebArea: + return "WebArea"_s; + case AccessibilityRole::WebCoreLink: + return "WebCoreLink"_s; + }; + return "Unknown"_s; +} + +static Ref snapshotForAXObject(WTF::RefPtr axObject, Node* nodeToFind) +{ + auto axNode = Inspector::Protocol::Page::AXNode::create() + .setRole(roleFromObject(axObject)) + .release(); + auto* liveObject = dynamicDowncast(axObject.get()); + + if (liveObject && !liveObject->computedLabel().isEmpty()) + axNode->setName(liveObject->computedLabel()); + if (!axObject->stringValue().isEmpty()) + axNode->setValue(JSON::Value::create(axObject->stringValue())); + if (liveObject && !liveObject->description().isEmpty()) + axNode->setDescription(liveObject->description()); + if (!axObject->keyShortcuts().isEmpty()) + axNode->setKeyshortcuts(axObject->keyShortcuts()); + if (!axObject->valueDescription().isEmpty()) + axNode->setValuetext(axObject->valueDescription()); + if (!axObject->roleDescription().isEmpty()) + axNode->setRoledescription(axObject->roleDescription()); + if (!axObject->isEnabled()) + axNode->setDisabled(!axObject->isEnabled()); + if (axObject->supportsExpanded()) + axNode->setExpanded(axObject->isExpanded()); + if (axObject->isFocused()) + axNode->setFocused(axObject->isFocused()); + if (axObject->isModalNode()) + axNode->setModal(axObject->isModalNode()); + if (axObject->isMultiSelectable()) + axNode->setMultiselectable(axObject->isMultiSelectable()); + if (liveObject && liveObject->supportsReadOnly() && !axObject->canSetValueAttribute() && axObject->isEnabled()) + axNode->setReadonly(true); + if (axObject->supportsRequiredAttribute()) + axNode->setRequired(axObject->isRequired()); + if (axObject->isSelected()) + axNode->setSelected(axObject->isSelected()); + if (axObject->supportsChecked()) { + AccessibilityButtonState checkedState = axObject->checkboxOrRadioValue(); + switch (checkedState) { + case AccessibilityButtonState::On: + axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::True); + break; + case AccessibilityButtonState::Off: + axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::False); + break; + case AccessibilityButtonState::Mixed: + axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::Mixed); + break; + } + } + unsigned level = axObject->hierarchicalLevel() ? axObject->hierarchicalLevel() : axObject->headingLevel(); + if (level) + axNode->setLevel(level); + if (axObject->minValueForRange() != 0) + axNode->setValuemin(axObject->minValueForRange()); + if (axObject->maxValueForRange() != 0) + axNode->setValuemax(axObject->maxValueForRange()); + if (liveObject && liveObject->supportsAutoComplete()) + axNode->setAutocomplete(axObject->autoCompleteValue()); + if (axObject->hasPopup()) + axNode->setHaspopup(axObject->popupValue()); + + String invalidValue = axObject->invalidStatus(); + if (invalidValue != "false"_s) { + if (invalidValue == "grammar"_s) + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Grammar); + else if (invalidValue == "spelling"_s) + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Spelling); + else // Future versions of ARIA may allow additional truthy values. Ex. format, order, or size. + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::True); + } + switch (axObject->orientation()) { + case AccessibilityOrientation::Undefined: + break; + case AccessibilityOrientation::Vertical: + axNode->setOrientation("vertical"_s); + break; + case AccessibilityOrientation::Horizontal: + axNode->setOrientation("horizontal"_s); + break; + } + + if (axObject->isKeyboardFocusable()) + axNode->setFocusable(axObject->isKeyboardFocusable()); + + if (nodeToFind && axObject->node() == nodeToFind) + axNode->setFound(true); + + if (!axObject->children().isEmpty()) { + Ref> children = JSON::ArrayOf::create(); + for (auto& childObject : axObject->children()) + children->addItem(snapshotForAXObject(childObject.ptr(), nodeToFind)); + axNode->setChildren(WTFMove(children)); + } + return axNode; +} + + +Protocol::ErrorStringOr> InspectorPageAgent::accessibilitySnapshot(const String& objectId) +{ + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); + + auto* localMainFrame = dynamicDowncast(m_inspectedPage->mainFrame()); + if (!localMainFrame) + return makeUnexpected("No local main frame"_s); + + RefPtr document = localMainFrame->document(); + if (!document) + return makeUnexpected("No document for main frame"_s); + + AXObjectCache* axObjectCache = document->axObjectCache(); + if (!axObjectCache) + return makeUnexpected("No AXObjectCache for main document"_s); + + AXCoreObject* axObject = axObjectCache->rootObjectForFrame(*localMainFrame); + if (!axObject) + return makeUnexpected("No AXObject for main document"_s); + + Node* node = nullptr; + if (!objectId.isEmpty()) { + InspectorDOMAgent* domAgent = m_instrumentingAgents.persistentDOMAgent(); + ASSERT(domAgent); + node = domAgent->nodeForObjectId(objectId); + if (!node) + return makeUnexpected("No Node for objectId"_s); + } + + m_doingAccessibilitySnapshot = true; + Ref axNode = snapshotForAXObject(RefPtr { axObject }, node); + m_doingAccessibilitySnapshot = false; + return axNode; +} + +Protocol::ErrorStringOr InspectorPageAgent::setInterceptFileChooserDialog(bool enabled) +{ + m_interceptFileChooserDialog = enabled; + return { }; +} + +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(WTFMove(color))); + return { }; +} + +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, WTFMove(world)); + return { }; +} + +void InspectorPageAgent::ensureUserWorldsExistInAllFrames(const Vector& worlds) +{ + for (Frame* frame = &m_inspectedPage->mainFrame(); frame; frame = frame->tree().traverseNext()) { + auto* localFrame = dynamicDowncast(frame); + for (auto* world : worlds) + localFrame->windowProxy().jsWindowProxy(*world)->window(); + } +} + +Protocol::ErrorStringOr InspectorPageAgent::setBypassCSP(bool enabled) +{ + m_bypassCSP = enabled; + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::crash() +{ + WTFCrash(); + return { }; +} + +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 7daa8d1d5c96afe1829aa21ccb8ed1b8ebcc3861..da57245795d7cb287daaaaf5d09a523c0f88fcc7 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h @@ -32,8 +32,10 @@ #pragma once #include "CachedResource.h" +#include "FrameIdentifier.h" #include "InspectorWebAgentBase.h" #include "LayoutRect.h" +#include "ProcessIdentifier.h" #include #include #include @@ -43,11 +45,16 @@ #include #include +namespace Inspector { +class InjectedScriptManager; +} + namespace WebCore { class DOMWrapperWorld; class DocumentLoader; class Frame; +class HTMLInputElement; class InspectorClient; class InspectorOverlay; class LocalFrame; @@ -80,6 +87,8 @@ public: OtherResource, }; + WEBCORE_EXPORT static String serializeFrameID(FrameIdentifier frameID); + WEBCORE_EXPORT static std::optional parseFrameID(String frameID); static bool sharedBufferContent(RefPtr&&, const String& textEncodingName, bool withBase64Encode, String* result); static Vector cachedResourcesForFrame(LocalFrame*); static void resourceContent(Inspector::Protocol::ErrorString&, LocalFrame*, const URL&, String* result, bool* base64Encoded); @@ -100,8 +109,11 @@ 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 navigate(const String& url); 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(); @@ -117,45 +129,65 @@ 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> accessibilitySnapshot(const String& objectId); + 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 frameStartedLoading(LocalFrame&); void frameStoppedLoading(LocalFrame&); - void frameScheduledNavigation(Frame&, Seconds delay); + void frameScheduledNavigation(Frame&, Seconds delay, bool targetIsCurrentFrame); void frameClearedScheduledNavigation(Frame&); 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); + bool doingAccessibilitySnapshot() const { return m_doingAccessibilitySnapshot; }; 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&); Ref protectedOverlay() const; @@ -173,17 +205,22 @@ private: RefPtr m_backendDispatcher; WeakRef m_inspectedPage; + Inspector::InjectedScriptManager& m_injectedScriptManager; InspectorClient* m_client { nullptr }; WeakRef m_overlay; - WeakHashMap m_frameToIdentifier; MemoryCompactRobinHoodHashMap> m_identifierToFrame; HashMap m_loaderToIdentifier; 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_doingAccessibilitySnapshot { 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 0cc351959aaa96bd427ecbf75dd2ba51e730fc30..fb2b6c842a2e2b819ce746403e33550c0d4e2440 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp @@ -34,6 +34,7 @@ #include "DOMWrapperWorld.h" #include "Document.h" +#include "FrameLoader.h" #include "InspectorPageAgent.h" #include "InstrumentingAgents.h" #include "JSDOMWindowCustom.h" @@ -42,6 +43,7 @@ #include "Page.h" #include "PageConsoleClient.h" #include "ScriptController.h" +#include "ScriptSourceCode.h" #include "SecurityOrigin.h" #include "UserGestureEmulationScope.h" #include @@ -88,13 +90,74 @@ Inspector::Protocol::ErrorStringOr PageRuntimeAgent::disable() { m_instrumentingAgents.setEnabledPageRuntimeAgent(nullptr); + m_bindingNames.clear(); + return InspectorRuntimeAgent::disable(); } void PageRuntimeAgent::frameNavigated(LocalFrame& frame) { + auto* pageAgent = m_instrumentingAgents.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 = JSC::jsDynamicCast(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))); +} + +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) @@ -103,7 +166,26 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper if (!pageAgent) return; + if (pageAgent->ignoreDidClearWindowObject()) + return; + + if (world.isNormal()) { + for (const auto& name : m_bindingNames) + addBindingToFrame(frame, name); + } + + pageAgent->setIgnoreDidClearWindowObject(true); notifyContextCreated(pageAgent->frameId(&frame), frame.script().globalObject(world), world); + 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 +224,6 @@ void PageRuntimeAgent::reportExecutionContextCreation() return; m_inspectedPage->forEachLocalFrame([&](LocalFrame& frame) { - if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) - return; - auto frameId = pageAgent->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 ab49ddd13fc6e1ed967cf501afb0230c1e795159..5ea038212cedc1a7b250588b616225edad6f643c 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h @@ -38,6 +38,7 @@ namespace JSC { class CallFrame; +class JSGlobalObject; } namespace WebCore { @@ -59,10 +60,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&&); @@ -77,6 +81,7 @@ private: InstrumentingAgents& 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 8fb27c1045b8073d1487d5b61ccdec23a395bfd1..5008052f587ca4ba90da973c539188deb9551621 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: @@ -80,6 +81,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 0ed08d14f259f4c9ca92447222bb7bc5344f335b..8f04196baa58d2c9b627f59d5e2c0126bd2b4e01 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp @@ -774,8 +774,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc if (!didReceiveRedirectResponse) return completionHandler(WTFMove(newRequest)); + InspectorInstrumentation::willCheckNavigationPolicy(*frame); auto navigationPolicyCompletionHandler = [this, protectedThis = Ref { *this }, frame, completionHandler = WTFMove(completionHandler)] (ResourceRequest&& request, WeakPtr&&, NavigationPolicyDecision navigationPolicyDecision) mutable { m_waitingForNavigationPolicy = false; + InspectorInstrumentation::didCheckNavigationPolicy(*frame, navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad); switch (navigationPolicyDecision) { case NavigationPolicyDecision::IgnoreLoad: case NavigationPolicyDecision::LoadWillContinueInAnotherProcess: @@ -1574,11 +1576,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 3b8896bcc5661929a7f96fb7a01de99b36109dbf..8c3421c5e6a0c36f82c0d7a82f796ca90ba61be7 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h @@ -224,6 +224,8 @@ public: WEBCORE_EXPORT virtual void detachFromFrame(LoadWillContinueInAnotherProcess); + void replacedByFragmentNavigation(LocalFrame&); + WEBCORE_EXPORT FrameLoader* frameLoader() const; WEBCORE_EXPORT RefPtr protectedFrameLoader() const; WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const; diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 0a408b9d3b2c4daa271691041eb1f4fd897d3e93..650180483ace8b8d031d1d022e847409e948a9a4 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -1323,6 +1323,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(); @@ -1861,6 +1862,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t const String& httpMethod = loader->request().httpMethod(); if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) { + loader->replacedByFragmentNavigation(m_frame); RefPtr oldDocumentLoader = m_documentLoader; NavigationAction action { frame->protectedDocument().releaseNonNull(), loader->request(), InitiatedByMainFrame::Unknown, loader->isRequestFromClientOrUserInput(), policyChecker().loadType(), isFormSubmission }; @@ -1898,7 +1900,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, WTFMove(formState), [this, protectedThis = Ref { *this }, allowNavigationToInvalidURL, completionHandler = completionHandlerCaller.release()] (const ResourceRequest& request, WeakPtr&& weakFormState, NavigationPolicyDecision navigationPolicyDecision) mutable { + InspectorInstrumentation::didCheckNavigationPolicy(m_frame, navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad); continueLoadAfterNavigationPolicy(request, RefPtr { weakFormState.get() }.get(), navigationPolicyDecision, allowNavigationToInvalidURL); completionHandler(); }, policyDecisionMode); @@ -3210,10 +3214,15 @@ String FrameLoader::userAgent(const URL& url) const String FrameLoader::navigatorPlatform() const { + String platform; + auto customNavigatorPlatform = m_frame->protectedMainFrame()->customNavigatorPlatform(); if (!customNavigatorPlatform.isEmpty()) - return customNavigatorPlatform; - return String(); + platform = customNavigatorPlatform; + + InspectorInstrumentation::applyPlatformOverride(m_frame, platform); + + return platform; } void FrameLoader::dispatchOnloadEvents() @@ -3672,6 +3681,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill checkCompleted(); if (frame->page()) checkLoadComplete(loadWillContinueInAnotherProcess); + + InspectorInstrumentation::didReceiveMainResourceError(m_frame, error); } void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, const SecurityOrigin* requesterOrigin, bool shouldContinue, NavigationHistoryBehavior historyHandling) @@ -4566,9 +4577,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { - if (!protectedFrame()->checkedScript()->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript)) - return; - Vector> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) @@ -4578,13 +4586,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { Ref frame = m_frame.get(); - if (!frame->checkedScript()->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript) || !frame->protectedWindowProxy()->existingJSWindowProxy(world)) - return; - - m_client->dispatchDidClearWindowObjectInWorld(world); - - if (RefPtr page = frame->page()) - page->inspectorController().didClearWindowObjectInWorld(frame, world); + if (frame->windowProxy().existingJSWindowProxy(world)) { + if (frame->checkedScript()->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 1b34dfdd2a8e56beab49591a3517aba02c510ee6..768b895c132b73d935198cbfc2126a227a656b46 100644 --- a/Source/WebCore/loader/LoaderStrategy.h +++ b/Source/WebCore/loader/LoaderStrategy.h @@ -86,6 +86,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/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp index 5f70f737d06ced029e3b86a4dc93fd49e8ff4cae..15e6c42cbd4733b526493c3c7dfbea62e70ddb0c 100644 --- a/Source/WebCore/loader/NavigationScheduler.cpp +++ b/Source/WebCore/loader/NavigationScheduler.cpp @@ -806,7 +806,7 @@ void NavigationScheduler::startTimer() Seconds delay = 1_s * m_redirect->delay(); m_timer.startOneShot(delay); - InspectorInstrumentation::frameScheduledNavigation(frame, delay); + InspectorInstrumentation::frameScheduledNavigation(frame, delay, m_redirect->targetIsCurrentFrame()); m_redirect->didStartTimer(frame, m_timer); // m_redirect may be null on return (e.g. the client canceled the load) } diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp index a1554c16a0b836bcf87fea0f4e7831d9e0d7baf0..354e4fef6de9c77b7cad96cc428056ae4e2ff067 100644 --- a/Source/WebCore/loader/ProgressTracker.cpp +++ b/Source/WebCore/loader/ProgressTracker.cpp @@ -163,6 +163,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame) if (!m_numProgressTrackedFrames || originatingProgressFrame == &frame) finalProgressComplete(); + InspectorInstrumentation::frameStoppedLoading(frame); + m_client->didChangeEstimatedProgress(); } @@ -189,8 +191,6 @@ void ProgressTracker::finalProgressComplete() m_client->progressFinished(*frame); protectedPage()->progressFinished(*frame); frame->protectedLoader()->loadProgressingStatusChanged(); - - InspectorInstrumentation::frameStoppedLoading(*frame); } } diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp index fb3e38627c8c3491f4994a74c6785cc9767fea2c..000de0c2f725d894cbdfa000d79ed48290eba00a 100644 --- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp +++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp @@ -1173,8 +1173,11 @@ ResourceErrorOr> CachedResourceLoader::requ 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.get()) { bool madeHTTPS { request.resourceRequest().wasSchemeOptimisticallyUpgraded() }; @@ -1811,8 +1814,9 @@ Vector> CachedResourceLoader::allCachedSVGImages() const ResourceErrorOr> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request) { - if (InspectorInstrumentation::willIntercept(protectedFrame().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(protectedFrame().get(), request.resourceRequest())) + // return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s }); RefPtr document = m_document.get(); ASSERT(document); diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h index 51ac3768b20683f26e3a568f390bfe8eba7e1fb5..f6f285ddbe261ccb807e1a57f93f202296f100d2 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h @@ -364,7 +364,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 47392ed5c5888954373a1916f757ee9ccf1edbbd..8fb82ad84ea589efaf6074e79ca5a0c2a4df14ca 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -4460,6 +4460,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; @@ -5054,6 +5060,7 @@ static HitTestResult hitTestResultInFrame(LocalFrame* frame, const LayoutPoint& return result; } +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEvent& event) { Ref frame = m_frame.get(); @@ -5127,7 +5134,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap. unsigned touchPointTargetKey = point.id() + 1; -#if PLATFORM(WPE) +#if !ENABLE(IOS_TOUCH_EVENTS) bool pointerCancelled = false; #endif RefPtr touchTarget; @@ -5174,7 +5181,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve // we also remove it from the map. touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey); -#if PLATFORM(WPE) +#if !ENABLE(IOS_TOUCH_EVENTS) HitTestResult result = hitTestResultAtPoint(pagePoint, hitType | HitTestRequest::Type::AllowChildFrameContent); pointerTarget = result.targetElement(); pointerCancelled = (pointerTarget != touchTarget); @@ -5197,7 +5204,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve if (!targetFrame) continue; -#if PLATFORM(WPE) +#if !ENABLE(IOS_TOUCH_EVENTS) // FIXME: WPE currently does not send touch stationary events, so create a naive TouchReleased PlatformTouchPoint // on release if the hit test result changed since the previous TouchPressed or TouchMoved if (pointState == PlatformTouchPoint::TouchReleased && pointerCancelled) { @@ -5287,6 +5294,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve 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 f4a1e3408623e2b338149d1a129dc8075c764f59..571c4c6e9a873167bbc78b0708ffac44b7a8e641 100644 --- a/Source/WebCore/page/FocusController.cpp +++ b/Source/WebCore/page/FocusController.cpp @@ -586,13 +586,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/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp index 3474800864049dcbe6c84746c4216e72a68fa48f..8f5d536921eeb41c77fe689c036dcb77e625e431 100644 --- a/Source/WebCore/page/FrameSnapshotting.cpp +++ b/Source/WebCore/page/FrameSnapshotting.cpp @@ -115,7 +115,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; @@ -134,6 +134,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; @@ -142,7 +144,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 713cb9c3c59bbad23ef0b821ab27b3d669a7dea8..12077ebf0978b6b52e6af4602767c09d9f3cd9de 100644 --- a/Source/WebCore/page/FrameSnapshotting.h +++ b/Source/WebCore/page/FrameSnapshotting.h @@ -58,6 +58,7 @@ enum class SnapshotFlags : uint16_t { PaintWith3xBaseScale = 1 << 10, ExcludeText = 1 << 11, FixedAndStickyLayersOnly = 1 << 12, + OmitDeviceScaleFactor = 1 << 13, }; struct SnapshotOptions { diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index adc6185687b6fcee3a49819d0149cde24a4485bf..a33e5db46933c514abce86e3f264de9b7e7c20d9 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -32,6 +32,7 @@ #include "FrameLoader.h" #include "HistoryController.h" #include "HistoryItem.h" +#include "InspectorInstrumentation.h" #include "LocalFrame.h" #include "LocalFrameLoaderClient.h" #include "Logging.h" @@ -309,6 +310,8 @@ ExceptionOr History::stateObjectAdded(RefPtr&& data } frame->loader().updateURLAndHistory(fullURL, WTFMove(data), historyBehavior); + InspectorInstrumentation::didNavigateWithinPage(*frame); + return { }; } diff --git a/Source/WebCore/page/LocalFrame.cpp b/Source/WebCore/page/LocalFrame.cpp index 54cab8376adfb6dd1e5ca32e170219290e4f0508..d212eece82066ba788d049e9aff212ff3493a6c3 100644 --- a/Source/WebCore/page/LocalFrame.cpp +++ b/Source/WebCore/page/LocalFrame.cpp @@ -41,6 +41,7 @@ #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" +#include "ComposedTreeIterator.h" #include "DiagnosticLoggingClient.h" #include "DiagnosticLoggingKeys.h" #include "DocumentLoader.h" @@ -59,6 +60,7 @@ #include "FrameSelection.h" #include "GraphicsContext.h" #include "GraphicsLayer.h" +#include "HTMLAreaElement.h" #include "HTMLAttachmentElement.h" #include "HTMLFormControlElement.h" #include "HTMLFormElement.h" @@ -81,6 +83,7 @@ #include "Logging.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeRenderStyle.h" #include "NodeTraversal.h" #include "Page.h" #include "PaymentSession.h" @@ -205,6 +208,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie void LocalFrame::init() { + InspectorInstrumentation::frameAttached(this); protectedLoader()->init(); } @@ -442,7 +446,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) @@ -1549,6 +1553,364 @@ RefPtr LocalFrame::frameDocumentSecurityOrigin() const return nullptr; } +#if !PLATFORM(IOS_FAMILY) + +void LocalFrame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect) +{ + IntRect candidateRect; + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; + auto* candidate = nodeQualifierFunction(eventHandler().hitTestResultAtPoint(testPoint, hitType), failedNode, &candidateRect); + + // Bail if we have no candidate, or the candidate is already equal to our current best node, + // or our candidate is the avoidedNode and there is a current best node. + if (!candidate || candidate == best) + return; + + // The document should never be considered the best alternative. + if (candidate->isDocumentNode()) + return; + + if (best) { + IntRect bestIntersect = intersection(testRect, bestRect); + IntRect candidateIntersect = intersection(testRect, candidateRect); + // if the candidate intersection is smaller than the current best intersection, bail. + if (candidateIntersect.width() * candidateIntersect.height() <= bestIntersect.width() * bestIntersect.height()) + return; + } + + // At this point we either don't have a previous best, or our current candidate has a better intersection. + best = candidate; + bestPoint = testPoint; + bestRect = candidateRect; +} + +bool LocalFrame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center) +{ + if (!m_doc || !m_doc->renderView()) + return false; + + FrameView* view = m_view.get(); + if (!view) + return false; + + center = view->windowToContents(roundedIntPoint(viewportLocation)); + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; + hitTestResult = eventHandler().hitTestResultAtPoint(center, hitType); + return true; +} + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN +Node* LocalFrame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement) +{ + adjustedViewportLocation = viewportLocation; + + IntPoint testCenter; + HitTestResult candidateInfo; + if (!hitTestResultAtViewportLocation(viewportLocation, candidateInfo, testCenter)) + return nullptr; + + IntPoint bestPoint = testCenter; + + // We have the candidate node at the location, check whether it or one of its ancestors passes + // the qualifier function, which typically checks if the node responds to a particular event type. + Node* approximateNode = nodeQualifierFunction(candidateInfo, 0, 0); + + if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode && approximateNode->isContentEditable()) { + // If we are in editable content, we look for the root editable element. + approximateNode = approximateNode->rootEditableElement(); + // If we have a focusable node, there is no need to approximate. + if (approximateNode) + shouldApproximate = ShouldApproximate::No; + } + + float scale = page() ? page()->pageScaleFactor() : 1; +#if PLATFORM(IOS_FAMILY) + float ppiFactor = screenPPIFactor(); +#else + float ppiFactor = 326; // most popular iPhone PPI +#endif + + static const float unscaledSearchRadius = 15; + int searchRadius = static_cast(unscaledSearchRadius * ppiFactor / scale); + + if (approximateNode && shouldApproximate == ShouldApproximate::Yes) { + const float testOffsets[] = { + -.3f, -.3f, + -.6f, -.6f, + +.3f, +.3f, + -.9f, -.9f, + }; + + Node* originalApproximateNode = approximateNode; + for (unsigned n = 0; n < std::size(testOffsets); n += 2) { + IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); + IntPoint testPoint = testCenter + testOffset; + + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowChildFrameContent }; + auto candidateInfo = eventHandler().hitTestResultAtPoint(testPoint, hitType); + Node* candidateNode = nodeQualifierFunction(candidateInfo, 0, 0); + if (candidateNode && candidateNode->isDescendantOf(originalApproximateNode)) { + approximateNode = candidateNode; + bestPoint = testPoint; + break; + } + } + } else if (!approximateNode && shouldApproximate == ShouldApproximate::Yes) { + // Grab the closest parent element of our failed candidate node. + Node* candidate = candidateInfo.innerNode(); + Node* failedNode = candidate; + + while (candidate && !candidate->isElementNode()) + candidate = candidate->parentInComposedTree(); + + if (candidate) + failedNode = candidate; + + // The center point was tested earlier. + const float testOffsets[] = { + -.3f, -.3f, + +.3f, -.3f, + -.3f, +.3f, + +.3f, +.3f, + -.6f, -.6f, + +.6f, -.6f, + -.6f, +.6f, + +.6f, +.6f, + -1.f, 0, + +1.f, 0, + 0, +1.f, + 0, -1.f, + }; + IntRect bestFrame; + IntRect testRect(testCenter, IntSize()); + testRect.inflate(searchRadius); + int currentTestRadius = 0; + for (unsigned n = 0; n < std::size(testOffsets); n += 2) { + IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); + IntPoint testPoint = testCenter + testOffset; + int testRadius = std::max(abs(testOffset.width()), abs(testOffset.height())); + if (testRadius > currentTestRadius) { + // Bail out with the best match within a radius + currentTestRadius = testRadius; + if (approximateNode) + break; + } + betterApproximateNode(testPoint, nodeQualifierFunction, approximateNode, failedNode, bestPoint, bestFrame, testRect); + } + } + + if (approximateNode) { + IntPoint p = m_view->contentsToWindow(bestPoint); + adjustedViewportLocation = p; + if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode->isContentEditable()) { + // When in editable content, look for the root editable node again, + // since this could be the node found with the approximation. + approximateNode = approximateNode->rootEditableElement(); + } + } + + return approximateNode; +} +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END + +Node* LocalFrame::deepestNodeAtLocation(const FloatPoint& viewportLocation) +{ + IntPoint center; + HitTestResult hitTestResult; + if (!hitTestResultAtViewportLocation(viewportLocation, hitTestResult, center)) + return nullptr; + + return hitTestResult.innerNode(); +} + +static bool nodeIsMouseFocusable(Node& node) +{ + if (!is(node)) + return false; + + auto& element = downcast(node); + if (element.isMouseFocusable()) + return true; + + if (RefPtr shadowRoot = element.shadowRoot()) { + if (shadowRoot->delegatesFocus()) { + for (auto& node : composedTreeDescendants(element)) { + if (is(node) && downcast(node).isMouseFocusable()) + return true; + } + } + } + + return false; +} + +static bool nodeWillRespondToMouseEvents(Node& node) +{ + return node.willRespondToMouseClickEvents() || node.willRespondToMouseMoveEvents() || nodeIsMouseFocusable(node); +} + +Node* LocalFrame::approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + // This function is only used for UIWebView. + auto&& ancestorRespondingToClickEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + bool bodyHasBeenReached = false; + bool pointerCursorStillValid = true; + + if (nodeBounds) + *nodeBounds = IntRect(); + + auto node = hitTestResult.innerNode(); + if (!node) + return nullptr; + + Node* pointerCursorNode = nullptr; + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + // We only accept pointer nodes before reaching the body tag. + if (node->hasTagName(HTMLNames::bodyTag)) { + // Make sure we cover the case of an empty editable body. + if (!pointerCursorNode && node->isContentEditable()) + pointerCursorNode = node; + bodyHasBeenReached = true; + pointerCursorStillValid = false; + } + + // If we already have a pointer, and we reach a table, don't accept it. + if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag))) + pointerCursorStillValid = false; + + // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor. + if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CursorType::Pointer) + pointerCursorNode = node; + else if (pointerCursorNode) { + // We want the lowest unbroken chain of pointer cursors. + pointerCursorStillValid = false; + } + + if (nodeWillRespondToMouseEvents(*node)) { + // If we're at the body or higher, use the pointer cursor node (which may be null). + if (bodyHasBeenReached) + node = pointerCursorNode; + + // If we are interested about the frame, use it. + if (nodeBounds) { + // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check. + if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is(*node)) + *nodeBounds = snappedIntRect(downcast(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer())); + else if (node && node->renderer()) + *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); + } + + return node; + } + } + + return nullptr; + }; + + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToClickEvents), ShouldApproximate::Yes); +} + +static inline NodeQualifier ancestorRespondingToClickEventsNodeQualifier(SecurityOrigin* securityOrigin = nullptr) +{ + return [securityOrigin](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) + *nodeBounds = IntRect(); + + auto node = hitTestResult.innerNode(); + if (!node || (securityOrigin && !securityOrigin->isSameOriginAs(node->document().securityOrigin()))) + return nullptr; + + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + if (nodeWillRespondToMouseEvents(*node)) { + // If we are interested about the frame, use it. + if (nodeBounds) { + // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check. + if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is(*node)) + *nodeBounds = snappedIntRect(downcast(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer())); + else if (node && node->renderer()) + *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); + } + + return node; + } + } + + return nullptr; + }; +} + +Node* LocalFrame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin) +{ + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(securityOrigin), ShouldApproximate::Yes); +} + +Node* LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + auto&& ancestorRespondingToDoubleClickEvent = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) + *nodeBounds = IntRect(); + + auto* node = hitTestResult.innerNode(); + if (!node) + return nullptr; + + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + if (!node->hasEventListeners(eventNames().dblclickEvent)) + continue; +#if ENABLE(TOUCH_EVENTS) + if (!node->allowsDoubleTapGesture()) + continue; +#endif + if (nodeBounds && node->renderer()) + *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); + return node; + } + return nullptr; + }; + + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes); +} + +Node* LocalFrame::nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(), ShouldApproximate::Yes, ShouldFindRootEditableElement::No); +} + +Node* LocalFrame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation) +{ + auto&& ancestorRespondingToScrollWheelEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) + *nodeBounds = IntRect(); + + Node* scrollingAncestor = nullptr; + for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) { + RenderObject* renderer = node->renderer(); + if (!renderer) + continue; + + if ((renderer->isRenderTextControlSingleLine() || renderer->isRenderTextControlMultiLine()) && downcast(*renderer).canScroll()) { + scrollingAncestor = node; + continue; + } + + auto& style = renderer->style(); + + if (renderer->hasNonVisibleOverflow() + && (style.overflowY() == Overflow::Auto || style.overflowY() == Overflow::Scroll + || style.overflowX() == Overflow::Auto || style.overflowX() == Overflow::Scroll)) { + scrollingAncestor = node; + } + } + + return scrollingAncestor; + }; + + FloatPoint adjustedViewportLocation; + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToScrollWheelEvents), ShouldApproximate::No); +} + +#endif // !PLATFORM(IOS_FAMILY) + } // namespace WebCore #undef FRAME_RELEASE_LOG_ERROR diff --git a/Source/WebCore/page/LocalFrame.h b/Source/WebCore/page/LocalFrame.h index b46fd5f993569302c23b7302a493a37fd8c1f440..2d9bbfc639deba681ecb7465d87981a787901dac 100644 --- a/Source/WebCore/page/LocalFrame.h +++ b/Source/WebCore/page/LocalFrame.h @@ -28,8 +28,10 @@ #pragma once #include "AdjustViewSizeOrNot.h" +#include "DOMPasteAccess.h" #include "Document.h" #include "Frame.h" +#include "IntDegrees.h" #include "ScrollTypes.h" #include "UserScriptTypes.h" #include @@ -116,8 +118,8 @@ enum { }; enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll }; -using NodeQualifier = Function; #endif +using NodeQualifier = Function; class LocalFrame final : public Frame { public: @@ -227,10 +229,6 @@ public: WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults(); #endif -#if PLATFORM(IOS_FAMILY) - const ViewportArguments& viewportArguments() const; - WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&); - WEBCORE_EXPORT Node* deepestNodeAtLocation(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* = nullptr); WEBCORE_EXPORT Node* nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); @@ -238,6 +236,10 @@ public: WEBCORE_EXPORT Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); +#if PLATFORM(IOS_FAMILY) + const ViewportArguments& viewportArguments() const; + WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&); + WEBCORE_EXPORT NSArray *wordsInCurrentParagraph() const; WEBCORE_EXPORT CGRect renderRectForPoint(CGPoint, bool* isReplaced, float* fontSize) const; @@ -305,6 +307,7 @@ public: WEBCORE_EXPORT FloatSize screenSize() const; void setOverrideScreenSize(FloatSize&&); + bool hasScreenSizeOverride() const { return !m_overrideScreenSize.isEmpty(); } void selfOnlyRef(); void selfOnlyDeref(); @@ -373,7 +376,6 @@ private: #if ENABLE(DATA_DETECTION) std::unique_ptr m_dataDetectionResults; #endif -#if PLATFORM(IOS_FAMILY) void betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect); bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center); @@ -381,6 +383,7 @@ private: enum class ShouldFindRootEditableElement : bool { No, Yes }; Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier&, ShouldApproximate, ShouldFindRootEditableElement = ShouldFindRootEditableElement::Yes); +#if PLATFORM(IOS_FAMILY) void setTimersPausedInternal(bool); ViewportArguments m_viewportArguments; diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index a9369054928a0c9c1f3aef0252c2da3d33d4ce7c..2b151666e718fb037471ab7005c62623c4ee332d 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -655,6 +655,45 @@ void Page::setOverrideViewportArguments(const std::optional& localTopDocument->updateViewportArguments(); } +FloatSize Page::screenSize() +{ + auto* localMainFrame = dynamicDowncast(mainFrame()); + 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; + auto* localMainFrame = dynamicDowncast(mainFrame()); + 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; + + auto* localMainFrame = dynamicDowncast(mainFrame()); + if (localMainFrame) + localMainFrame->orientationChanged(); +} +#endif + ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { @@ -4214,6 +4253,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 4e33885a4771eb8260c8cebb14991d780f95be3d..e413dde6db076f587cbf520f17bfa5078320f8cc 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h @@ -366,6 +366,9 @@ public: const ViewportArguments* overrideViewportArguments() const { 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(); WEBCORE_EXPORT Ref protectedPluginData(); @@ -463,6 +466,10 @@ public: #if ENABLE(DRAG_SUPPORT) DragController& dragController() { return m_dragController.get(); } const DragController& dragController() const { 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; } WEBCORE_EXPORT CheckedRef checkedFocusController() const; @@ -648,6 +655,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; } @@ -1116,6 +1127,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 @@ -1389,6 +1405,9 @@ private: #if ENABLE(DRAG_SUPPORT) const UniqueRef m_dragController; +#if PLATFORM(MAC) + String m_overrideDragPasteboardName; +#endif #endif std::unique_ptr m_focusController; #if ENABLE(CONTEXT_MENUS) @@ -1467,6 +1486,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 }; @@ -1649,6 +1670,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/PageConsoleClient.cpp b/Source/WebCore/page/PageConsoleClient.cpp index ad70f3c37261ab24afc23f7136ae3feb1fcbe154..ecf31d4aaf2080e705e9caec75596104bdfce786 100644 --- a/Source/WebCore/page/PageConsoleClient.cpp +++ b/Source/WebCore/page/PageConsoleClient.cpp @@ -456,4 +456,9 @@ Ref PageConsoleClient::protectedPage() const return m_page.get(); } +void PageConsoleClient::bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg) +{ + InspectorInstrumentation::bindingCalled(m_page, globalObject, name, arg); +} + } // namespace WebCore diff --git a/Source/WebCore/page/PageConsoleClient.h b/Source/WebCore/page/PageConsoleClient.h index 153fc36199f26adbfb61cbef6744ffe31a68b951..cc667e06700013fd5e994467e19536d2e4cab189 100644 --- a/Source/WebCore/page/PageConsoleClient.h +++ b/Source/WebCore/page/PageConsoleClient.h @@ -86,6 +86,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; Ref protectedPage() const; diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp index ad7f92bf398348be7823247931ce71d5a1c2296e..accabfd4f44199f026ca7bb9ea058bfe3d0ad8f8 100644 --- a/Source/WebCore/page/PointerCaptureController.cpp +++ b/Source/WebCore/page/PointerCaptureController.cpp @@ -205,7 +205,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi return capturingData && capturingData->preventsCompatibilityMouseEvents; } -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName) { for (RefPtr currentNode = target; currentNode; currentNode = currentNode->parentInComposedTree()) { @@ -555,7 +555,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)) +#if ENABLE(TOUCH_EVENTS) capturingData->previousTarget = nullptr; #endif diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h index b7e3f7cbd54e6ba9419de1bbf70594f3c2771d41..abb08ab5f5a979d7a40af30a27fddfe163db2b12 100644 --- a/Source/WebCore/page/PointerCaptureController.h +++ b/Source/WebCore/page/PointerCaptureController.h @@ -60,7 +60,7 @@ public: RefPtr pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType); -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&, const IntPoint&); #endif @@ -81,12 +81,12 @@ private: WeakPtr activeDocument; RefPtr pendingTargetOverride; RefPtr targetOverride; -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) RefPtr previousTarget; #endif bool hasAnyElement() const { return pendingTargetOverride || targetOverride -#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE)) +#if ENABLE(TOUCH_EVENTS) || previousTarget #endif ; diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp index 24ed7c019bea4df52f2883db0e40bdbc2dc74ebd..a788f534d9e0e8124153c7f380b4fdb232c51a1a 100644 --- a/Source/WebCore/page/Screen.cpp +++ b/Source/WebCore/page/Screen.cpp @@ -124,6 +124,9 @@ int Screen::availLeft() const if (shouldApplyScreenFingerprintingProtections(*frame)) return 0; + if (frame->hasScreenSizeOverride()) + return 0; + return static_cast(screenAvailableRect(frame->protectedView().get()).x()); } @@ -139,6 +142,9 @@ int Screen::availTop() const if (shouldApplyScreenFingerprintingProtections(*frame)) return 0; + if (frame->hasScreenSizeOverride()) + return 0; + return static_cast(screenAvailableRect(frame->protectedView().get()).y()); } @@ -154,6 +160,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(frame->protectedView().get()).height()); } @@ -169,6 +178,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(frame->protectedView().get()).width()); } diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp index 4861e2276c172ea347cd31f68029b49df9350fe1..91c6eb5e3031f863d7b2483d9ba8be75c8718ea0 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp @@ -372,6 +372,8 @@ bool ContentSecurityPolicy::allowContentSecurityPolicySourceStarToMatchAnyProtoc template typename std::enable_if::value, bool>::type ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, Predicate&& predicate, Args&&... args) const { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get())) + return true; bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; for (auto& policy : m_policies) { if (policy->isReportOnly() != isReportOnly) @@ -385,6 +387,8 @@ typename std::enable_if 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) { @@ -401,6 +405,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)(std::forward(args)...)) { diff --git a/Source/WebCore/page/wpe/DragControllerWPE.cpp b/Source/WebCore/page/wpe/DragControllerWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..803239911006cfb3b03ea911c003f2d233f67600 --- /dev/null +++ b/Source/WebCore/page/wpe/DragControllerWPE.cpp @@ -0,0 +1,80 @@ +/* + * 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 "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/Cairo.cmake b/Source/WebCore/platform/Cairo.cmake index 96baa501801c5952d4b5b203dff278adb54aaa54..34c498f6050388d30e4190604e7af6f68b33fab9 100644 --- a/Source/WebCore/platform/Cairo.cmake +++ b/Source/WebCore/platform/Cairo.cmake @@ -15,6 +15,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/cairo/ImageBufferCairoBackend.h platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.h platform/graphics/cairo/ImageBufferCairoSurfaceBackend.h + platform/graphics/cairo/ImageBufferUtilitiesCairo.h platform/graphics/cairo/RefPtrCairo.h ) diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h index 2ebb3221cb3818f20abc7b7c3307ea7644f49d49..e0bffb6f5adee0b0a202340f633c2def1955b384 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -47,7 +47,7 @@ typedef void* DragDataRef; #elif PLATFORM(WIN) typedef struct IDataObject* DragDataRef; -#elif PLATFORM(GTK) +#elif PLATFORM(GTK) || PLATFORM(WPE) namespace WebCore { class SelectionData; } @@ -92,8 +92,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 @@ -143,7 +143,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/DragImage.cpp b/Source/WebCore/platform/DragImage.cpp index 2f4e02e783ac512aeb76e0abe7e253b57bfda937..94e0c9335720324a746f300a26b17a28eedf2197 100644 --- a/Source/WebCore/platform/DragImage.cpp +++ b/Source/WebCore/platform/DragImage.cpp @@ -280,7 +280,7 @@ DragImage::~DragImage() deleteDragImage(m_dragImageRef); } -#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN) +#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN) && !PLATFORM(WPE) IntSize dragImageSize(DragImageRef) { diff --git a/Source/WebCore/platform/DragImage.h b/Source/WebCore/platform/DragImage.h index 77286d8e715825c9c7c0d329480fc0fc497fe561..5ea53eb8b7e53dd5a5950c65a38c1d23bfe46681 100644 --- a/Source/WebCore/platform/DragImage.h +++ b/Source/WebCore/platform/DragImage.h @@ -60,7 +60,7 @@ class Node; typedef RetainPtr DragImageRef; #elif PLATFORM(MAC) typedef RetainPtr DragImageRef; -#elif PLATFORM(WIN) +#elif PLATFORM(WIN) && USE(CAIRO) typedef HBITMAP DragImageRef; #elif USE(CAIRO) typedef RefPtr DragImageRef; diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h index 1b1a1147d4948e9281a114281e95d57d3b0ccf27..e21ccb98542cc582ad2489d301cb29c2b0c03f4b 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -46,7 +46,7 @@ OBJC_CLASS NSString; OBJC_CLASS NSArray; #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) #include "SelectionData.h" #endif @@ -108,7 +108,7 @@ struct PasteboardURL { #if PLATFORM(MAC) String userVisibleForm; #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) String markup; #endif }; @@ -197,6 +197,11 @@ public: #endif #endif +#if PLATFORM(WPE) && ENABLE(DRAG_SUPPORT) + explicit Pasteboard(std::unique_ptr&&, SelectionData&); + explicit Pasteboard(std::unique_ptr&&, SelectionData&&); +#endif + #if PLATFORM(WIN) explicit Pasteboard(std::unique_ptr&&, IDataObject*); explicit Pasteboard(std::unique_ptr&&, WCDataObject*); @@ -264,6 +269,12 @@ public: int64_t changeCount() const; #endif +#if PLATFORM(WPE) + const SelectionData& selectionData() const { + return *m_selectionData; + } +#endif + #if PLATFORM(IOS_FAMILY) explicit Pasteboard(std::unique_ptr&&, int64_t changeCount); explicit Pasteboard(std::unique_ptr&&, const String& pasteboardName); @@ -306,6 +317,7 @@ public: COMPtr dataObject() const { return m_dataObject; } WEBCORE_EXPORT void setExternalDataObject(IDataObject*); const DragDataMap& dragDataMap() const { 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. @@ -358,6 +370,10 @@ private: int64_t m_changeCount { 0 }; #endif +#if PLATFORM(WPE) + std::optional m_selectionData; +#endif + #if PLATFORM(COCOA) String m_pasteboardName; int64_t m_changeCount; @@ -373,6 +389,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 63ffd6ca32c3baee03db2a9419c4f7e9de45388a..c60c7a8d1f110472117c8c4e969fd05fef71f908 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -135,6 +135,7 @@ namespace WebCore { static String keyCodeForHardwareKeyCode(unsigned); static String keyIdentifierForGdkKeyCode(unsigned); static int windowsKeyCodeForGdkKeyCode(unsigned); + static unsigned gdkKeyCodeForWindowsKeyCode(int); static String singleCharacterString(unsigned); #endif @@ -143,6 +144,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 ef0abc9a93e878897ffc9d2497a3da0fca5b37b7..abd96c6d1a6c3ab9e0121c1e78f2f75a5f805b32 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 82a54ac2de2ddf4650e4b48db129fe25f6562264..d144ba15d18d2e892c25988dab27636135353a99 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h @@ -160,10 +160,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 23f011953c66f401553bedfaef3485af215ae083..a73da2ebe47f0d8dc57f3d0159e8f299abb61c96 100644 --- a/Source/WebCore/platform/PlatformTouchEvent.h +++ b/Source/WebCore/platform/PlatformTouchEvent.h @@ -42,7 +42,7 @@ public: const Vector& predictedEvents() const { 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/PlatformTouchPoint.h b/Source/WebCore/platform/PlatformTouchPoint.h index 34715d27b529750fc866db87cd330b5184286771..3eefa218af075f76d98012cdeae7e4b344850116 100644 --- a/Source/WebCore/platform/PlatformTouchPoint.h +++ b/Source/WebCore/platform/PlatformTouchPoint.h @@ -49,7 +49,7 @@ public: { } -#if PLATFORM(WPE) +#if !ENABLE(IOS_TOUCH_EVENTS) // FIXME: since WPE currently does not send touch stationary events, we need to be able to // create a PlatformTouchPoint of type TouchCancelled artificially PlatformTouchPoint(unsigned id, State state, IntPoint screenPos, IntPoint pos) diff --git a/Source/WebCore/platform/Skia.cmake b/Source/WebCore/platform/Skia.cmake index c39b57e01190b833be46452c3d964fe243c216d3..6e4af1509037697421cf0c80e2459da0bad79ba8 100644 --- a/Source/WebCore/platform/Skia.cmake +++ b/Source/WebCore/platform/Skia.cmake @@ -14,6 +14,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/skia/FontCascadeSkiaInlines.h platform/graphics/skia/GraphicsContextSkia.h platform/graphics/skia/ImageBufferSkiaBackend.h + platform/graphics/skia/ImageBufferUtilitiesSkia.h platform/graphics/skia/SkiaHarfBuzzFont.h platform/graphics/skia/SkiaHarfBuzzFontCache.h platform/graphics/skia/SkiaPaintingEngine.h diff --git a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp index 492c5e76290c2379cda40b9663f5f67ff8f66360..096752985edf39960eb4be6eb733ebe3713313cb 100644 --- a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp +++ b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp @@ -46,7 +46,7 @@ namespace WebCore { -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/cairo/ImageBufferUtilitiesCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp index d137ffd1a8ed0b788bd28197c6d7e9f7d14e852f..dcf8bf3f7ee6b037a370712e2ac36b6e2e4bbebc 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp @@ -48,6 +48,13 @@ #include #endif +#if PLATFORM(WPE) || PLATFORM(WIN) +#include // Needed by jpeglib.h for FILE. +extern "C" { +#include "jpeglib.h" +} +#endif + namespace WebCore { #if !PLATFORM(GTK) @@ -65,8 +72,75 @@ static bool encodeImage(cairo_surface_t* image, const String& mimeType, Vector encodeData(cairo_surface_t* image, const String& mimeType, std::optional) +static Vector encodeJpeg(cairo_surface_t* image, int quality) +{ + if (cairo_surface_get_type(image) != CAIRO_SURFACE_TYPE_IMAGE) { + fprintf(stderr, "Unexpected cairo surface type: %d\n", cairo_surface_get_type(image)); + return { }; + } + + if (cairo_image_surface_get_format(image) != CAIRO_FORMAT_ARGB32) { + fprintf(stderr, "Unexpected surface image format: %d\n", cairo_image_surface_get_format(image)); + return { }; + } + + struct jpeg_compress_struct info; + struct jpeg_error_mgr error; + info.err = jpeg_std_error(&error); + jpeg_create_compress(&info); + + unsigned char* bufferPtr = nullptr; + unsigned long bufferSize; + jpeg_mem_dest(&info, &bufferPtr, &bufferSize); + info.image_width = cairo_image_surface_get_width(image); + info.image_height = cairo_image_surface_get_height(image); + +#ifndef LIBJPEG_TURBO_VERSION + COMPILE_ASSERT(false, only_libjpeg_turbo_is_supported); +#endif + +#if CPU(LITTLE_ENDIAN) + info.in_color_space = JCS_EXT_BGRA; +#else + info.in_color_space = JCS_EXT_ARGB; +#endif + // # of color components in input image + info.input_components = 4; + + jpeg_set_defaults(&info); + jpeg_set_quality(&info, quality, true); + + jpeg_start_compress(&info, true); + + while (info.next_scanline < info.image_height) + { + JSAMPROW row = cairo_image_surface_get_data(image) + (info.next_scanline * cairo_image_surface_get_stride(image)); + if (jpeg_write_scanlines(&info, &row, 1) != 1) { + fprintf(stderr, "JPEG library failed to encode line\n"); + break; + } + } + + jpeg_finish_compress(&info); + jpeg_destroy_compress(&info); + + Vector output; + output.append(std::span { bufferPtr, bufferSize }); + // Cannot use unique_ptr as bufferPtr changes during compression. GUniquePtr would work + // but it's under GLib and won't work on Windows. + free(bufferPtr); + return output; +} + +Vector encodeData(cairo_surface_t* image, const String& mimeType, std::optional quality) { + if (mimeType == "image/jpeg"_s) { + int qualityPercent = 100; + if (quality) + qualityPercent = static_cast(*quality * 100.0 + 0.5); + return encodeJpeg(image, qualityPercent); + } + Vector encodedImage; if (!image || !encodeImage(image, mimeType, &encodedImage)) return { }; diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h index 5b659c763b9754b025a63f89522954cc39915b9a..448b50a2b131361a75d3f816cdcbb6a102551280 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h +++ b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h @@ -38,7 +38,7 @@ WEBCORE_EXPORT uint8_t verifyImageBufferIsBigEnough(std::span buf RetainPtr utiFromImageBufferMIMEType(const String& mimeType); CFStringRef jpegUTI(); -Vector encodeData(CGImageRef, const String& mimeType, std::optional quality); +WEBCORE_EXPORT Vector encodeData(CGImageRef, const String& mimeType, std::optional quality); Vector encodeData(const PixelBuffer&, const String& mimeType, std::optional quality); Vector encodeData(std::span, const String& mimeType, std::optional quality); diff --git a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h b/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h index 3d0ab7eceaf2a6321685bc362eb9b25600fd98fd..2d7e9a399bf2e9dc3f373d5fa3db99fa0908bd9d 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 78ea08023ebd5f1b41b06cd843b6dce4ee80dd50..55fed94b774f033b4f75e2dee85dc27cf2e2689e 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 +#include namespace WebCore { @@ -1302,6 +1304,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(unsigned keycode) } +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 = PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(gdkKeyCode); + // If several gdk key codes map to the same win key code first one is used. + result->add(winKeyCode, gdkKeyCode); + } + }); + return *result; +} + +unsigned PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(int keycode) +{ + return gdkToWindowsKeyCodeMap().get(keycode); +} + String PlatformKeyboardEvent::singleCharacterString(unsigned val) { switch (val) { diff --git a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp index 1339241aae69b657ffa40b603eea992c45db0e65..9194ff5f8308e5cf22fb250723ae4161142da45f 100644 --- a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -121,7 +121,7 @@ bool screenSupportsExtendedColor(Widget*) } #if ENABLE(TOUCH_EVENTS) -bool screenHasTouchDevice() +bool platformScreenHasTouchDevice() { return getScreenProperties().screenHasTouchDevice; } diff --git a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp index ae439e30f1fb239d18e1164e8896dfb272c75673..4cf29eda13d1f2dc2f03750c0ef8985b17de7f50 100644 --- a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp @@ -32,6 +32,10 @@ #include "PasteboardStrategy.h" #include "PlatformStrategies.h" +#if ENABLE(DRAG_SUPPORT) +#include "DragData.h" +#endif + namespace WebCore { std::unique_ptr Pasteboard::createForCopyAndPaste(std::unique_ptr&& context) @@ -52,9 +56,28 @@ bool Pasteboard::hasData() return !types.isEmpty(); } -Vector Pasteboard::typesSafeForBindings(const String&) +Vector Pasteboard::typesSafeForBindings(const String& origin) { - notImplemented(); + if (m_selectionData) { + ListHashSet types; + if (auto& buffer = m_selectionData->customData()) { + auto customData = PasteboardCustomData::fromSharedBuffer(*buffer); + if (customData.origin() == origin) { + for (auto& type : customData.orderedTypes()) + types.add(type); + } + } + + if (m_selectionData->hasText()) + types.add("text/plain"_s); + if (m_selectionData->hasMarkup()) + types.add("text/html"_s); + if (m_selectionData->hasURIList()) + types.add("text/uri-list"_s); + + return copyToVector(types); + } + return { }; } @@ -67,23 +90,55 @@ Vector Pasteboard::typesForLegacyUnsafeBindings() String Pasteboard::readOrigin() { - notImplemented(); // webkit.org/b/177633: [GTK] Move to new Pasteboard API + if (m_selectionData) { + if (auto& buffer = m_selectionData->customData()) + return PasteboardCustomData::fromSharedBuffer(*buffer).origin(); + + return { }; + } + return { }; } String Pasteboard::readString(const String& type) { + if (m_selectionData) { + if (type == "text/plain"_s) + return m_selectionData->text();; + if (type == "text/html"_s) + return m_selectionData->markup(); + if (type == "Files"_s || type == "text/uri-list"_s) + return m_selectionData->uriList(); + return { }; + } + return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(0, type, name(), context()); } -String Pasteboard::readStringInCustomData(const String&) +String Pasteboard::readStringInCustomData(const String& type) { + if (m_selectionData) { + if (auto& buffer = m_selectionData->customData()) + return PasteboardCustomData::fromSharedBuffer(*buffer).readStringInCustomData(type); + + return { }; + } + notImplemented(); return { }; } void Pasteboard::writeString(const String& type, const String& text) { + if (m_selectionData) { + if (type == "Files"_s || type == "text/uri-list"_s) + m_selectionData->setURIList(text); + else if (type == "text/html"_s) + m_selectionData->setMarkup(text); + else if (type == "text/plain"_s) + m_selectionData->setText(text); + return; + } platformStrategies()->pasteboardStrategy()->writeToPasteboard(type, text); } @@ -111,7 +166,12 @@ void Pasteboard::read(PasteboardFileReader&, std::optional) void Pasteboard::write(const PasteboardURL& url) { - platformStrategies()->pasteboardStrategy()->writeToPasteboard("text/plain;charset=utf-8"_s, url.url.string()); + if (m_selectionData) { + m_selectionData->clearAll(); + m_selectionData->setURL(url.url, url.title); + } else { + platformStrategies()->pasteboardStrategy()->writeToPasteboard("text/plain;charset=utf-8"_s, url.url.string()); + } } void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) @@ -119,8 +179,16 @@ void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) notImplemented(); } -void Pasteboard::write(const PasteboardImage&) +void Pasteboard::write(const PasteboardImage& pasteboardImage) { + if (m_selectionData) { + m_selectionData->clearAll(); + if (!pasteboardImage.url.url.isEmpty()) { + m_selectionData->setURL(pasteboardImage.url.url, pasteboardImage.url.title); + m_selectionData->setMarkup(pasteboardImage.url.markup); + } + m_selectionData->setImage(pasteboardImage.image.get()); + } } void Pasteboard::write(const PasteboardBuffer&) @@ -129,7 +197,13 @@ void Pasteboard::write(const PasteboardBuffer&) void Pasteboard::write(const PasteboardWebContent& content) { - platformStrategies()->pasteboardStrategy()->writeToPasteboard(content); + if (m_selectionData) { + m_selectionData->clearAll(); + m_selectionData->setText(content.text); + m_selectionData->setMarkup(content.markup); + } else { + platformStrategies()->pasteboardStrategy()->writeToPasteboard(content); + } } Pasteboard::FileContentState Pasteboard::fileContentState() @@ -152,14 +226,54 @@ void Pasteboard::writePlainText(const String& text, SmartReplaceOption) writeString("text/plain;charset=utf-8"_s, text); } -void Pasteboard::writeCustomData(const Vector&) +void Pasteboard::writeCustomData(const Vector& data) { + if (m_selectionData) { + if (!data.isEmpty()) { + const auto& customData = data[0]; + customData.forEachPlatformString([this] (auto& type, auto& string) { + writeString(type, string); + }); + if (customData.hasSameOriginCustomData() || !customData.origin().isEmpty()) + m_selectionData->setCustomData(customData.createSharedBuffer()); + } + return; + } } void Pasteboard::write(const Color&) { } +#if ENABLE(DRAG_SUPPORT) + +Pasteboard::Pasteboard(std::unique_ptr&& context, SelectionData&& selectionData) + : m_context(WTFMove(context)) + , m_selectionData(WTFMove(selectionData)) +{ +} + +Pasteboard::Pasteboard(std::unique_ptr&& context, SelectionData& selectionData) + : m_context(WTFMove(context)) + , m_selectionData(selectionData) +{ +} + +std::unique_ptr Pasteboard::createForDragAndDrop(std::unique_ptr&& context) +{ + return makeUnique(WTFMove(context), SelectionData()); +} + +std::unique_ptr Pasteboard::create(const DragData& dragData) +{ + RELEASE_ASSERT(dragData.platformData()); + return makeUnique(dragData.createPasteboardContext(), *dragData.platformData()); +} +void Pasteboard::setDragImage(DragImage, const IntPoint&) +{ +} +#endif + } // namespace WebCore #endif // USE(LIBWPE) diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp index a8674916429908cabb86bd95dc5b3da217e1556b..6a464e2b0c1c45cd4e8effba678b8dde9dd870da 100644 --- a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp @@ -30,9 +30,11 @@ #include "WindowsKeyboardCodes.h" #include +#include #include #include #include +#include namespace WebCore { @@ -1303,6 +1305,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 16b45d9d3f3787a348d2d26427ca2b03fd5cf3d5..448321a8388b7075173061caf8c9b272997e02fd 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()) { @@ -54,72 +62,26 @@ void PlatformPasteboard::performAsDataOwner(DataOwnerType, NOESCAPE Function& 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;charset=utf-8"_s; - - CString textString = content.text.utf8(); - CString markupString = content.markup.utf8(); - - 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() }; - - wpe_pasteboard_write(m_pasteboard, &map); - - 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); - - 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/network/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp index 1178c8fb001994bc9e6166376a367d9bc148913c..fcc6534568cad6b42a819a435f84ba2b9baae6f8 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 18e1d04c6f984c1c3502542399ab1b8eeba1f239..2ec3ed7e28cdf802c017ca705bab3bf769f69a21 100644 --- a/Source/WebCore/platform/network/NetworkStorageSession.h +++ b/Source/WebCore/platform/network/NetworkStorageSession.h @@ -202,6 +202,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 bc4d0a6059710f349685b9782079e17f19e289fa..f15d5944bf4259248c1dcc11bd536e5398cb7f03 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.cpp +++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp @@ -78,6 +78,7 @@ ResourceResponseBase::ResourceResponseBase(std::optional d , m_httpStatusText(data ? data->httpStatusText : String { }) , m_httpVersion(data ? data->httpVersion : String { }) , m_httpHeaderFields(data ? data->httpHeaderFields : HTTPHeaderMap { }) + , m_httpRequestHeaderFields(data ? data->httpRequestHeaderFields : HTTPHeaderMap { }) , m_networkLoadMetrics(data && data->networkLoadMetrics ? Box::create(*data->networkLoadMetrics) : Box { }) , m_certificateInfo(data ? data->certificateInfo : std::nullopt) , m_httpStatusCode(data ? data->httpStatusCode : 0) @@ -904,6 +905,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, @@ -979,6 +981,11 @@ std::optional Coder httpRequestHeaderFields; + decoder >> httpRequestHeaderFields; + if (!httpRequestHeaderFields) + return std::nullopt; + std::optional httpStatusCode; decoder >> httpStatusCode; if (!httpStatusCode) @@ -1038,6 +1045,7 @@ std::optional Coder m_networkLoadMetrics; mutable std::optional m_certificateInfo; @@ -297,7 +302,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) + 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) : url(WTFMove(url)) , mimeType(WTFMove(mimeType)) , expectedContentLength(expectedContentLength) @@ -306,6 +311,7 @@ struct ResourceResponseData { , httpStatusText(WTFMove(httpStatusText)) , httpVersion(WTFMove(httpVersion)) , httpHeaderFields(WTFMove(httpHeaderFields)) + , httpRequestHeaderFields(WTFMove(httpRequestHeaderFields)) , networkLoadMetrics(WTFMove(networkLoadMetrics)) , source(source) , type(type) @@ -329,6 +335,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 d938386a2a7bb9a338b781706434fbee753a5ad4..96b8e6d3b7fc65fb6f04162e4975467b3cbd3cf4 100644 --- a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm +++ b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm @@ -552,6 +552,22 @@ 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) +{ + 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]]; + } + NSURL *cookieURL = url.createNSURL().get(); + setHTTPCookiesForURL(cookieStorage().get(), cookies, cookieURL, firstParty.createNSURL().get(), sameSiteInfo); +} + 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 37e129136c69b27d509acc01f10be42a8a1fe35a..9df0babc8f82372925fddf2211a7c8c908f3bb18 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/CurlStream.cpp b/Source/WebCore/platform/network/curl/CurlStream.cpp index d07f26d77447d05fa2b086d04e6aa105c3d6b4b1..52b09365fff63fa4099320d0eebc1d498e0c068e 100644 --- a/Source/WebCore/platform/network/curl/CurlStream.cpp +++ b/Source/WebCore/platform/network/curl/CurlStream.cpp @@ -37,7 +37,7 @@ namespace WebCore { WTF_MAKE_TZONE_ALLOCATED_IMPL(CurlStream); -CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias) +CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, bool ignoreCertificateErrors, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias) : m_scheduler(scheduler) , m_streamID(streamID) { @@ -52,6 +52,9 @@ CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, UR m_curlHandle->disableServerTrustEvaluation(); m_curlHandle->enableConnectionOnly(); + if (ignoreCertificateErrors) + m_curlHandle->disableServerTrustEvaluation(); + auto errorCode = m_curlHandle->perform(); if (errorCode != CURLE_OK) { diff --git a/Source/WebCore/platform/network/curl/CurlStream.h b/Source/WebCore/platform/network/curl/CurlStream.h index 96c3d2c216d522cf5c8b53b06a87eb849d159618..b595a1cfe961ad98364d8893014ab5c2fc1007f5 100644 --- a/Source/WebCore/platform/network/curl/CurlStream.h +++ b/Source/WebCore/platform/network/curl/CurlStream.h @@ -56,12 +56,12 @@ public: virtual void didFail(CurlStreamID, CURLcode, CertificateInfo&&) = 0; }; - static std::unique_ptr create(CurlStreamScheduler& scheduler, CurlStreamID streamID, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias) + static std::unique_ptr create(CurlStreamScheduler& scheduler, CurlStreamID streamID, bool ignoreCertificateErrors, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias) { - return makeUnique(scheduler, streamID, WTFMove(url), serverTrustEvaluation, localhostAlias); + return makeUnique(scheduler, streamID, ignoreCertificateErrors, WTFMove(url), serverTrustEvaluation, localhostAlias); } - CurlStream(CurlStreamScheduler&, CurlStreamID, URL&&, ServerTrustEvaluation, LocalhostAlias); + CurlStream(CurlStreamScheduler&, CurlStreamID, bool ignoreCertificateErrors, URL&&, ServerTrustEvaluation, LocalhostAlias); virtual ~CurlStream(); void send(UniqueArray&&, size_t); diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp b/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp index 83c4ca7871e536077f2d0a1a8ba6e2b4adb584da..12a49c124283fbe50ac17ecaa0c1e6fee32741d6 100644 --- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp +++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp @@ -43,7 +43,7 @@ CurlStreamScheduler::~CurlStreamScheduler() ASSERT(isMainThread()); } -CurlStreamID CurlStreamScheduler::createStream(const URL& url, CurlStream::Client& client, CurlStream::ServerTrustEvaluation serverTrustEvaluation, CurlStream::LocalhostAlias localhostAlias) +CurlStreamID CurlStreamScheduler::createStream(const URL& url, bool ignoreCertificateErrors, CurlStream::Client& client, CurlStream::ServerTrustEvaluation serverTrustEvaluation, CurlStream::LocalhostAlias localhostAlias) { ASSERT(isMainThread()); @@ -54,8 +54,8 @@ CurlStreamID CurlStreamScheduler::createStream(const URL& url, CurlStream::Clien auto streamID = m_currentStreamID; m_clientList.add(streamID, &client); - callOnWorkerThread([this, streamID, url = url.isolatedCopy(), serverTrustEvaluation, localhostAlias]() mutable { - m_streamList.add(streamID, CurlStream::create(*this, streamID, WTFMove(url), serverTrustEvaluation, localhostAlias)); + callOnWorkerThread([this, streamID, ignoreCertificateErrors, url = url.isolatedCopy(), serverTrustEvaluation, localhostAlias]() mutable { + m_streamList.add(streamID, CurlStream::create(*this, streamID, ignoreCertificateErrors, WTFMove(url), serverTrustEvaluation, localhostAlias)); }); return streamID; diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h index 2d7a77d759aaea9a541030af5e6015a8ed9c97a4..a0c947d325c984045dbbdf2580d19a32eea86ada 100644 --- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h +++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h @@ -39,7 +39,7 @@ public: CurlStreamScheduler(); virtual ~CurlStreamScheduler(); - WEBCORE_EXPORT CurlStreamID createStream(const URL&, CurlStream::Client&, CurlStream::ServerTrustEvaluation, CurlStream::LocalhostAlias); + WEBCORE_EXPORT CurlStreamID createStream(const URL&, bool ignoreCertificateErrors, CurlStream::Client&, CurlStream::ServerTrustEvaluation, CurlStream::LocalhostAlias); WEBCORE_EXPORT void destroyStream(CurlStreamID); WEBCORE_EXPORT void send(CurlStreamID, UniqueArray&&, size_t); diff --git a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp index 96289d8ae2e4feb60a91fab3f5cf1fc27b9e7c87..8c0b62c44a18571d1f3ea1ed81d59a0aae28d3f1 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 8750fc6d3ad81889da3d60685fc9a107bf4760c1..7a35cf7516b837084fafbfceae84147ab17bd161 100644 --- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp +++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp @@ -551,6 +551,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/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp index bbcc12d58f7b5df3462c93617f6ef19eef403cf2..b255b05da89248a99ff11965ceae840ef45b9fab 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -40,6 +40,7 @@ #include #include #include +#include "Pasteboard.h" namespace WebCore { @@ -691,7 +692,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 c3ffc7392c0b7fa099a7dd4e4be977cdee1c803c..9570dbb0f2c42ca38598a8898183c9b310f858ab 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/DragImageWin.cpp b/Source/WebCore/platform/win/DragImageWin.cpp index dd24e15115aeff41f0f4452a9cac292d75bc0d5d..8df467c008bdb3de59d301b14c1c20b8bb0b6a41 100644 --- a/Source/WebCore/platform/win/DragImageWin.cpp +++ b/Source/WebCore/platform/win/DragImageWin.cpp @@ -62,16 +62,22 @@ IntSize dragImageSize(DragImageRef image) { if (!image) return IntSize(); - BITMAP b; - GetObject(image, sizeof(BITMAP), &b); - return IntSize(b.bmWidth, b.bmHeight); + return { image->width(), image->height() }; } +#if USE(CAIRO) void deleteDragImage(DragImageRef image) { if (image) ::DeleteObject(image); } +#else +void deleteDragImage(DragImageRef) +{ + // Since this is a RefPtr, there's nothing additional we need to do to + // delete it. It will be released when it falls out of scope. +} +#endif DragImageRef dissolveDragImageToFraction(DragImageRef image, float) { @@ -79,8 +85,9 @@ DragImageRef dissolveDragImageToFraction(DragImageRef image, float) return image; } -DragImageRef createDragImageIconForCachedImageFilename(const String& filename) +DragImageRef createDragImageIconForCachedImageFilename(const String&) { +#if USE(CAIRO) SHFILEINFO shfi { }; auto fname = filename.wideCharacters(); if (FAILED(SHGetFileInfo(fname.data(), FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES))) @@ -96,6 +103,9 @@ DragImageRef createDragImageIconForCachedImageFilename(const String& filename) DeleteObject(iconInfo.hbmMask); return iconInfo.hbmColor; +#else + return nullptr; +#endif } #if USE(CAIRO) @@ -221,9 +231,9 @@ DragImageRef createDragImageForColor(const Color&, const FloatRect&, float, Path } #if USE(SKIA) -DragImageRef createDragImageFromImage(Image*, ImageOrientation, GraphicsClient*, float) +DragImageRef createDragImageFromImage(Image* image, ImageOrientation, GraphicsClient*, float) { - return nullptr; + return image->currentNativeImage()->platformImage(); } DragImageRef scaleDragImage(DragImageRef, FloatSize) diff --git a/Source/WebCore/platform/win/KeyEventWin.cpp b/Source/WebCore/platform/win/KeyEventWin.cpp index d450bf9d0fd1f0bf8f28db483ac9d3d60fa9d114..72a59403a0b5493aea4a8e28eb15eac24b652b09 100644 --- a/Source/WebCore/platform/win/KeyEventWin.cpp +++ b/Source/WebCore/platform/win/KeyEventWin.cpp @@ -243,10 +243,16 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData, { } -void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type, bool) +void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardsCompatibility) { - // 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 8aab5ddd1dc749ecdd02ac59eb81f16294d67235..31cfdfb8dd2e174f39470421c59d9e520ddf84de 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp @@ -1142,7 +1142,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) { @@ -1181,4 +1195,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/platform/wpe/DragDataWPE.cpp b/Source/WebCore/platform/wpe/DragDataWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbd32d390129129fd5b213f7f9c3e96bdca9355b --- /dev/null +++ b/Source/WebCore/platform/wpe/DragDataWPE.cpp @@ -0,0 +1,92 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DragData.h" +#include "SelectionData.h" + +namespace WebCore { + +bool DragData::canSmartReplace() const +{ + return false; +} + +bool DragData::containsColor() const +{ + return false; +} + +bool DragData::containsFiles() const +{ + return m_platformDragData->hasFilenames(); +} + +unsigned DragData::numberOfFiles() const +{ + return m_platformDragData->filenames().size(); +} + +Vector DragData::asFilenames() const +{ + return m_platformDragData->filenames(); +} + +bool DragData::containsPlainText() const +{ + return m_platformDragData->hasText(); +} + +String DragData::asPlainText() const +{ + return m_platformDragData->text(); +} + +Color DragData::asColor() const +{ + return Color(); +} + +bool DragData::containsCompatibleContent(DraggingPurpose) const +{ + return containsPlainText() || containsURL() || containsColor() || containsFiles(); +} + +bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const +{ + return !asURL(filenamePolicy).isEmpty(); +} + +String DragData::asURL(FilenameConversionPolicy filenamePolicy, String* title) const +{ + if (!m_platformDragData->hasURL()) + return String(); + if (filenamePolicy != ConvertFilenames) { + if (m_platformDragData->url().protocolIsFile()) + return { }; + } + + if (title) + *title = m_platformDragData->urlLabel(); + return m_platformDragData->url().string(); +} + +bool DragData::shouldMatchStyleOnDrop() const +{ + return false; +} + +} diff --git a/Source/WebCore/platform/wpe/DragImageWPE.cpp b/Source/WebCore/platform/wpe/DragImageWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5a20bfaacd42d27bee5f843483d6b60d9dee9dbd --- /dev/null +++ b/Source/WebCore/platform/wpe/DragImageWPE.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010,2017 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DragImage.h" +#include "NotImplemented.h" + +#include "Image.h" + +namespace WebCore { + +IntSize dragImageSize(DragImageRef) +{ + notImplemented(); + return { 0, 0 }; +} + +void deleteDragImage(DragImageRef) +{ + notImplemented(); +} + +DragImageRef scaleDragImage(DragImageRef, FloatSize) +{ + notImplemented(); + return nullptr; +} + +DragImageRef dissolveDragImageToFraction(DragImageRef image, float) +{ + notImplemented(); + return image; +} + +DragImageRef createDragImageFromImage(Image* image, ImageOrientation, GraphicsClient*, float) +{ + return image->currentNativeImage()->platformImage(); +} + + +DragImageRef createDragImageIconForCachedImageFilename(const String&) +{ + notImplemented(); + return nullptr; +} + +DragImageRef createDragImageForLink(Element&, URL&, const String&, TextIndicatorData&, float) +{ + notImplemented(); + return nullptr; +} + +DragImageRef createDragImageForColor(const Color&, const FloatRect&, float, Path&) +{ + return nullptr; +} + +} diff --git a/Source/WebCore/platform/wpe/SelectionData.cpp b/Source/WebCore/platform/wpe/SelectionData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..947bfe6576780038ecb87ea9bda116adb19dfd71 --- /dev/null +++ b/Source/WebCore/platform/wpe/SelectionData.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2009, Martin Robinson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "SelectionData.h" + +#include +#include +#include + +namespace WebCore { + +SelectionData::SelectionData(const String& text, const String& markup, const URL& url, const String& uriList, RefPtr&& image, RefPtr&& buffer, bool canSmartReplace) +{ + if (!text.isEmpty()) + setText(text); + if (!markup.isEmpty()) + setMarkup(markup); + if (!url.isEmpty()) + setURL(url, String()); + if (!uriList.isEmpty()) + setURIList(uriList); + if (image) + setImage(WTFMove(image)); + if (buffer) + setCustomData(buffer.releaseNonNull()); + setCanSmartReplace(canSmartReplace); +} + +static void replaceNonBreakingSpaceWithSpace(String& str) +{ + static const UChar NonBreakingSpaceCharacter = 0xA0; + static const UChar SpaceCharacter = ' '; + str = makeStringByReplacingAll(str, NonBreakingSpaceCharacter, SpaceCharacter); +} + +void SelectionData::setText(const String& newText) +{ + m_text = newText; + replaceNonBreakingSpaceWithSpace(m_text); +} + +void SelectionData::setURIList(const String& uriListString) +{ + m_uriList = uriListString; + + // This code is originally from: platform/chromium/ChromiumDataObject.cpp. + // FIXME: We should make this code cross-platform eventually. + + // Line separator is \r\n per RFC 2483 - however, for compatibility + // reasons we also allow just \n here. + + // Process the input and copy the first valid URL into the url member. + // In case no URLs can be found, subsequent calls to getData("URL") + // will get an empty string. This is in line with the HTML5 spec (see + // "The DragEvent and DataTransfer interfaces"). Also extract all filenames + // from the URI list. + bool setURL = hasURL(); + for (auto& line : uriListString.split('\n')) { + line = line.trim(deprecatedIsSpaceOrNewline); + if (line.isEmpty()) + continue; + if (line[0] == '#') + continue; + + URL url = URL(URL(), line); + if (url.isValid()) { + if (!setURL) { + m_url = url; + setURL = true; + } + + GUniqueOutPtr error; + GUniquePtr filename(g_filename_from_uri(line.utf8().data(), 0, &error.outPtr())); + if (!error && filename) + m_filenames.append(String::fromUTF8(filename.get())); + } + } +} + +void SelectionData::setURL(const URL& url, const String& label) +{ + m_url = url; + if (m_uriList.isEmpty()) + m_uriList = url.string(); + + if (!hasText()) + setText(url.string()); + + if (hasMarkup()) + return; + + String actualLabel(label); + if (actualLabel.isEmpty()) + actualLabel = url.string(); + + StringBuilder markup; + markup.append(""_s); + GUniquePtr escaped(g_markup_escape_text(actualLabel.utf8().data(), -1)); + markup.append(String::fromUTF8(escaped.get())); + markup.append(""_s); + setMarkup(markup.toString()); +} + +const String& SelectionData::urlLabel() const +{ + if (hasText()) + return text(); + + if (hasURL()) + return url().string(); + + return emptyString(); +} + +void SelectionData::clearAllExceptFilenames() +{ + clearText(); + clearMarkup(); + clearURIList(); + clearURL(); + clearImage(); + clearCustomData(); + + m_canSmartReplace = false; +} + +void SelectionData::clearAll() +{ + clearAllExceptFilenames(); + m_filenames.clear(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/wpe/SelectionData.h b/Source/WebCore/platform/wpe/SelectionData.h new file mode 100644 index 0000000000000000000000000000000000000000..a76b583a1e65cd6999fab4784c22dd9cb48d6aeb --- /dev/null +++ b/Source/WebCore/platform/wpe/SelectionData.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2009, Martin Robinson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "Image.h" +#include "SharedBuffer.h" +#include +#include +#include + +namespace WebCore { + +class SelectionData { + WTF_MAKE_FAST_ALLOCATED; +public: + void setText(const String&); + const String& text() const { return m_text; } + bool hasText() const { return !m_text.isEmpty(); } + void clearText() { m_text = emptyString(); } + + void setMarkup(const String& newMarkup) { m_markup = newMarkup; } + const String& markup() const { return m_markup; } + bool hasMarkup() const { return !m_markup.isEmpty(); } + void clearMarkup() { m_markup = emptyString(); } + + void setURL(const URL&, const String&); + const URL& url() const { return m_url; } + const String& urlLabel() const; + bool hasURL() const { return !m_url.isEmpty() && m_url.isValid(); } + void clearURL() { m_url = URL(); } + + void setURIList(const String&); + const String& uriList() const { return m_uriList; } + const Vector& filenames() const { return m_filenames; } + bool hasURIList() const { return !m_uriList.isEmpty(); } + bool hasFilenames() const { return !m_filenames.isEmpty(); } + void clearURIList() { m_uriList = emptyString(); } + + void setImage(RefPtr&& newImage) { m_image = WTFMove(newImage); } + const RefPtr& image() const { return m_image; } + bool hasImage() const { return m_image; } + void clearImage() { m_image = nullptr; } + + void setCanSmartReplace(bool canSmartReplace) { m_canSmartReplace = canSmartReplace; } + bool canSmartReplace() const { return m_canSmartReplace; } + + void setCustomData(Ref&& buffer) { m_customData = WTFMove(buffer); } + const RefPtr& customData() const { return m_customData; } + bool hasCustomData() const { return !!m_customData; } + void clearCustomData() { m_customData = nullptr; } + + void clearAll(); + void clearAllExceptFilenames(); + + SelectionData(const String& text, const String& markup, const URL&, const String& uriList, RefPtr&&, RefPtr&&, bool); + SelectionData() = default; + +private: + String m_text; + String m_markup; + URL m_url; + String m_uriList; + Vector m_filenames; + RefPtr m_image; + bool m_canSmartReplace { false }; + RefPtr m_customData; +}; + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index 015f1d0d829c0a1ef2c0cc137eb4967fa7bfe67a..25a6d41d2e08d50004749298f9555024a895b61c 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -228,13 +228,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 { auto innerText = innerTextElement(); diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h index faf34133df0bf205072145ffbab8163b93d3c874..fdc4554952e0e33f8827bb3d00c827dec966ad15 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -38,9 +38,9 @@ public: WEBCORE_EXPORT HTMLTextFormControlElement& textFormControlElement() const; WEBCORE_EXPORT Ref protectedTextFormControlElement() const; -#if PLATFORM(IOS_FAMILY) bool canScroll() const; +#if PLATFORM(IOS_FAMILY) // Returns the line height of the inner renderer. int innerLineHeight() const override; #endif diff --git a/Source/WebCore/workers/WorkerConsoleClient.cpp b/Source/WebCore/workers/WorkerConsoleClient.cpp index 5b64d59511778572142eae5e48b16cfaa1040d49..7082cd677870f4c359130bc065bdee097c82feda 100644 --- a/Source/WebCore/workers/WorkerConsoleClient.cpp +++ b/Source/WebCore/workers/WorkerConsoleClient.cpp @@ -104,4 +104,6 @@ void WorkerConsoleClient::recordEnd(JSC::JSGlobalObject*, Ref&& // FIXME: Web Inspector: support console screenshots in a Worker void WorkerConsoleClient::screenshot(JSC::JSGlobalObject*, Ref&&) { } +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 db95c8273bd0deb3f903a45d02fc07bbbd8ab305..bf88228b4c838b90d11d430cc9429d5130631afa 100644 --- a/Source/WebCore/workers/WorkerConsoleClient.h +++ b/Source/WebCore/workers/WorkerConsoleClient.h @@ -58,6 +58,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& m_globalScope; }; diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp index eb1ee28ea9a6bee86f68b4d0d4e16ae6dea32772..1968c70c80c1529ada0e76f1a5f45981924fa629 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp @@ -97,6 +97,8 @@ #if PLATFORM(COCOA) #include +#include "NetworkDataTaskCocoa.h" +#include "NetworkSessionCocoa.h" #endif #if ENABLE(APPLE_PAY_REMOTE_UI) @@ -1231,6 +1233,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 (auto* storageSession = protectedNetworkProcess()->storageSession(m_sessionID)) diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h index 3f1539237c6c8d1cd832cd3ece2ba20939e01a41..1259c36e38d46c0ebfdf98be20f217433f831ca5 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h @@ -388,6 +388,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 b10706aafd037a2b92a68b0d2c474ec2e42cd2fe..f80792c02d880dbd61849233fdbc348f1eeffb33 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in @@ -80,6 +80,8 @@ messages -> NetworkConnectionToWebProcess WantsDispatchMessage { ClearPageSpecificData(WebCore::PageIdentifier pageID); + SetCookieFromResponse(URL firstParty, struct WebCore::SameSiteInfo sameSiteInfo, URL url, String setCookieValue); + RemoveStorageAccessForFrame(WebCore::FrameIdentifier frameID, WebCore::PageIdentifier pageID); LogUserInteraction(WebCore::RegistrableDomain domain) ResourceLoadStatisticsUpdated(Vector statistics) -> () diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp index be181729d818871958a51ad54b95424be796cbd1..759be2137d58cfbc088e1e459fdfca5d329c3ff4 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp @@ -670,6 +670,12 @@ void NetworkProcess::registrableDomainsExemptFromWebsiteDataDeletion(PAL::Sessio completionHandler({ }); } +void NetworkProcess::setIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignore) +{ + if (auto* networkSession = this->networkSession(sessionID)) + networkSession->setIgnoreCertificateErrors(ignore); +} + void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler&& completionHandler) { if (auto* session = networkSession(sessionID)) { diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h index aad6d1ad7d9735935f7d55d56ae8f3e8d0c5b852..a7421b51a4e8bbf9c695d2aca3ec6cfc98d14bf5 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h @@ -84,6 +84,7 @@ class SessionID; namespace WebCore { class CertificateInfo; +struct Cookie; class CurlProxySettings; class ProtectionSpace; class NetworkStorageSession; @@ -235,6 +236,9 @@ public: void registrableDomainsWithLastAccessedTime(PAL::SessionID, CompletionHandler>)>&&); void registrableDomainsExemptFromWebsiteDataDeletion(PAL::SessionID, CompletionHandler)>&&); + + void setIgnoreCertificateErrors(PAL::SessionID, bool); + void clearPrevalentResource(PAL::SessionID, RegistrableDomain&&, CompletionHandler&&); void clearUserInteraction(PAL::SessionID, RegistrableDomain&&, CompletionHandler&&); void deleteAndRestrictWebsiteDataForRegistrableDomains(PAL::SessionID, OptionSet, RegistrableDomainsToDeleteOrRestrictWebsiteDataFor&&, CompletionHandler&&)>&&); diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in index 64312176007bfc3c06ae2d624dbbabc4007e0fdf..8dfd79c77f27f13aa23927c9b2c6610cd40885d5 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in @@ -91,6 +91,8 @@ messages -> NetworkProcess : AuxiliaryProcess WantsAsyncDispatchMessage { SetInspectionForServiceWorkersAllowed(PAL::SessionID sessionID, bool inspectable) + SetIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignoreTLSErrors) + ClearPrevalentResource(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () ClearUserInteraction(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () DumpResourceLoadStatistics(PAL::SessionID sessionID) -> (String dumpedStatistics) diff --git a/Source/WebKit/NetworkProcess/NetworkSession.h b/Source/WebKit/NetworkProcess/NetworkSession.h index 2a48fae7bd8cce5ee360df66e5bc49cb4d2b9c54..5fdec3ff3fb706a426717c95831ece36c43543ce 100644 --- a/Source/WebKit/NetworkProcess/NetworkSession.h +++ b/Source/WebKit/NetworkProcess/NetworkSession.h @@ -207,6 +207,9 @@ public: void lowMemoryHandler(WTF::Critical); + void setIgnoreCertificateErrors(bool ignore) { m_ignoreCertificateErrors = ignore; } + bool ignoreCertificateErrors() { return m_ignoreCertificateErrors; } + void removeSoftUpdateLoader(ServiceWorkerSoftUpdateLoader* loader) { m_softUpdateLoaders.remove(loader); } void addNavigationPreloaderTask(ServiceWorkerFetchTask&); ServiceWorkerFetchTask* navigationPreloaderTaskFromFetchIdentifier(WebCore::FetchIdentifier); @@ -345,6 +348,7 @@ protected: bool m_privateClickMeasurementDebugModeEnabled { false }; std::optional m_ephemeralMeasurement; bool m_isRunningEphemeralMeasurementTest { false }; + bool m_ignoreCertificateErrors { false }; HashSet> m_keptAliveLoads; diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm index 846603d498fa5f0cfe8829340ed810558df54b41..6edf57edc6d0c2d7ba79319ddb2765b856a8cddc 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm @@ -805,6 +805,8 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didRece if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { sessionCocoa->setClientAuditToken(challenge); + if (sessionCocoa->ignoreCertificateErrors()) + return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); negotiatedLegacyTLS = checkForLegacyTLS(task._incompleteTaskMetrics.transactionMetrics.lastObject); if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes && task._preconnect) @@ -1148,6 +1150,14 @@ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)data resourceResponse.setDeprecatedNetworkLoadMetrics(WebCore::copyTimingData(taskMetrics.get(), networkDataTask->networkLoadMetrics())); resourceResponse.setProxyName(WTFMove(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 = WTFMove(requestHeaders); + networkDataTask->didReceiveResponse(WTFMove(resourceResponse), negotiatedLegacyTLS, privateRelayed, [completionHandler = makeBlockPtr(completionHandler), taskIdentifier](WebCore::PolicyAction policyAction) { #if !LOG_DISABLED LOG(NetworkSession, "%llu didReceiveResponse completionHandler (%s)", taskIdentifier, toString(policyAction).characters()); diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp index 1aa46419c05ba688a2ca79bfa48f4c7a9164375e..9b90036b16c587cd509bb35f067c9a9fddd8cfc2 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp @@ -80,10 +80,18 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas blockCookies(); restrictRequestReferrerToOriginIfNeeded(request); - m_curlRequest = createCurlRequest(WTFMove(request)); - if (!m_initialCredential.isEmpty()) { - m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); - m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); + if (request.url().protocolIsData()) { + DataURLDecoder::decode(request.url(), { }, DataURLDecoder::ShouldValidatePadding::Yes, [this, protectedThis = Ref { *this }](auto decodeResult) mutable { + didReadDataURL(WTFMove(decodeResult)); + }); + } else { + m_curlRequest = createCurlRequest(WTFMove(request)); + if (!m_initialCredential.isEmpty()) { + m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); + m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); + } + if (m_session->ignoreCertificateErrors()) + m_curlRequest->disableServerTrustEvaluation(); } } @@ -166,6 +174,7 @@ void NetworkDataTaskCurl::curlDidReceiveResponse(CurlRequest& request, CurlRespo updateNetworkLoadMetrics(receivedResponse.networkLoadMetrics); m_response.setDeprecatedNetworkLoadMetrics(Box::create(WTFMove(receivedResponse.networkLoadMetrics))); + m_response.m_httpRequestHeaderFields = request.resourceRequest().httpHeaderFields(); handleCookieHeaders(request.resourceRequest(), receivedResponse); @@ -293,6 +302,35 @@ bool NetworkDataTaskCurl::shouldRedirectAsGET(const ResourceRequest& request, bo return false; } +void NetworkDataTaskCurl::didReadDataURL(std::optional&& result) +{ + if (state() == State::Canceling || state() == State::Completed) + return; + + m_dataURLResult = WTFMove(result); + m_response = ResourceResponse::dataURLResponse(firstRequest().url(), m_dataURLResult.value()); + invokeDidReceiveResponse(); +} + +void NetworkDataTaskCurl::downloadDataURL(Download& download) +{ + if (!m_dataURLResult) { + deleteDownloadFile(); + download.didFail(internalError(firstRequest().url()), std::span()); + return; + } + + if (!m_downloadDestinationFile.write(std::span(m_dataURLResult.value().data.data(), m_dataURLResult.value().data.size()))) { + deleteDownloadFile(); + download.didFail(ResourceError(CURLE_WRITE_ERROR, m_response.url()), std::span()); + return; + } + + download.didReceiveData(m_dataURLResult.value().data.size(), 0, 0); + m_downloadDestinationFile = { }; + download.didFinish(); +} + void NetworkDataTaskCurl::invokeDidReceiveResponse() { didReceiveResponse(ResourceResponse(m_response), NegotiatedLegacyTLS::No, PrivateRelayed::No, std::nullopt, [this, protectedThis = Ref { *this }](PolicyAction policyAction) { @@ -322,6 +360,8 @@ void NetworkDataTaskCurl::invokeDidReceiveResponse() download->didCreateDestination(m_pendingDownloadLocation); if (m_curlRequest) m_curlRequest->completeDidReceiveResponse(); + else if (firstRequest().url().protocolIsData()) + downloadDataURL(download); break; } default: @@ -410,6 +450,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection() m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic); } + if (m_session->ignoreCertificateErrors()) + m_curlRequest->disableServerTrustEvaluation(); if (m_state != State::Suspended) { m_state = State::Suspended; diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h index 7babe41b8351f8adbffcf194310d4df41637b192..2d6f0055cfcb0ec8a4629ce41b19cecd17ab4fdc 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h @@ -28,6 +28,7 @@ #include "NetworkDataTask.h" #include "NetworkLoadParameters.h" #include +#include #include #include #include @@ -43,6 +44,8 @@ class SharedBuffer; namespace WebKit { +class Download; + class NetworkDataTaskCurl final : public NetworkDataTask, public WebCore::CurlRequestClient { public: static Ref create(NetworkSession& session, NetworkDataTaskClient& client, const NetworkLoadParameters& parameters) @@ -76,6 +79,9 @@ private: void curlDidComplete(WebCore::CurlRequest&, WebCore::NetworkLoadMetrics&&) override; void curlDidFailWithError(WebCore::CurlRequest&, WebCore::ResourceError&&, WebCore::CertificateInfo&&) override; + void didReadDataURL(std::optional&&); + void downloadDataURL(Download&); + void invokeDidReceiveResponse(); bool shouldStartHTTPRedirection(); @@ -114,6 +120,9 @@ private: unsigned m_authFailureCount { 0 }; bool m_allowOverwriteDownload { false }; + + std::optional m_dataURLResult; + FileSystem::FileHandle m_downloadDestinationFile; bool m_blockingCookies { false }; diff --git a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp index a6f84189b7163563874a148c9bf1c8afb42bb446..8b5db0010c4be8e24efd121e4ccba0568e6f4bed 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp @@ -68,7 +68,7 @@ void NetworkSessionCurl::clearAlternativeServices(WallTime) std::unique_ptr NetworkSessionCurl::createWebSocketTask(WebPageProxyIdentifier webPageProxyID, std::optional, std::optional, NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol, const WebCore::ClientOrigin& clientOrigin, bool, bool, OptionSet, StoredCredentialsPolicy) { - return makeUnique(channel, webPageProxyID, request, protocol, clientOrigin); + return makeUnique(channel, webPageProxyID, request, protocol, ignoreCertificateErrors(), clientOrigin); } void NetworkSessionCurl::didReceiveChallenge(WebSocketTask& webSocketTask, WebCore::AuthenticationChallenge&& challenge, CompletionHandler&& challengeCompletionHandler) diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp index 1853b717d021c5ec5c79abb61bec684460646a7a..625b921890a75c521bdf6fc3a5fd4bf3e9d74006 100644 --- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp @@ -39,11 +39,12 @@ namespace WebKit { WTF_MAKE_TZONE_ALLOCATED_IMPL(WebSocketTask); -WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifier webProxyPageID, const WebCore::ResourceRequest& request, const String& protocol, const WebCore::ClientOrigin& clientOrigin) +WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifier webProxyPageID, const WebCore::ResourceRequest& request, const String& protocol, bool ignoreCertificateErrors, const WebCore::ClientOrigin& clientOrigin) : m_channel(channel) , m_webProxyPageID(webProxyPageID) , m_request(request.isolatedCopy()) , m_protocol(protocol) + , m_ignoreCertificateErrors(ignoreCertificateErrors) , m_scheduler(WebCore::CurlContext::singleton().streamScheduler()) { // We use topOrigin in case of service worker websocket connections, for which pageID does not link to a real page. @@ -55,7 +56,7 @@ WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifi if (networkSession() && networkSession()->networkProcess().localhostAliasesForTesting().contains(m_request.url().host())) localhostAlias = WebCore::CurlStream::LocalhostAlias::Enable; - m_streamID = m_scheduler.createStream(request.url(), *this, WebCore::CurlStream::ServerTrustEvaluation::Enable, localhostAlias); + m_streamID = m_scheduler.createStream(request.url(), ignoreCertificateErrors, *this, WebCore::CurlStream::ServerTrustEvaluation::Enable, localhostAlias); channel.didSendHandshakeRequest(WebCore::ResourceRequest(m_request)); } @@ -265,7 +266,7 @@ void WebSocketTask::tryServerTrustEvaluation(WebCore::AuthenticationChallenge&& if (networkSession() && networkSession()->networkProcess().localhostAliasesForTesting().contains(m_request.url().host())) localhostAlias = WebCore::CurlStream::LocalhostAlias::Enable; - m_streamID = m_scheduler.createStream(m_request.url(), *this, WebCore::CurlStream::ServerTrustEvaluation::Disable, localhostAlias); + m_streamID = m_scheduler.createStream(m_request.url(), m_ignoreCertificateErrors, *this, WebCore::CurlStream::ServerTrustEvaluation::Disable, localhostAlias); } else didFail(WTFMove(errorReason)); }); diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h index 0ef9f38c7662f922b7a8e4da81613799b0fddc68..45704b96df02cead2f21fd948455502793a1508c 100644 --- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h +++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h @@ -55,7 +55,7 @@ class WebSocketTask : public CanMakeWeakPtr, public CanMakeChecke WTF_MAKE_TZONE_ALLOCATED(WebSocketTask); WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(WebSocketTask); public: - WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, const String& protocol, const WebCore::ClientOrigin&); + WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, const String& protocol, bool ignoreCertificateErrors, const WebCore::ClientOrigin&); virtual ~WebSocketTask(); void sendString(std::span, CompletionHandler&&); @@ -110,6 +110,7 @@ private: WebPageProxyIdentifier m_webProxyPageID; WebCore::ResourceRequest m_request; String m_protocol; + bool m_ignoreCertificateErrors { false }; WebCore::SecurityOriginData m_topOrigin; WebCore::CurlStreamScheduler& m_scheduler; 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 9ecb3e28299aa54a8ac309e74afb6944833e8eae..383bdd7533fad2fd58b4d0cceee4e68962aa8455 100644 --- a/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in +++ b/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in @@ -451,9 +451,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 4fd4b7c714f0c6364f7c239b9e25af3428ffd1fd..56d6e55721c077a34dee36ea7043395331d453bb 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp @@ -461,6 +461,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr&& inputStream) m_networkLoadMetrics.responseStart = MonotonicTime::now(); #endif + auto& additionalMetrics = additionalNetworkLoadMetricsForWebInspector(); + m_response.m_httpRequestHeaderFields = additionalMetrics.requestHeaders; dispatchDidReceiveResponse(); } @@ -563,6 +565,8 @@ bool NetworkDataTaskSoup::acceptCertificate(GTlsCertificate* certificate, GTlsCe { ASSERT(m_soupMessage); URL url = soupURIToURL(soup_message_get_uri(m_soupMessage.get())); + if (m_session->ignoreCertificateErrors()) + return true; auto error = static_cast(*m_session).soupNetworkSession().checkTLSErrors(url, certificate, tlsErrors); if (!error) return true; diff --git a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp index c0c9bf6f4f1879efb8dfdd24951ef67ae373fa2f..48aeb8ac1324a58dc59bdb125c8ec4e317e24fd2 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp @@ -100,6 +100,11 @@ void NetworkSessionSoup::clearCredentials(WallTime) #endif } +static gboolean webSocketAcceptCertificateCallbackIgnoreTLSErrors(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) +{ + return TRUE; +} + #if USE(SOUP2) static gboolean webSocketAcceptCertificateCallback(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) { @@ -130,12 +135,16 @@ std::unique_ptr NetworkSessionSoup::createWebSocketTask(WebPagePr #if USE(SOUP2) g_signal_connect(soupMessage.get(), "network-event", G_CALLBACK(webSocketMessageNetworkEventCallback), this); #else - g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) -> gboolean { - if (DeprecatedGlobalSettings::allowsAnySSLCertificate()) - return TRUE; - - return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors); - }), this); + if (ignoreCertificateErrors()) { + g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(webSocketAcceptCertificateCallbackIgnoreTLSErrors), this); + } else { + g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) -> gboolean { + if (DeprecatedGlobalSettings::allowsAnySSLCertificate()) + return TRUE; + + return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors); + }), this); + } #endif } diff --git a/Source/WebKit/PlatformGTK.cmake b/Source/WebKit/PlatformGTK.cmake index 2990740be0d39d16ebbc625639c57200cdd700a8..78d25fe109ac96343d4aeedbc1e6b0087b34299a 100644 --- a/Source/WebKit/PlatformGTK.cmake +++ b/Source/WebKit/PlatformGTK.cmake @@ -321,6 +321,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GSTREAMER_PBUTILS_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} +# Playwright begin + ${LIBVPX_INCLUDE_DIRS} +# Playwright end ) list(APPEND WebKit_INTERFACE_INCLUDE_DIRECTORIES @@ -360,6 +363,9 @@ if (USE_LIBWEBRTC) list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES "${THIRDPARTY_DIR}/libwebrtc/Source/" "${THIRDPARTY_DIR}/libwebrtc/Source/webrtc" +# Playwright begin + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" +# Playwright end ) endif () @@ -411,6 +417,12 @@ else () set(WebKitGTK_ENUM_HEADER_TEMPLATE ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitEnumTypesGtk3.h.in) endif () +# Playwright begin +list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" +) +# Playwright end + # To generate WebKitEnumTypes.h we want to use all installed headers, except WebKitEnumTypes.h itself. set(WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_INSTALLED_HEADERS}) list(REMOVE_ITEM WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_DERIVED_SOURCES_DIR}/webkit/WebKitEnumTypes.h) diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index d55e9837af868c774cadcd6791ec07ccee1a97a0..649c0668818d6f2d70036bb18ff108060318d0fb 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -121,6 +121,8 @@ list(APPEND WebKit_SERIALIZATION_IN_FILES Shared/glib/UserMessage.serialization.in Shared/soup/WebCoreArgumentCodersSoup.serialization.in + + Shared/libwpe/ArgumentCodersWPE.serialization.in ) list(APPEND WebKit_DERIVED_SOURCES @@ -220,6 +222,7 @@ set(WPE_API_HEADER_TEMPLATES ${WEBKIT_DIR}/UIProcess/API/glib/WebKitWindowProperties.h.in ${WEBKIT_DIR}/UIProcess/API/glib/WebKitWebsitePolicies.h.in ${WEBKIT_DIR}/UIProcess/API/glib/webkit.h.in + ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in ) if (ENABLE_2022_GLIB_API) @@ -430,7 +433,16 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GIO_UNIX_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} +# Playwright begin + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" +# Playwright end +) + +# Playwright begin +list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" ) +# Playwright end list(APPEND WebKit_LIBRARIES WPE::libwpe diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake index 8429fc8b2e3721830edf197b3369f4f21bb70a9a..bb6779326529bfe16f47dd1b941f4e3d364cb4df 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/InspectorTargetProxyWin.cpp + UIProcess/win/InspectorPlaywrightAgentClientWin.cpp UIProcess/win/PageClientImpl.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/AcceleratedSurface.cpp @@ -119,8 +125,81 @@ list(APPEND WebKit_PUBLIC_FRAMEWORK_HEADERS list(APPEND WebKit_PRIVATE_LIBRARIES comctl32 + ${LIBVPX_CUSTOM_LIBRARY} +) + +# Playwright begin +list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" + "${LIBVPX_CUSTOM_INCLUDE_DIR}" +) + +list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" ) +set(vpxutils_SOURCES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvwriter.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_from.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_any.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_any.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_rvv.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_uv.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/video_common.cc" +) + +add_library(vpxutils STATIC ${vpxutils_SOURCES}) + +target_include_directories(vpxutils PRIVATE + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" +) + +target_link_libraries(WebKit PRIVATE vpxutils) +# Playwright end + list(APPEND WebProcess_SOURCES WebProcess/EntryPoint/win/WebProcessMain.cpp diff --git a/Source/WebKit/Shared/AuxiliaryProcess.h b/Source/WebKit/Shared/AuxiliaryProcess.h index c36aaf218982ee54d433b023485ac36e7c45cb2b..1f07f8ebad02fd11a4d23a69ec5092122df73aa0 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 c72c9733800b6f836c4d3ccb0b50d40c3ee83067..e2955ddebe388d886ca43d733dce0eb58256ce8b 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,23 +71,39 @@ 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, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(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, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands)) + { + } #elif PLATFORM(IOS_FAMILY) enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(::WebEvent *, HandledByInputMethod); #elif 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, WallTime timestamp) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp) + { + } #if PLATFORM(WPE) && ENABLE(WPE_PLATFORM) NativeWebKeyboardEvent(WPEEvent*, const String&, bool isAutoRepeat); NativeWebKeyboardEvent(const String&, std::optional>&&, std::optional&&); #endif #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, WallTime 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 a39b6dd673e1639f9fe64c23dd054f0ff57f7464..4026f6244889e5a0ee85edb72696d0be20ba531d 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h @@ -87,6 +87,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, WallTime timestamp) + : WebMouseEvent({type, modifiers, timestamp}, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount) { } +#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 f8e96218fd2671d1c0aca5e549efe0d8b94ef0f9..6cebd61bceb39c08e916fe991e4c3fc6f34b4704 100644 --- a/Source/WebKit/Shared/NativeWebWheelEvent.h +++ b/Source/WebKit/Shared/NativeWebWheelEvent.h @@ -74,7 +74,8 @@ public: #elif PLATFORM(WIN) NativeWebWheelEvent(HWND, UINT message, WPARAM, LPARAM, float deviceScaleFactor); #endif - + NativeWebWheelEvent(const WebWheelEvent & webWheelEvent) + : WebWheelEvent(webWheelEvent) { } #if USE(APPKIT) NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/Pasteboard.serialization.in b/Source/WebKit/Shared/Pasteboard.serialization.in index ea1eb9f00feaaecf73bdddc37c904e88f43bfa85..8a631e5293a11abd650958baad4e967840a9a526 100644 --- a/Source/WebKit/Shared/Pasteboard.serialization.in +++ b/Source/WebKit/Shared/Pasteboard.serialization.in @@ -73,7 +73,7 @@ header: #if PLATFORM(MAC) String userVisibleForm #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) String markup #endif }; diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in index c0ba2034b3d6a9fd9d807f1d67a62284c311c3dc..d688da2d022ded01cf9828fd6d56d0570fcc5735 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in @@ -2826,6 +2826,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(); @@ -3624,6 +3627,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 8040819bba9dcde87311aaafe7d8177d0e07281d..24972c0a357324d27910ae6ff1979d1c6b8bc758 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, WallTime 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(WTFMove(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, WallTime 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(WTFMove(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, WallTime 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() { } diff --git a/Source/WebKit/Shared/WebKeyboardEvent.h b/Source/WebKit/Shared/WebKeyboardEvent.h index 8e4e2d6d5ebb08fba210fe0a328d45290348dd11..32a43192ec1e918c33b1b046b71d2ec571dc92ff 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, WallTime 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, WallTime 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) 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, WallTime 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, WallTime timestamp); #endif const String& text() const { return m_text; } diff --git a/Source/WebKit/Shared/WebMouseEvent.h b/Source/WebKit/Shared/WebMouseEvent.h index 20a6e465457151b02daa22e6bc059cf0e117ece5..ef4b1f737aaa683bc13c447aa4ca77e5cf0d64d7 100644 --- a/Source/WebKit/Shared/WebMouseEvent.h +++ b/Source/WebKit/Shared/WebMouseEvent.h @@ -70,6 +70,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::IntPoint& position() const { return m_position; } // Relative to the view. void setPosition(const WebCore::IntPoint& position) { m_position = position; } const WebCore::IntPoint& globalPosition() const { return m_globalPosition; } diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h index 40b760ec89270bb9a8c586d05cab205c8bd9e7cf..db59f464cc96f9db4800034509e048a1f4d237ac 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h @@ -301,6 +301,8 @@ struct WebPageCreationParameters { WebCore::ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking { WebCore::ShouldRelaxThirdPartyCookieBlocking::No }; bool httpsUpgradeEnabled { true }; + + 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 d137231cfb0f9d9632e788f8e08968ad514f2227..6647f08415b1f0b213e4162ca93697e39280c888 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in +++ b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in @@ -223,6 +223,8 @@ enum class WebCore::UserInterfaceLayoutDirection : bool; bool httpsUpgradeEnabled; + 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 9899d60864664d1abff2b71c1c01e564e5dfb08c..391e0e42ca6a39f82b5a12c6aede069d61095ee2 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 char* 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), StringView::fromLatin1(processName)); diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp index 8d33ceb065fb3e90372b0c696779189d07838da0..6e3194c3e96e46bfa09f8d706324e6515df1e7f4 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -51,12 +51,12 @@ 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, WallTime::now()), text, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, false, std::nullopt, std::nullopt, WTFMove(commands), isAutoRepeat, isKeypad) + : WebKeyboardEvent(WebEvent(type, modifiers, WallTime::now()), text, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, false, std::nullopt, std::nullopt, WTFMove(commands), false, isKeypad) { } NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event) - : WebKeyboardEvent(WebEvent(event.type(), event.modifiers(), event.timestamp()), event.text(), event.key(), event.code(), event.keyIdentifier(), event.windowsVirtualKeyCode(), event.nativeVirtualKeyCode(), event.handledByInputMethod(), std::optional>(event.preeditUnderlines()), std::optional(event.preeditSelectionRange()), Vector(event.commands()), event.isAutoRepeat(), event.isKeypad()) + : WebKeyboardEvent(event) , m_nativeEvent(event.nativeEvent() ? constructNativeEvent(event.nativeEvent()) : nullptr) { } diff --git a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp index 9a1c3f09c756ea368ac2d68e183a13e2eb47ead7..01c738376230f83376d80d6d225543a3914943dd 100644 --- a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp @@ -61,7 +61,7 @@ NativeWebMouseEvent::NativeWebMouseEvent(WebEventType type, WebMouseEventButton } NativeWebMouseEvent::NativeWebMouseEvent(const NativeWebMouseEvent& event) - : WebMouseEvent(WebEvent(event.type(), event.modifiers(), event.timestamp()), event.button(), event.buttons(), event.position(), event.globalPosition(), event.deltaX(), event.deltaY(), event.deltaZ(), event.clickCount(), 0, WebMouseEventSyntheticClickType::NoTap, event.isTouchEvent(), event.pointerId(), event.pointerType()) + : WebMouseEvent(event) , m_nativeEvent(event.nativeEvent() ? constructNativeEvent(const_cast(event.nativeEvent())) : nullptr) { } diff --git a/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.serialization.in b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.serialization.in new file mode 100644 index 0000000000000000000000000000000000000000..f4f09d171ebf9774b3f8744751d220d35941fcb5 --- /dev/null +++ b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.serialization.in @@ -0,0 +1,32 @@ +# Copyright (C) 2024 Igalia, S.L. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +header: +class WebCore::SelectionData { + String text() + String markup() + URL url() + String uriList() + RefPtr image() + RefPtr customData() + bool canSmartReplace() +} diff --git a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp index 7fcd22cd2172cd7fa77aee12ad5cfcf7a435abba..bc822b40eea889fb0499dd4e78f89f04d87c64a1 100644 --- a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp +++ b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp @@ -40,6 +40,15 @@ 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) @@ -94,6 +103,10 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_END } #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 053e9336017d8818b3cbea79ce7c145fd5c46274..5632498d6ef875df80fc68ec206a9d08e5d05a6f 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 8580135604e6c41c0d2adc22b37ce50366069788..dcbca0904ab9acff6bfcc5cffd6f821af682ecb5 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt @@ -391,6 +391,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 @@ -400,16 +401,20 @@ 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/ModelElementController.cpp UIProcess/OverrideLanguages.cpp UIProcess/PageLoadState.cpp +UIProcess/PlaywrightFullScreenManagerProxyClient.cpp UIProcess/ProcessAssertion.cpp UIProcess/ProcessThrottler.cpp UIProcess/ProvisionalFrameProxy.cpp UIProcess/ProvisionalPageProxy.cpp +UIProcess/RemoteInspectorPipe.cpp UIProcess/RemotePageDrawingAreaProxy.cpp UIProcess/RemotePageFullscreenManagerProxy.cpp UIProcess/RemotePageProxy.cpp @@ -452,6 +457,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 @@ -598,7 +605,11 @@ UIProcess/Inspector/WebInspectorUtilities.cpp UIProcess/Inspector/WebPageDebuggable.cpp UIProcess/Inspector/WebPageInspectorController.cpp +UIProcess/Inspector/Agents/CairoJpegEncoder.cpp UIProcess/Inspector/Agents/InspectorBrowserAgent.cpp +UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp +UIProcess/Inspector/Agents/ScreencastEncoder.cpp +UIProcess/Inspector/Agents/WebMFileWriter.cpp UIProcess/Media/AudioSessionRoutingArbitratorProxy.cpp UIProcess/Media/MediaUsageManager.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt index 768e618630ca0090790320007cbcadad8e0d6452..536e02dc95c2adff1be74a1c2116ab8e8e98196c 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt @@ -272,6 +272,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm UIProcess/API/Cocoa/_WKAttachment.mm UIProcess/API/Cocoa/_WKAutomationSession.mm UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm +UIProcess/API/Cocoa/_WKBrowserInspector.mm UIProcess/API/Cocoa/_WKContentRuleListAction.mm UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @no-unify @@ -468,6 +469,7 @@ UIProcess/Inspector/ios/WKInspectorHighlightView.mm UIProcess/Inspector/ios/WKInspectorNodeSearchGestureRecognizer.mm UIProcess/Inspector/mac/RemoteWebInspectorUIProxyMac.mm +UIProcess/Inspector/mac/ScreencastEncoderMac.mm UIProcess/Inspector/mac/WebInspectorUIProxyMac.mm UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm UIProcess/Inspector/mac/WKInspectorViewController.mm diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt index 3c8d209cba714f7df7c1e78d951886692ca58b09..2d893bdc430f9e81a3369a9470d21134aa63c9a1 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -122,6 +122,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 @@ -252,6 +253,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp UIProcess/glib/DisplayVBlankMonitorDRM.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 @@ -270,6 +272,7 @@ UIProcess/gtk/DisplayX11.cpp @no-unify UIProcess/gtk/DisplayWayland.cpp @no-unify UIProcess/gtk/WebDateTimePickerGtk.cpp UIProcess/gtk/HardwareAccelerationManager.cpp +UIProcess/gtk/InspectorTargetProxyGtk.cpp UIProcess/gtk/KeyBindingTranslator.cpp UIProcess/gtk/PointerLockManager.cpp @no-unify UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify @@ -283,6 +286,8 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp UIProcess/gtk/WebColorPickerGtk.cpp UIProcess/gtk/WebContextMenuProxyGtk.cpp UIProcess/gtk/WebDataListSuggestionsDropdownGtk.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 42931a643d8ff85469b5e162a42e9a09a8bdca3f..f962949675b8de7b79e6d56bb8bb3f342b39dfe8 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -124,6 +124,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 @@ -157,6 +158,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 @@ -221,6 +223,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp UIProcess/glib/DisplayVBlankMonitorDRM.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 @@ -254,8 +257,14 @@ UIProcess/linux/MemoryPressureMonitor.cpp UIProcess/soup/WebProcessPoolSoup.cpp UIProcess/wpe/AcceleratedBackingStoreDMABuf.cpp +UIProcess/wpe/InspectorTargetProxyWPE.cpp UIProcess/wpe/ScreenManagerWPE.cpp UIProcess/wpe/SystemSettingsManagerProxyWPE.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/WebPreferencesWPE.cpp @@ -282,6 +291,8 @@ WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp +WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp + WebProcess/WebCoreSupport/wpe/WebEditorClientWPE.cpp WebProcess/WebPage/AcceleratedSurface.cpp diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp index a9d9e1ecd35d4f3b55fa27ff913d054513d423a6..d7f083485598a5b458c09c278a7c0181272d0e93 100644 --- a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp @@ -275,6 +275,11 @@ WebPageProxy* PageConfiguration::relatedPage() const return m_data.relatedPage.get(); } +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 ceb054aec4899fa74d160c08e1009dba052488e7..e4c817a32510d006b95d0039d9dc763351831978 100644 --- a/Source/WebKit/UIProcess/API/APIPageConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.h @@ -160,6 +160,10 @@ public: WebKit::WebPageProxy* relatedPage() const; void setRelatedPage(WeakPtr&& relatedPage) { m_data.relatedPage = WTFMove(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 = WTFMove(openerPageForInspector); } + WebKit::WebPageProxy* pageToCloneSessionStorageFrom() const; void setPageToCloneSessionStorageFrom(WeakPtr&&); @@ -518,6 +522,7 @@ private: #endif RefPtr pageGroup; WeakPtr relatedPage; + WeakPtr openerPageForInspector; std::optional openerInfo; WebCore::Site openedSite; WTF::String openedMainFrameName; diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp index e256b905bf9727aa7c8a48012237a6a6bc9acdbc..4e855c441af6f235f0fd8dfdd57b9bd6e4646492 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp @@ -52,6 +52,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 af4944e5a5d373bc51995b50d1ea7c70f64ef1b3..403cfdeda26db2b648e32aa0e5f3ef6e076634f6 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h @@ -96,6 +96,16 @@ public: 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 = WTFMove(languages); } + /* end playwright revert fb205fb */ + bool alwaysRunsAtBackgroundPriority() const { return m_alwaysRunsAtBackgroundPriority; } void setAlwaysRunsAtBackgroundPriority(bool alwaysRunsAtBackgroundPriority) { m_alwaysRunsAtBackgroundPriority = alwaysRunsAtBackgroundPriority; } @@ -178,6 +188,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 4d3564df93fcad126ddd9b3ca851618976cd7571..826aad7a5675b4daf90d83d36a6f352751932f03 100644 --- a/Source/WebKit/UIProcess/API/APIUIClient.h +++ b/Source/WebKit/UIProcess/API/APIUIClient.h @@ -114,6 +114,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, Object*) { } diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.cpp b/Source/WebKit/UIProcess/API/C/WKInspector.cpp index 8ecba5bacfa39f9f5309a127e2c0aed527373a04..0873b91211c89b9cddab9ed74120c0b77e4c6aec 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) 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 55aeb95735a56d285d7faeb21e9cec6e4ce6762e..9ecc7e8b24a3550659e62e01e704ea0064a985aa 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp @@ -1935,6 +1935,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) @@ -1964,6 +1971,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 fc43c44a85a0fc6bf5f8c643bd120a16ce762914..ee86fd213d25682f9b6553ec7da99bc8a812212b 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); @@ -1365,6 +1366,7 @@ typedef struct WKPageUIClientV14 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; } WKPageUIClientV14; typedef struct WKPageUIClientV15 { @@ -1472,6 +1474,7 @@ typedef struct WKPageUIClientV15 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1583,6 +1586,7 @@ typedef struct WKPageUIClientV16 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1697,6 +1701,7 @@ typedef struct WKPageUIClientV17 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1811,6 +1816,7 @@ typedef struct WKPageUIClientV18 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1927,6 +1933,7 @@ typedef struct WKPageUIClientV19 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm index 3298711f75bd5be68290738a21de99c927e2d925..6943df0b1f4ee684db0b52f336b5d7f8922c2707 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm @@ -712,6 +712,16 @@ - (void)_setMediaCaptureRequiresSecureConnection:(BOOL)requiresSecureConnection _preferences->setMediaCaptureRequiresSecureConnection(requiresSecureConnection); } +- (BOOL)_alternateWebMPlayerEnabled +{ + return _preferences->alternateWebMPlayerEnabled(); +} + +- (void)_setAlternateWebMPlayerEnabled:(BOOL)enabled +{ + _preferences->setAlternateWebMPlayerEnabled(enabled); +} + - (double)_inactiveMediaCaptureStreamRepromptIntervalInMinutes { return _preferences->inactiveMediaCaptureStreamRepromptIntervalInMinutes(); diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h index 41525c8980f698aa4326e7d4d232311cee2c43d5..1f1745431c6cc7af66b47dd5d015c52389626e6f 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h @@ -119,6 +119,7 @@ typedef NS_ENUM(NSInteger, _WKPitchCorrectionAlgorithm) { @property (nonatomic, setter=_setMockCaptureDevicesEnabled:) BOOL _mockCaptureDevicesEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0)); @property (nonatomic, setter=_setMockCaptureDevicesPromptEnabled:) BOOL _mockCaptureDevicesPromptEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3)); @property (nonatomic, setter=_setMediaCaptureRequiresSecureConnection:) BOOL _mediaCaptureRequiresSecureConnection WK_API_AVAILABLE(macos(10.13), ios(11.0)); +@property (nonatomic, setter=_setAlternateWebMPlayerEnabled:) BOOL _alternateWebMPlayerEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA)); @property (nonatomic, setter=_setEnumeratingAllNetworkInterfacesEnabled:) BOOL _enumeratingAllNetworkInterfacesEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0)); @property (nonatomic, setter=_setICECandidateFilteringEnabled:) BOOL _iceCandidateFilteringEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3)); @property (nonatomic, setter=_setInactiveMediaCaptureStreamRepromptIntervalInMinutes:) double _inactiveMediaCaptureStreamRepromptIntervalInMinutes WK_API_AVAILABLE(macos(10.13.4), ios(11.3)); diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h index 5f4e98c6ab6bb3cce607b96600cac66c70753224..1c2af77331d0da8d9ba232ba508b96e4f7276fe8 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h @@ -149,6 +149,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 930357ac3469195e9f33d5ffce92777018bb0b13..f62555ec562f8416976d31692e8fb1751a04d458 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h @@ -138,6 +138,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) #endif #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 5b6b451a4ab86b3c280c107e5f7bec822155ccde..99eeb8633ab25d8f4f174440e328ba5287e3a2b8 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm @@ -55,6 +55,7 @@ #import "_WKWebPushActionInternal.h" #import "_WKWebsiteDataStoreConfigurationInternal.h" #import "_WKWebsiteDataStoreDelegate.h" +#import #import #import #import @@ -523,6 +524,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..5fabe06a3289689246c36dfd96eb9900a48b2b0f --- /dev/null +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h @@ -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. + */ + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class WKWebView; + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserContext : NSObject +@property (nonatomic, strong) WKWebsiteDataStore *dataStore; +@property (nonatomic, strong) WKProcessPool *processPool; +@end + +@protocol _WKBrowserInspectorDelegate +- (WKWebView *)createNewPage:(uint64_t)sessionID; +- (_WKBrowserContext *)createBrowserContext:(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 426c7cbc897e22fd2e962dd3744959975d6ae6a0..f7a52359d7d42f970ef424b6c702b0ec1121a902 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h @@ -67,6 +67,7 @@ WK_CLASS_AVAILABLE(macos(10.10), ios(8.0)) @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 7ccfd9a46cd024c8f6644594b9d0cde8ae7e60db..921ec683dce77583f24d27a0b1b6f478242dfb42 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm @@ -241,6 +241,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 d139d35f09a999e2c85f48799a399d791d421ffd..f79c073291c6071c566220a40f7dd4bbc57192a1 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..575245fc1f279a75f7e74c26652cf772a2fc95b7 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp @@ -0,0 +1,158 @@ +/* + * 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 "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)); +} 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/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp index 1080e5d6a44b4d7ec649913c39af89aa702d2ee4..2ef7037a1778982275f4b1a5190a089295c8e59c 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp @@ -101,6 +101,10 @@ private: page.makeViewBlankIfUnpaintedSinceLastLoadCommit(); webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTFMove(completionHandler)); } + void handleJavaScriptDialog(WebPageProxy&, bool accept, const String& value) final + { + webkitWebViewHandleJavaScriptDialog(m_webView, accept, value); + } bool canRunBeforeUnloadConfirmPanel() const final { return true; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 5479cf466e1ba77ede37ff980e78bee85bbb094c..224c04a4bd9de6ad5661b15071c1267a57430547 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -423,10 +423,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 df1381b577be94114401e1faaf1979183d82614f..7739fac45b41e07d39a6ac1568641b44f67d5f56 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -39,6 +39,7 @@ #include "WebContextMenuItem.h" #include "WebContextMenuItemData.h" #include "WebFrameProxy.h" +#include "WebPageInspectorController.h" #include "WebKitAuthenticationRequestPrivate.h" #include "WebKitBackForwardListPrivate.h" #include "WebKitContextMenuClient.h" @@ -152,6 +153,7 @@ enum { CLOSE, SCRIPT_DIALOG, + SCRIPT_DIALOG_HANDLED, DECIDE_POLICY, PERMISSION_REQUEST, @@ -520,6 +522,16 @@ 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(WTFMove(surface)); +#elif USE(CAIRO) + if (RefPtr surface = adoptRef(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get()))) + getPage(m_webView).inspectorController().didPaint(surface.get()); +#endif + { SetForScope inFrameDisplayedGuard(m_webView->priv->inFrameDisplayed, true); for (const auto& callback : m_webView->priv->frameDisplayedCallbacks) { @@ -536,6 +548,18 @@ void WebKitWebViewClient::frameDisplayed(WKWPE::View&) } } +#if USE(SKIA) +sk_sp WebKitWebViewClient::takeViewScreenshot() +{ + return sk_sp(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get())); +} +#elif USE(CAIRO) +cairo_surface_t* WebKitWebViewClient::takeViewScreenshot() +{ + return webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get()); +} +#endif + void WebKitWebViewClient::willStartLoad(WKWPE::View&) { webkitWebViewWillStartLoad(m_webView); @@ -622,7 +646,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; @@ -945,6 +969,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, WTFMove(configuration)); webkitWebContextWebViewCreated(priv->context.get(), webView); @@ -1984,6 +2012,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 @@ -2769,6 +2806,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 bf5b4c2bcca722e4d008f12194344c29c0db8824..ee6ee6b476ac28dee3a5983d03ba89ad0c9eb9ff 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h @@ -64,6 +64,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 763cd55f7abca011ac8bc4fef7f233bf52854cda..bd43917b274bf19ff9f3d96b7e80e20710372cba 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 986edbe2d0b6ff2ed5717a14a71f26c973604f0c..c688cc026456686a54916857ba0396702ebf4a1e 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp @@ -270,6 +270,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; @@ -362,9 +364,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), WTFMove(clipRect)); + return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget), WTFMove(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 bd11269e156a92ce0e44cab3da4e4adde5142f64..1761d7541f226232b16ba8da3a6d609280037389 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(const 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..45221096280941d747ef3f46749b1466b2d70090 --- /dev/null +++ b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h @@ -0,0 +1,81 @@ +/* + * 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); + +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 2add5ab84105ad5e79635524b385fb5cb1de1a1b..0585e8474fc8cf42db262be75b514ea68fd5274b 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -2873,6 +2873,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); @@ -2929,12 +2934,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 3b8ca9470bab69dc26313111a79f954b10b30bf4..5c056dd6734f42d24bc168b4f5ba436584b3f7a8 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 "InputMethodState.h" #include "RendererBufferFormat.h" @@ -104,7 +105,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*); @@ -145,3 +146,5 @@ void webkitWebViewBaseSetPlugID(WebKitWebViewBase*, const String&); #endif WebKit::RendererBufferFormat webkitWebViewBaseGetRendererBufferFormat(WebKitWebViewBase*); + +WebKit::AcceleratedBackingStore* webkitWebViewBaseGetAcceleratedBackingStore(WebKitWebViewBase*); diff --git a/Source/WebKit/UIProcess/API/wpe/APIViewClient.h b/Source/WebKit/UIProcess/API/wpe/APIViewClient.h index 7636ad733e7be66a74f8fede966b0acb905a5842..cf54287353d1e529c6765e3caf8d283abe1e3472 100644 --- a/Source/WebKit/UIProcess/API/wpe/APIViewClient.h +++ b/Source/WebKit/UIProcess/API/wpe/APIViewClient.h @@ -26,6 +26,12 @@ #pragma once #include "UserMessage.h" +#if USE(CAIRO) +#include +#endif +#if USE(SKIA) +#include +#endif #include #include @@ -50,6 +56,13 @@ public: virtual bool isGLibBasedAPI() { return false; } virtual void frameDisplayed(WKWPE::View&) { } +// Playwright begin +#if USE(CAIRO) + virtual cairo_surface_t* takeViewScreenshot() { return nullptr; } +#elif 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 aec5bdaa6d2ceea13ad61e3996fd69f9f6a2dc55..ca51881ce7783979f9d36035093b571db93a9253 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp @@ -35,9 +35,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 @@ -55,6 +58,12 @@ #include #endif +#if USE(SKIA) +#include +#include +#include +#endif + namespace WebKit { WTF_MAKE_TZONE_ALLOCATED_IMPL(PageClientImpl); @@ -299,14 +308,14 @@ Ref PageClientImpl::createContextMenuProxy(WebPageProxy& pa } #endif -RefPtr PageClientImpl::createColorPicker(WebPageProxy&, const WebCore::Color& intialColor, const WebCore::IntRect&, ColorControlSupportsAlpha supportsAlpha, Vector&&) +RefPtr PageClientImpl::createColorPicker(WebPageProxy& page, const WebCore::Color& intialColor, const WebCore::IntRect& rect, ColorControlSupportsAlpha supportsAlpha, Vector&&) { - return nullptr; + return WebColorPickerWPE::create(page, intialColor, rect); } -RefPtr PageClientImpl::createDataListSuggestionsDropdown(WebPageProxy&) +RefPtr PageClientImpl::createDataListSuggestionsDropdown(WebKit::WebPageProxy& page) { - return nullptr; + return WebDataListSuggestionsDropdownWPE::create(page); } RefPtr PageClientImpl::createDateTimePicker(WebPageProxy& page) @@ -523,6 +532,64 @@ void PageClientImpl::selectionDidChange() m_view.selectionDidChange(); } +#if USE(SKIA) +sk_sp PageClientImpl::takeViewSnapshot(std::optional&& clipRect, bool nominalResolution) +{ + sk_sp fullScreenshot = m_view.client().takeViewScreenshot(); + float deviceScale = m_view.page().deviceScaleFactor(); + if (!clipRect && (!nominalResolution || deviceScale == 1)) + return fullScreenshot; + + WebCore::IntSize size = clipRect ? clipRect->size() : m_view.page().viewSize(); + if (!nominalResolution) { + size.scale(deviceScale); + if (clipRect) + clipRect->scale(deviceScale); + } + + 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 bitmap.asImage(); +} +#elif USE(CAIRO) +RefPtr PageClientImpl::takeViewSnapshot(std::optional&& clipRect, bool nominalResolution) +{ + RefPtr fullScreenshot = adoptRef(m_view.client().takeViewScreenshot()); + float deviceScale = m_view.page().deviceScaleFactor(); + if (!clipRect && (!nominalResolution || deviceScale == 1)) + return fullScreenshot; + + WebCore::IntSize size = clipRect ? clipRect->size() : m_view.page().viewSize(); + if (!nominalResolution) { + size.scale(deviceScale); + if (clipRect) + clipRect->scale(deviceScale); + } + RefPtr surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_RGB24, size.width(), size.height())); + RefPtr cr = adoptRef(cairo_create(surface.get())); + if (clipRect) { + cairo_translate(cr.get(), -clipRect->x(), -clipRect->y()); + cairo_rectangle(cr.get(), clipRect->x(), clipRect->y(), clipRect->width(), clipRect->height()); + cairo_clip(cr.get()); + } + if (nominalResolution) + cairo_scale(cr.get(), 1/deviceScale, 1/deviceScale); + cairo_set_source_surface(cr.get(), fullScreenshot.get(), 0, 0); + cairo_paint(cr.get()); + return surface; +} +#endif + + WebKitWebResourceLoadManager* PageClientImpl::webResourceLoadManager() { return m_view.webResourceLoadManager(); @@ -533,4 +600,11 @@ void PageClientImpl::callAfterNextPresentationUpdate(CompletionHandler&& m_view.callAfterNextPresentationUpdate(WTFMove(callback)); } +#if ENABLE(DATE_AND_TIME_INPUT_TYPES) +RefPtr 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 c9b5db9dc3005f78212b295ecbf1eac95b24f2dd..c15b6879d6167ec8b4bbe4b1deeb12eb38fe2e10 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h @@ -181,9 +181,17 @@ private: void didChangeWebPageID() const override; void selectionDidChange() override; - +#if USE(SKIA) + sk_sp takeViewSnapshot(std::optional&&, bool nominalResolution) override; +#elif USE(CAIRO) + RefPtr takeViewSnapshot(std::optional&&, bool nominalResolution) override; +#endif WebKitWebResourceLoadManager* webResourceLoadManager() override; +#if ENABLE(DATE_AND_TIME_INPUT_TYPES) + RefPtr createDateTimePicker(WebPageProxy&) override; +#endif + WKWPE::View& m_view; #if ENABLE(FULLSCREEN_API) std::unique_ptr m_fullscreenClientForTesting; diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..273c5105cdf1638955cea01128c9bbab3e64436c --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h @@ -0,0 +1,81 @@ +/* + * 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); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp index 763bda5b29304f7ed7133c0a8158e6c8b94c5ea1..8ed962e8c1af62b9b73a68348d0d88765429861d 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp @@ -54,6 +54,7 @@ struct _WebKitWebViewBackend { struct wpe_view_backend* backend; GDestroyNotify notifyCallback; gpointer notifyCallbackData; + take_screenshot_callback screenshotCallback; int referenceCount { 1 }; }; @@ -116,6 +117,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 { template <> WebKitWebViewBackend* refGPtr(WebKitWebViewBackend* ptr) diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h index 16dcc1f69c38cd8ad630bc49d6d69feaa3aa811e..efa3814a8e896e02b955dea0be70bdc5828e3d82 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h @@ -28,6 +28,15 @@ #include #include +#if defined(USE_CAIRO) && USE_CAIRO +#include +using PlatformImage = cairo_surface_t*; +#endif +#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 +53,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 e4b92ace1531090ae38a7aec3d3d4febf19aee84..b66b573f9148c39c5ce2738add6cd01a9a352be8 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h @@ -31,3 +31,5 @@ template <> void derefGPtr(WebKitWebViewBackend* ptr); } void webkitWebViewBackendUnref(WebKitWebViewBackend*); + +PlatformImage webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend*); diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h index 2f1182cb91a00353eace0b71612df096391c2450..d71d7fc724b046fab41285bb8f390cb6af6520ca 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h @@ -51,6 +51,13 @@ private: bool isGLibBasedAPI() override { return true; } void frameDisplayed(WKWPE::View&) override; +// Playwright begin +#if USE(CAIRO) + cairo_surface_t* takeViewScreenshot() override; +#elif USE(SKIA) + sk_sp takeViewScreenshot() override; +#endif +// Playwright end void willStartLoad(WKWPE::View&) override; void didChangePageID(WKWPE::View&) override; void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler&&) override; diff --git a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h index 6ae7054c30026bbaca91936c46ffff0760039d5a..5e97a1247dc43118c901b548f8dafa377e3f98ae 100644 --- a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h +++ b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h @@ -285,6 +285,9 @@ public: void didDestroyFrame(WebCore::FrameIdentifier); + static std::optional platformGetBase64EncodedPNGData(const ViewSnapshot&); + +private: RefPtr webPageProxyForHandle(const String&); String handleForWebPageProxy(const WebPageProxy&); @@ -336,7 +339,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 a4d1f15cd80b95ec8c82ac07cac3b8dfdae5916c..5182ffa031fd7278ea3bce5bb56e0a648f9223e2 100644 --- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp +++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp @@ -172,7 +172,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 1bca45f83bccfd8f917fc8a49b39414d9a8b6548..bcf8c5e5acb0652d04201aa8a8a840537e17e66f 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 945c62704e0b25f04e9ee4be88b21f88aeda8bd9..ff9a8ee47e2669260743ae2174801b1cc3c4c413 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) || USE(CAIRO) + 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/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 505b934da3a86e218d11e2db1406b0a0a4c7ec36..2e800a8f78fb6209de7f2950fbf84ae062633a4d 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h @@ -103,6 +103,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; @@ -221,6 +222,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 54b225795a14877140396f612330d5212bbf5fea..9c006877aa2a9d4804c71ad34766750fe74539b9 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm @@ -134,6 +134,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:)]; @@ -494,6 +495,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 1f2f95479d04ad49499db7dae7954c1c54db6d3e..4aee549a4b5a371b35ce012bcdc258147ddeba8c 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm @@ -42,7 +42,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 "RemoteLayerTreeTransaction.h" @@ -336,11 +338,86 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() void WebPageProxy::startDrag(const DragItem& dragItem, ShareableBitmap::Handle&& dragImageHandle) { + if (m_interceptDrags) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName: m_overrideDragPasteboardName.createNSString().get()]; + + m_dragSelectionData = String([pasteboard name]); + if (auto replyID = grantAccessToCurrentPasteboardData(String([pasteboard name]), [] () { })) + websiteDataStore().protectedNetworkProcess()->connection().waitForAsyncReplyAndDispatchImmediately(*replyID, 100_ms); + m_dragSourceOperationMask = WebCore::anyDragOperation(); + + if (auto& info = dragItem.promisedAttachmentInfo) { + auto attachment = attachmentForIdentifier(info.attachmentIdentifier); + if (!attachment) { + dragCancelled(); + return; + } + NSString *utiType = attachment->utiType().createNSString().get(); + if (!utiType.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, WTFMove(dragImageHandle)); } -#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 c20de41306158d48f4a761e93618acad0f2ae130..0bc1c2e90f4c80c9b506de3cfaf17ae06c173406 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm @@ -434,7 +434,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END auto screenProperties = WebCore::collectScreenProperties(); parameters.screenProperties = WTFMove(screenProperties); #if PLATFORM(MAC) - parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); + parameters.useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); #endif #if PLATFORM(VISION) @@ -833,8 +833,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:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp index 183a2dc44f4d2921e68a6ff5fd2fb0fb815753af..a17d0ed7d287694516305ba57a849ad8042e9287 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,8 +41,10 @@ #include #include #include +#include #if PLATFORM(GTK) +#include "WebKitWebViewBasePrivate.h" #include #endif @@ -49,6 +52,11 @@ #include #endif +#if PLATFORM(WIN) +#include +#include +#endif + namespace WebKit { using namespace WebCore; @@ -182,6 +190,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange(CompletionH sendWithAsyncReply(Messages::DrawingArea::SetDeviceScaleFactor(m_webPageProxy->deviceScaleFactor()), WTFMove(completionHandler)); } +void DrawingAreaProxyCoordinatedGraphics::waitForSizeUpdate(Function&& callback) +{ + m_callbacks.append(WTFMove(callback)); +} + void DrawingAreaProxyCoordinatedGraphics::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable) { #if !PLATFORM(WPE) @@ -243,6 +256,42 @@ void DrawingAreaProxyCoordinatedGraphics::updateAcceleratedCompositingMode(uint6 updateAcceleratedCompositingMode(layerTreeContext); } +#if PLATFORM(GTK) +void DrawingAreaProxyCoordinatedGraphics::captureFrame() +{ + RefPtr surface; + if (isInAcceleratedCompositingMode()) { + AcceleratedBackingStore* backingStore = webkitWebViewBaseGetAcceleratedBackingStore(WEBKIT_WEB_VIEW_BASE(protectedWebPageProxy()->viewWidget())); + if (!backingStore) + return; + + surface = backingStore->surface(); + } else if (m_backingStore) { + surface = m_backingStore->surface(); + } + + if (!surface) + return; + + protectedWebPageProxy()->inspectorController().didPaint(surface.get()); +} +#endif // PLATFORM(GTK) + +#if PLATFORM(WIN) +void DrawingAreaProxyCoordinatedGraphics::captureFrame() +{ + if (!m_backingStore) + return; + auto surface = m_backingStore->surface(); + if (!surface) + return; + auto image = surface->makeImageSnapshot(); + if (!image) + return; + protectedWebPageProxy()->inspectorController().didPaint(WTFMove(image)); +} +#endif // PLATFORM(WIN) + bool DrawingAreaProxyCoordinatedGraphics::alwaysUseCompositing() const { if (!m_webPageProxy) @@ -310,6 +359,12 @@ void DrawingAreaProxyCoordinatedGraphics::didUpdateGeometry() // we need to resend the new size here. if (m_lastSentSize != m_size) sendUpdateGeometry(); + else { + Vector> callbacks; + callbacks.swap(m_callbacks); + for (auto& cb : callbacks) + cb(*this); + } } #if !PLATFORM(WPE) diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h index 9c2bde0db0e4032a32e6ae02dc45af335df92f7a..3f3a58ee9b0f5c0ddad84f41cf3acd6199d81c37 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 { return m_layerTreeContext; } + void waitForSizeUpdate(Function&&); +#if !PLATFORM(WPE) + void captureFrame(); +#endif void dispatchAfterEnsuringDrawing(CompletionHandler&&); @@ -129,6 +134,7 @@ private: // The last size we sent to the web process. WebCore::IntSize m_lastSentSize; + Vector> m_callbacks; #if !PLATFORM(WPE) bool m_isBackingStoreDiscardable { true }; diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp index 248a3bc1d03be7bca3c4324b93f13b452d91cc42..1ebb98bea247b882335569560d9fe8678f5d4793 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) { - protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler)] (std::span resumeData) mutable { + auto* instrumentation = m_dataStore->downloadInstrumentation(); + protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTFMove(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); }); @@ -163,6 +171,33 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour suggestedFilename = m_suggestedFilename; 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()) { + destination = FileSystem::pathByAppendingComponent(m_dataStore->downloadPathForAutomation(), m_uuid); + if (auto handle = SandboxExtension::createHandle(destination, SandboxExtension::Type::ReadWrite)) + sandboxExtensionHandle = WTFMove(*handle); + } + m_client->decidePlaceholderPolicy(*this, [completionHandler = WTFMove(completionHandler), destination = WTFMove(destination), sandboxExtensionHandle = WTFMove(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 = WTFMove(*handle); +#endif + completionHandler(destination, WTFMove(sandboxExtensionHandle), AllowOverwrite::Yes, WebKit::UseDownloadPlaceholder::No, url, WTFMove(placeHolderSandboxExtensionHandle), bookmarkData.span(), activityTokenData.span()); + }); + return; + } + protectedClient()->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable { SandboxExtension::Handle sandboxExtensionHandle; if (!destination.isNull()) { @@ -227,6 +262,8 @@ void DownloadProxy::didFinish() protectedClient()->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()) @@ -241,6 +278,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span m_legacyResumeData = createData(resumeData); protectedClient()->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 9a92a8cde3b5d1da0fbbf5fe7c549cebb8a7f2f7..9ce201ca2d7aa002c7bd389f1fe03edfb306df5d 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h @@ -166,6 +166,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 e1f55b4a7fbc452ca1f2eb025b0c88ec9f4b845f..beb3c7a6619b554bb3186a0de917f497ac0f47f8 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.h +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h @@ -94,6 +94,7 @@ public: const WebCore::IntSize& size() const { 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/CairoJpegEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d20e2aa36ba0f7996c20a6a02792c7f151bbed5 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.cpp @@ -0,0 +1,246 @@ +/* Copyright 2018 Bernhard R. Fischer, 4096R/8E24F29D + * + * This file is part of Cairo_JPG. + * + * Cairo_JPG is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cairo_JPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cairo_JPG. If not, see . + */ + +/*! \file cairo_jpg.c + * This file contains two functions for reading and writing JPEG files from + * and to Cairo image surfaces. It uses the functions from the libjpeg. + * Most of the code is directly derived from the online example at + * http://libjpeg-turbo.virtualgl.org/Documentation/Documentation + * + * All prototypes are defined in cairo_jpg.h All functions and their parameters + * and return values are described below directly at the functions. You may + * also have a look at the preprocessor macros defined below. + * + * To compile this code you need to have installed the packages libcairo2-dev + * and libjpeg-dev. Compile with the following to create an object file to link + * with your code: + * gcc -std=c99 -Wall -c `pkg-config cairo libjpeg --cflags --libs` cairo_jpg.c + * Use the following command to include the main() function and create an + * executable for testing of this code: + * gcc -std=c99 -Wall -o cairo_jpg -DCAIRO_JPEG_MAIN `pkg-config cairo libjpeg --cflags --libs` cairo_jpg.c + * + * @author Bernhard R. Fischer, 4096R/8E24F29D bf@abenteuerland.at + * @version 2020/01/18 + * @license LGPL3. + */ + +#include "config.h" + +#if USE(CAIRO) || PLATFORM(GTK) + +#include "CairoJpegEncoder.h" + +#include +#include +#include +#include +#include +#include +extern "C" { +#include "jpeglib.h" +} + +/*! Macro to activate main() function. This is only used for testing. Comment + * it out (#undef) if you link this file to your own program. + */ +//#define CAIRO_JPEG_MAIN +// +/*! Define this to use an alternate implementation of + * cairo_image_surface_create_from_jpeg() which fstat(3)s the file before + * reading (see below). For huge files this /may/ be slightly faster. + */ +#undef CAIRO_JPEG_USE_FSTAT + +/*! This is the read block size for the stream reader + * cairo_image_surface_create_from_jpeg_stream(). + */ +#ifdef USE_CAIRO_READ_FUNC_LEN_T +#define CAIRO_JPEG_IO_BLOCK_SIZE 4096 +#else +/*! Block size has to be one if cairo_read_func_t is in use because of the lack + * to detect EOF (truncated reads). + */ +#define CAIRO_JPEG_IO_BLOCK_SIZE 1 +/*! In case of original cairo_read_func_t is used fstat() should be used for + * performance reasons (see CAIRO_JPEG_USE_FSTAT above). + */ +#define CAIRO_JPEG_USE_FSTAT +#endif + +/*! Define this to test jpeg creation with non-image surfaces. This is only for + * testing and is to be used together with CAIRO_JPEG_MAIN. + */ +#undef CAIRO_JPEG_TEST_SIMILAR +#if defined(CAIRO_JPEG_TEST_SIMILAR) && defined(CAIRO_JPEG_MAIN) +#include +#endif + + +#ifndef LIBJPEG_TURBO_VERSION +/*! This function makes a covnersion for "odd" pixel sizes which typically is a + * conversion from a 3-byte to a 4-byte (or more) pixel size or vice versa. + * The conversion is done from the source buffer src to the destination buffer + * dst. The caller MUST ensure that src and dst have the correct memory size. + * This is dw * num for dst and sw * num for src. src and dst may point to the + * same memory address. + * @param dst Pointer to destination buffer. + * @param dw Pixel width (in bytes) of pixels in destination buffer, dw >= 3. + * @param src Pointer to source buffer. + * @param sw Pixel width (in bytes) of pixels in source buffer, sw >= 3. + * @param num Number of pixels to convert, num >= 1; + */ +static void pix_conv(unsigned char *dst, int dw, const unsigned char *src, int sw, int num) +{ + int si, di; + + // safety check + if (dw < 3 || sw < 3 || dst == NULL || src == NULL) + return; + + num--; + for (si = num * sw, di = num * dw; si >= 0; si -= sw, di -= dw) + { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + dst[di + 2] = src[si ]; + dst[di + 1] = src[si + 1]; + dst[di + 0] = src[si + 2]; +#else + // FIXME: This is untested, it may be wrong. + dst[di - 3] = src[si - 3]; + dst[di - 2] = src[si - 2]; + dst[di - 1] = src[si - 1]; +#endif + } +} +#endif + + +/*! This function creates a JPEG file in memory from a Cairo image surface. + * @param sfc Pointer to a Cairo surface. It should be an image surface of + * either CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_RGB24. Other formats are + * converted to CAIRO_FORMAT_RGB24 before compression. + * Please note that this may give unexpected results because JPEG does not + * support transparency. Thus, default background color is used to replace + * transparent regions. The default background color is black if not specified + * explicitly. Thus converting e.g. PDF surfaces without having any specific + * background color set will apear with black background and not white as you + * might expect. In such cases it is suggested to manually convert the surface + * to RGB24 before calling this function. + * @param data Pointer to a memory pointer. This parameter receives a pointer + * to the memory area where the final JPEG data is found in memory. This + * function reserves the memory properly and it has to be freed by the caller + * with free(3). + * @param len Pointer to a variable of type size_t which will receive the final + * lenght of the memory buffer. + * @param quality Compression quality, 0-100. + * @return On success the function returns CAIRO_STATUS_SUCCESS. In case of + * error CAIRO_STATUS_INVALID_FORMAT is returned. + */ +cairo_status_t cairo_image_surface_write_to_jpeg_mem(cairo_surface_t *sfc, unsigned char **data, size_t *len, int quality) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW row_pointer[1]; + cairo_surface_t *other = NULL; + + // check valid input format (must be IMAGE_SURFACE && (ARGB32 || RGB24)) + if (cairo_surface_get_type(sfc) != CAIRO_SURFACE_TYPE_IMAGE || + (cairo_image_surface_get_format(sfc) != CAIRO_FORMAT_ARGB32 && + cairo_image_surface_get_format(sfc) != CAIRO_FORMAT_RGB24)) + { + // create a similar surface with a proper format if supplied input format + // does not fulfill the requirements + double x1, y1, x2, y2; + other = sfc; + cairo_t *ctx = cairo_create(other); + // get extents of original surface + cairo_clip_extents(ctx, &x1, &y1, &x2, &y2); + cairo_destroy(ctx); + + // create new image surface + sfc = cairo_surface_create_similar_image(other, CAIRO_FORMAT_RGB24, x2 - x1, y2 - y1); + if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_INVALID_FORMAT; + + // paint original surface to new surface + ctx = cairo_create(sfc); + cairo_set_source_surface(ctx, other, 0, 0); + cairo_paint(ctx); + cairo_destroy(ctx); + } + + // finish queued drawing operations + cairo_surface_flush(sfc); + + // init jpeg compression structures + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + // set compression parameters + unsigned long targetSize; + jpeg_mem_dest(&cinfo, data, &targetSize); + + cinfo.image_width = cairo_image_surface_get_width(sfc); + cinfo.image_height = cairo_image_surface_get_height(sfc); +#ifdef LIBJPEG_TURBO_VERSION +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + //cinfo.in_color_space = JCS_EXT_BGRX; + cinfo.in_color_space = cairo_image_surface_get_format(sfc) == CAIRO_FORMAT_ARGB32 ? JCS_EXT_BGRA : JCS_EXT_BGRX; +#else + //cinfo.in_color_space = JCS_EXT_XRGB; + cinfo.in_color_space = cairo_image_surface_get_format(sfc) == CAIRO_FORMAT_ARGB32 ? JCS_EXT_ARGB : JCS_EXT_XRGB; +#endif + cinfo.input_components = 4; +#else + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; +#endif + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + + // start compressor + jpeg_start_compress(&cinfo, TRUE); + + // loop over all lines and compress + while (cinfo.next_scanline < cinfo.image_height) + { +#ifdef LIBJPEG_TURBO_VERSION + row_pointer[0] = cairo_image_surface_get_data(sfc) + (cinfo.next_scanline + * cairo_image_surface_get_stride(sfc)); +#else + unsigned char row_buf[3 * cinfo.image_width]; + pix_conv(row_buf, 3, cairo_image_surface_get_data(sfc) + + (cinfo.next_scanline * cairo_image_surface_get_stride(sfc)), 4, cinfo.image_width); + row_pointer[0] = row_buf; +#endif + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + // finalize and close everything + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + // destroy temporary image surface (if available) + if (other != NULL) + cairo_surface_destroy(sfc); + + *len = targetSize; + return CAIRO_STATUS_SUCCESS; +} + +#endif diff --git a/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.h new file mode 100644 index 0000000000000000000000000000000000000000..4ec8b96bbbddf8a7b042f53a8068754a384fc7ad --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) Microsoft. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +cairo_status_t cairo_image_surface_write_to_jpeg_mem(cairo_surface_t *sfc, unsigned char **data, size_t *len, int quality); diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..55a0cf8cd5be1cdd33165fe904a8f0ffd815f6d4 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp @@ -0,0 +1,392 @@ +/* + * 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 "ScreencastEncoder.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 USE(CAIRO) || PLATFORM(GTK) +#include "CairoJpegEncoder.h" +#include "DrawingAreaProxyCoordinatedGraphics.h" +#include "DrawingAreaProxy.h" +#endif + +#if PLATFORM(MAC) +#include +#endif + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +namespace WebKit { + +const int kMaxFramesInFlight = 1; + +using namespace Inspector; + +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(FrontendRouter*, BackendDispatcher*) +{ +} + +void InspectorScreencastAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ + if (!m_encoder) + return; + + // The agent may be destroyed when the callback is invoked. + m_encoder->finish([sessionID = m_page.websiteDataStore().sessionID(), screencastID = WTFMove(m_currentScreencastID)] { + if (WebPageInspectorController::observer()) + WebPageInspectorController::observer()->didFinishScreencast(sessionID, screencastID); + }); + + m_encoder = nullptr; +} + +#if USE(SKIA) && !PLATFORM(GTK) +void InspectorScreencastAgent::didPaint(sk_sp&& surface) +{ + sk_sp image(surface); +#if PLATFORM(WPE) || PLATFORM(WIN) + // 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; + } +#else + WebCore::IntSize displaySize = m_page.drawingArea()->size(); +#endif + // Do not WTFMove image here as it is used below + if (m_encoder) + m_encoder->encodeFrame(sk_sp(image), displaySize); + if (m_screencast) { + { + 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::CryptoDigest::create(PAL::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; + } + + if (m_screencastFramesInFlight > kMaxFramesInFlight) + return; + // 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, displaySize.width(), displaySize.height()); + } +} +#endif + +#if USE(CAIRO) || PLATFORM(GTK) +void InspectorScreencastAgent::didPaint(cairo_surface_t* surface) +{ +#if PLATFORM(WPE) + // Get actual image size (in device pixels). + WebCore::IntSize displaySize(cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface)); + + WebCore::IntSize drawingAreaSize = m_page.drawingArea()->size(); + drawingAreaSize.scale(m_page.deviceScaleFactor()); + if (drawingAreaSize != displaySize) { + return; + } + +#else + WebCore::IntSize displaySize = m_page.drawingArea()->size(); +#endif + if (m_encoder) + m_encoder->encodeFrame(surface, displaySize); + if (m_screencast) { + + { + // Do not send the same frame over and over. + unsigned char *data = cairo_image_surface_get_data(surface); + int stride = cairo_image_surface_get_stride(surface); + int height = cairo_image_surface_get_height(surface); + auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1); + cryptoDigest->addBytes(std::span(data, stride * height)); + auto digest = cryptoDigest->computeHash(); + if (m_lastFrameDigest == digest) + return; + m_lastFrameDigest = digest; + } + + if (m_screencastFramesInFlight > kMaxFramesInFlight) + return; + // Scale image to fit width / height + double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height()); + RefPtr scaledSurface; + if (scale < 1) { + WebCore::IntSize scaledSize = displaySize; + scaledSize.scale(scale); + cairo_matrix_t transform; + cairo_matrix_init_scale(&transform, scale, scale); + scaledSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, scaledSize.width(), scaledSize.height())); + RefPtr cr = adoptRef(cairo_create(scaledSurface.get())); + cairo_transform(cr.get(), &transform); + cairo_set_source_surface(cr.get(), surface, 0, 0); + cairo_paint(cr.get()); + surface = scaledSurface.get(); + } + unsigned char *data = nullptr; + size_t len = 0; + cairo_image_surface_write_to_jpeg_mem(surface, &data, &len, m_screencastQuality); + String result = base64EncodeToString(std::span(data, len)); + ++m_screencastFramesInFlight; + m_frontendDispatcher->screencastFrame(result, displaySize.width(), displaySize.height()); + } +} +#endif + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::startVideo(const String& file, int width, int height, int toolbarHeight) +{ + if (m_encoder) + return makeUnexpected("Already recording"_s); + + if (width < 10 || width > 10000 || height < 10 || height > 10000) + return makeUnexpected("Invalid size"_s); + + String errorString; + m_encoder = ScreencastEncoder::create(errorString, file, WebCore::IntSize(width, height)); + if (!m_encoder) + return makeUnexpected(errorString); + + m_currentScreencastID = createVersion4UUIDString(); + +#if PLATFORM(MAC) + m_encoder->setOffsetTop(toolbarHeight); +#endif + + kickFramesStarted(); + return { { m_currentScreencastID } }; +} + +void InspectorScreencastAgent::stopVideo(Ref&& callback) +{ + if (!m_encoder) { + callback->sendFailure("Not recording"_s); + return; + } + + // The agent may be destroyed when the callback is invoked. + m_encoder->finish([sessionID = m_page.websiteDataStore().sessionID(), screencastID = WTFMove(m_currentScreencastID), callback = WTFMove(callback)] { + if (WebPageInspectorController::observer()) + WebPageInspectorController::observer()->didFinishScreencast(sessionID, screencastID); + callback->sendSuccess(); + }); + m_encoder = nullptr; + if (!m_screencast) + m_framesAreGoing = false; +} + +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_screencastFramesInFlight = 0; + ++m_screencastGeneration; + kickFramesStarted(); + return m_screencastGeneration; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::screencastFrameAck(int generation) +{ + if (m_screencastGeneration != generation) + return { }; + --m_screencastFramesInFlight; + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::stopScreencast() +{ + if (!m_screencast) + return makeUnexpected("Not screencasting"_s); + m_screencast = false; + if (!m_encoder) + m_framesAreGoing = false; + 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_encoder && !m_screencast) + return; + + RunLoop::main().dispatchAfter(Seconds(1.0 / ScreencastEncoder::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_encoder && !m_screencast) + return; + RetainPtr imageRef = m_page.pageClient()->takeSnapshotForAutomation(); + if (m_screencast && m_screencastFramesInFlight <= kMaxFramesInFlight) { + 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::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1); + cryptoDigest->addBytes(std::span(data.data(), data.size())); + auto digest = cryptoDigest->computeHash(); + if (m_lastFrameDigest != digest) { + String base64Data = base64EncodeToString(data); + ++m_screencastFramesInFlight; + m_frontendDispatcher->screencastFrame(base64Data, displaySize.width(), displaySize.height()); + m_lastFrameDigest = digest; + } + } + if (m_encoder) + m_encoder->encodeFrame(WTFMove(imageRef)); +} +#endif + +#if PLATFORM(GTK) || PLATFORM(WIN) +void InspectorScreencastAgent::encodeFrame() +{ + if (!m_encoder && !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..f53bb59c65a4ced0360e473fb9ed9a36d1179310 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h @@ -0,0 +1,109 @@ +/* + * 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 + +#if USE(CAIRO) || PLATFORM(GTK) +#include +#endif + +#include +#include +#include + +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 ScreencastEncoder; +class WebPageProxy; + +class InspectorScreencastAgent : public Inspector::InspectorAgentBase, public Inspector::ScreencastBackendDispatcherHandler, public CanMakeWeakPtr { + WTF_MAKE_NONCOPYABLE(InspectorScreencastAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorScreencastAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorScreencastAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + +#if USE(SKIA) && !PLATFORM(GTK) + void didPaint(sk_sp&& surface); +#endif +#if USE(CAIRO) || PLATFORM(GTK) + void didPaint(cairo_surface_t*); +#endif + + Inspector::Protocol::ErrorStringOr startVideo(const String& file, int width, int height, int toolbarHeight) override; + void stopVideo(Ref&&) override; + + 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; + RefPtr m_encoder; + 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; + String m_currentScreencastID; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bec42378013c93ee6bd37f62a1d6a1c68d167fa3 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2010, The WebM Project authors. All rights reserved. + * Copyright (c) 2013 The Chromium Authors. All rights reserved. + * 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 "ScreencastEncoder.h" + +#include "WebMFileWriter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if USE(SKIA) && !PLATFORM(GTK) +#include +#include +#include +#include +#endif + +#if USE(CAIRO) || PLATFORM(GTK) +#include +#endif + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN + +using namespace WebCore; + +namespace WebKit { + +namespace { + +struct VpxCodecDeleter { + void operator()(vpx_codec_ctx_t* codec) { + if (codec) { + vpx_codec_err_t ret = vpx_codec_destroy(codec); + if (ret != VPX_CODEC_OK) + fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(codec)); + } + } +}; + +using ScopedVpxCodec = std::unique_ptr; + +// Number of timebase unints per one frame. +constexpr int timeScale = 1000; + +// Defines the dimension of a macro block. This is used to compute the active +// map for the encoder. +const int kMacroBlockSize = 16; + +void createImage(unsigned int width, unsigned int height, + std::unique_ptr& out_image, + std::unique_ptr& out_image_buffer) { + std::unique_ptr image(new vpx_image_t()); + memset(image.get(), 0, sizeof(vpx_image_t)); + + // libvpx seems to require both to be assigned. + image->d_w = width; + image->w = width; + image->d_h = height; + image->h = height; + + // I420 + image->fmt = VPX_IMG_FMT_YV12; + image->x_chroma_shift = 1; + image->y_chroma_shift = 1; + + // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad + // the Y, U and V planes' strides to multiples of 16 bytes. + const int y_stride = ((image->w - 1) & ~15) + 16; + const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; + const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; + + // libvpx accesses the source image in macro blocks, and will over-read + // if the image is not padded out to the next macroblock: crbug.com/119633. + // Pad the Y, U and V planes' height out to compensate. + // Assuming macroblocks are 16x16, aligning the planes' strides above also + // macroblock aligned them. + static_assert(kMacroBlockSize == 16, "macroblock_size_not_16"); + const int y_rows = ((image->h - 1) & ~(kMacroBlockSize-1)) + kMacroBlockSize; + const int uv_rows = y_rows >> image->y_chroma_shift; + + // Allocate a YUV buffer large enough for the aligned data & padding. + const int buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows; + std::unique_ptr image_buffer(new uint8_t[buffer_size]); + + // Reset image value to 128 so we just need to fill in the y plane. + memset(image_buffer.get(), 128, buffer_size); + + // Fill in the information for |image_|. + unsigned char* uchar_buffer = + reinterpret_cast(image_buffer.get()); + image->planes[0] = uchar_buffer; + image->planes[1] = image->planes[0] + y_stride * y_rows; + image->planes[2] = image->planes[1] + uv_stride * uv_rows; + image->stride[0] = y_stride; + image->stride[1] = uv_stride; + image->stride[2] = uv_stride; + + out_image = std::move(image); + out_image_buffer = std::move(image_buffer); +} + +} // namespace + +class ScreencastEncoder::VPXFrame { + WTF_MAKE_NONCOPYABLE(VPXFrame); + WTF_MAKE_FAST_ALLOCATED; +public: +#if USE(SKIA) && !PLATFORM(GTK) + explicit VPXFrame(sk_sp&& surface) + : m_surface(WTFMove(surface)) + { } +#elif USE(CAIRO) || PLATFORM(GTK) + explicit VPXFrame(RefPtr&& surface) + : m_surface(WTFMove(surface)) + { } +#elif PLATFORM(MAC) + VPXFrame(RetainPtr windowImage, int offsetTop) + : m_windowImage(WTFMove(windowImage)) + , m_offsetTop(offsetTop) + { } +#endif + + void setDuration(Seconds duration) { m_duration = duration; } + Seconds duration() const { return m_duration; } + + void convertToVpxImage(vpx_image_t* image) + { +#if USE(SKIA) && !PLATFORM(GTK) + // Convert the updated region to YUV ready for encoding. + SkImageInfo info = SkImageInfo::Make(m_surface->width(), m_surface->height(), kN32_SkColorType, kPremul_SkAlphaType); + int argb_stride = info.minRowBytes(); + size_t bufferSize = info.computeByteSize(argb_stride); + UniqueArray buffer = makeUniqueArray(bufferSize); + uint8_t* argb_data = buffer.get(); + if (!m_surface->readPixels(info, argb_data, argb_stride, 0, 0)) + fprintf(stderr, "Read SkImage to ARGB buffer\n"); +#elif USE(CAIRO) || PLATFORM(GTK) + // Convert the updated region to YUV ready for encoding. + const uint8_t* argb_data = cairo_image_surface_get_data(m_surface.get()); + int argb_stride = cairo_image_surface_get_stride(m_surface.get()); +#elif PLATFORM(MAC) + int argb_stride = image->w * 4; + UniqueArray buffer = makeUniqueArray(argb_stride * image->h); + uint8_t* argb_data = buffer.get(); + ScreencastEncoder::imageToARGB(m_windowImage.get(), argb_data, image->w, image->h, m_offsetTop); +#endif + const int y_stride = image->stride[0]; + ASSERT(image->stride[1] == image->stride[2]); + const int uv_stride = image->stride[1]; + uint8_t* y_data = image->planes[0]; + uint8_t* u_data = image->planes[1]; + uint8_t* v_data = image->planes[2]; + + // TODO: redraw only damaged regions? + libyuv::ARGBToI420(argb_data, argb_stride, + y_data, y_stride, + u_data, uv_stride, + v_data, uv_stride, + image->w, image->h); + } + +private: +#if USE(SKIA) && !PLATFORM(GTK) + sk_sp m_surface; +#elif USE(CAIRO) || PLATFORM(GTK) + RefPtr m_surface; +#elif PLATFORM(MAC) + RetainPtr m_windowImage; + int m_offsetTop { 0 }; +#endif + Seconds m_duration; +}; + + +class ScreencastEncoder::VPXCodec { +public: + VPXCodec(ScopedVpxCodec codec, vpx_codec_enc_cfg_t cfg, FILE* file) + : m_encoderQueue(WorkQueue::create("Screencast encoder"_s)) + , m_codec(WTFMove(codec)) + , m_cfg(cfg) + , m_file(file) + , m_writer(new WebMFileWriter(file, &m_cfg)) + { + createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer); + } + + void encodeFrameAsync(std::unique_ptr&& frame) + { + m_encoderQueue->dispatch([this, frame = WTFMove(frame)] { + frame->convertToVpxImage(m_image.get()); + double frameCount = frame->duration().seconds() * fps; + // For long duration repeat frame at 1 fps to ensure last frame duration is short enough. + // TODO: figure out why simply passing duration doesn't work well. + for (;frameCount > 1.5; frameCount -= 1) { + encodeFrame(m_image.get(), timeScale); + } + encodeFrame(m_image.get(), std::max(1, frameCount * timeScale)); + }); + } + + void finishAsync(Function&& callback) + { + m_encoderQueue->dispatch([this, callback = WTFMove(callback)] { + finish(); + callback(); + }); + } + +private: + bool encodeFrame(vpx_image_t *img, int duration) + { + vpx_codec_iter_t iter = nullptr; + const vpx_codec_cx_pkt_t *pkt = nullptr; + int flags = 0; + const vpx_codec_err_t res = vpx_codec_encode(m_codec.get(), img, m_pts, duration, flags, VPX_DL_REALTIME); + if (res != VPX_CODEC_OK) { + fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(m_codec.get())); + return false; + } + + bool gotPkts = false; + while ((pkt = vpx_codec_get_cx_data(m_codec.get(), &iter)) != nullptr) { + gotPkts = true; + + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { + if (!m_writer->writeFrame(pkt)) { + fprintf(stderr, "Failed to write compressed frame\n"); + return false; + } + ++m_frameCount; + m_pts += pkt->data.frame.duration; + } + } + + return gotPkts; + } + + void finish() + { + // Flush encoder. + while (encodeFrame(nullptr, 1)) + ++m_frameCount; + + m_writer->finish(); + fclose(m_file); + } + + Ref m_encoderQueue; + ScopedVpxCodec m_codec; + vpx_codec_enc_cfg_t m_cfg; + FILE* m_file { nullptr }; + std::unique_ptr m_writer; + int m_frameCount { 0 }; + int64_t m_pts { 0 }; + std::unique_ptr m_imageBuffer; + std::unique_ptr m_image; +}; + +ScreencastEncoder::ScreencastEncoder(std::unique_ptr&& vpxCodec, IntSize size) + : m_vpxCodec(WTFMove(vpxCodec)) + , m_size(size) +{ + ASSERT(!size.isZero()); +} + +ScreencastEncoder::~ScreencastEncoder() +{ +} + +RefPtr ScreencastEncoder::create(String& errorString, const String& filePath, IntSize size) +{ + vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx(); + if (!codec_interface) { + errorString = "Codec not found."_s; + return nullptr; + } + + if (size.width() <= 0 || size.height() <= 0 || (size.width() % 2) != 0 || (size.height() % 2) != 0) { + errorString = makeString("Invalid frame size: "_s, size.width(), "x"_s, size.height()); + return nullptr; + } + + vpx_codec_enc_cfg_t cfg; + memset(&cfg, 0, sizeof(cfg)); + vpx_codec_err_t error = vpx_codec_enc_config_default(codec_interface, &cfg, 0); + if (error) { + errorString = makeString("Failed to get default codec config: "_s, unsafeSpan(vpx_codec_err_to_string(error))); + return nullptr; + } + + cfg.g_w = size.width(); + cfg.g_h = size.height(); + cfg.g_timebase.num = 1; + cfg.g_timebase.den = fps * timeScale; + cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; + + ScopedVpxCodec codec(new vpx_codec_ctx_t); + if (vpx_codec_enc_init(codec.get(), codec_interface, &cfg, 0)) { + errorString = makeString("Failed to initialize encoder: "_s, unsafeSpan(vpx_codec_error(codec.get()))); + return nullptr; + } + + FILE* file = fopen(filePath.utf8().data(), "wb"); + if (!file) { + errorString = makeString("Failed to open file '"_s, filePath, "' for writing: "_s, unsafeSpan(strerror(errno))); + return nullptr; + } + + std::unique_ptr vpxCodec(new VPXCodec(WTFMove(codec), cfg, file)); + return adoptRef(new ScreencastEncoder(WTFMove(vpxCodec), size)); +} + +void ScreencastEncoder::flushLastFrame() +{ + MonotonicTime now = MonotonicTime::now(); + if (m_lastFrameTimestamp) { + // If previous frame encoding failed for some rason leave the timestampt intact. + if (!m_lastFrame) + return; + + Seconds seconds = now - m_lastFrameTimestamp; + m_lastFrame->setDuration(seconds); + m_vpxCodec->encodeFrameAsync(WTFMove(m_lastFrame)); + } + m_lastFrameTimestamp = now; +} + +#if USE(SKIA) && !PLATFORM(GTK) +void ScreencastEncoder::encodeFrame(sk_sp&& image, IntSize size) +{ + flushLastFrame(); + // Note that in WPE drawing area size is updated asynchronously and may differ from acutal + // size of the surface. + if (size.isZero()) { + return; + } + SkBitmap surface; + surface.allocPixels(SkImageInfo::Make(m_size.width(), m_size.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType)); + SkCanvas canvas(surface); + SkMatrix transform; + if (size.width() > m_size.width() || size.height() > m_size.height()) { + // If no scale is specified shrink to fit the frame. + double scale = std::min(static_cast(m_size.width()) / size.width(), + static_cast(m_size.height()) / size.height()); + transform.setScale(scale, scale); + canvas.setMatrix(transform); + } + // Record top left part of the drawing area that fits into the frame. + canvas.drawImage(image, 0, 0); + m_lastFrame = makeUnique(surface.asImage()); +} +#elif USE(CAIRO) || PLATFORM(GTK) +void ScreencastEncoder::encodeFrame(cairo_surface_t* drawingAreaSurface, IntSize size) +{ + flushLastFrame(); + // Note that in WPE drawing area size is updated asynchronously and may differ from acutal + // size of the surface. + if (size.isZero()) { + return; + } + + RefPtr surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_size.width(), m_size.height())); + { + RefPtr cr = adoptRef(cairo_create(surface.get())); + + cairo_matrix_t transform; + if (size.width() > m_size.width() || size.height() > m_size.height()) { + // If no scale is specified shrink to fit the frame. + double scale = std::min(static_cast(m_size.width()) / size.width(), + static_cast(m_size.height()) / size.height()); + cairo_matrix_init_scale(&transform, scale, scale); + cairo_transform(cr.get(), &transform); + } + + // Record top left part of the drawing area that fits into the frame. + cairo_set_source_surface(cr.get(), drawingAreaSurface, 0, 0); + cairo_paint(cr.get()); + } + cairo_surface_flush(surface.get()); + + m_lastFrame = makeUnique(WTFMove(surface)); +} +#elif PLATFORM(MAC) +void ScreencastEncoder::encodeFrame(RetainPtr&& windowImage) +{ + flushLastFrame(); + + m_lastFrame = makeUnique(WTFMove(windowImage), m_offsetTop); +} +#endif + +void ScreencastEncoder::finish(Function&& callback) +{ + if (!m_vpxCodec) { + callback(); + return; + } + + flushLastFrame(); + m_vpxCodec->finishAsync([protectRef = Ref { *this }, callback = WTFMove(callback)] () mutable { + RunLoop::main().dispatch([callback = WTFMove(callback)] { + callback(); + }); + }); +} + + +} // namespace WebKit + +WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h new file mode 100644 index 0000000000000000000000000000000000000000..caf0474267c1bda6346f7b025b6646bb4f1b56d9 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h @@ -0,0 +1,82 @@ +/* + * 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(CAIRO) || PLATFORM(GTK) +#include +#endif + +namespace WebKit { + +class WebPageProxy; + +class ScreencastEncoder : public ThreadSafeRefCounted { + WTF_MAKE_NONCOPYABLE(ScreencastEncoder); + WTF_MAKE_FAST_ALLOCATED; +public: + static constexpr int fps = 25; + + static RefPtr create(String& errorString, const String& filePath, WebCore::IntSize); + + class VPXCodec; + ScreencastEncoder(std::unique_ptr&&, WebCore::IntSize); + ~ScreencastEncoder(); + +#if USE(SKIA) && !PLATFORM(GTK) + void encodeFrame(sk_sp&&, WebCore::IntSize); +#elif USE(CAIRO) || PLATFORM(GTK) + void encodeFrame(cairo_surface_t*, WebCore::IntSize); +#elif PLATFORM(MAC) + void encodeFrame(RetainPtr&&); + void setOffsetTop(int offset) { m_offsetTop = offset;} +#endif + + void finish(Function&& callback); + +private: + void flushLastFrame(); +#if PLATFORM(MAC) + static void imageToARGB(CGImageRef, uint8_t* rgba_data, int width, int height, int offsetTop); +#endif + + std::unique_ptr m_vpxCodec; + const WebCore::IntSize m_size; + MonotonicTime m_lastFrameTimestamp; + class VPXFrame; + std::unique_ptr m_lastFrame; +#if PLATFORM(MAC) + int m_offsetTop { 0 }; +#endif +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.cpp b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b269b356e206f0252245a1497adb0d05128c9b4 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * 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 "WebMFileWriter.h" + +#include +#include "mkvmuxer/mkvmuxerutil.h" + +namespace WebKit { + +WebMFileWriter::WebMFileWriter(FILE* file, vpx_codec_enc_cfg_t* cfg) + : m_cfg(cfg) + , m_writer(new mkvmuxer::MkvWriter(file)) + , m_segment(new mkvmuxer::Segment()) { + m_segment->Init(m_writer.get()); + m_segment->set_mode(mkvmuxer::Segment::kFile); + m_segment->OutputCues(true); + + mkvmuxer::SegmentInfo* info = m_segment->GetSegmentInfo(); + std::string version = "Playwright " + std::string(vpx_codec_version_str()); + info->set_writing_app(version.c_str()); + + // Add vp8 track. + m_videoTrackId = m_segment->AddVideoTrack( + static_cast(m_cfg->g_w), static_cast(m_cfg->g_h), 0); + if (!m_videoTrackId) { + fprintf(stderr, "Failed to add video track\n"); + } +} + +WebMFileWriter::~WebMFileWriter() {} + +bool WebMFileWriter::writeFrame(const vpx_codec_cx_pkt_t* pkt) { + int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * m_cfg->g_timebase.num / + m_cfg->g_timebase.den; + return m_segment->AddFrame(static_cast(pkt->data.frame.buf), + pkt->data.frame.sz, m_videoTrackId, pts_ns, + pkt->data.frame.flags & VPX_FRAME_IS_KEY); +} + +void WebMFileWriter::finish() { + m_segment->Finalize(); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.h b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..e2ce910f3fd7f587add552275b7e7176cf8b2723 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.h @@ -0,0 +1,53 @@ +/* + * 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 "vpx/vpx_encoder.h" + +#include "mkvmuxer/mkvmuxer.h" +#include "mkvmuxer/mkvwriter.h" + +namespace WebKit { + +class WebMFileWriter { +public: + WebMFileWriter(FILE*, vpx_codec_enc_cfg_t* cfg); + ~WebMFileWriter(); + + bool writeFrame(const vpx_codec_cx_pkt_t* pkt); + void finish(); + +private: + vpx_codec_enc_cfg_t* m_cfg = nullptr; + std::unique_ptr m_writer; + std::unique_ptr m_segment; + uint64_t m_videoTrackId = 0; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp index 76cc869ca4d5fc311040a285d50a44f00273fd63..633f8323697f0c2f30311a35ac3876bf8e03b741 100644 --- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp +++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp @@ -28,7 +28,7 @@ #include "MessageSenderInlines.h" #include "ProvisionalPageProxy.h" -#include "WebFrameProxy.h" +#include "WebPageInspectorController.h" #include "WebPageInspectorTarget.h" #include "WebPageMessages.h" #include "WebPageProxy.h" @@ -46,13 +46,13 @@ std::unique_ptr InspectorTargetProxy::create(WebPageProxy& return makeUnique(page, targetId, type); } -std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId, Inspector::InspectorTargetType type) +std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId) { RefPtr page = provisionalPage.page(); if (!page) return nullptr; - auto target = InspectorTargetProxy::create(*page, targetId, type); + auto target = InspectorTargetProxy::create(*page, targetId, Inspector::InspectorTargetType::Page); target->m_provisionalPage = provisionalPage; return target; } @@ -108,6 +108,31 @@ void InspectorTargetProxy::didCommitProvisionalTarget() m_provisionalPage = nullptr; } +void InspectorTargetProxy::willResume() +{ + if (m_page->hasRunningProcess()) + m_page->legacyMainFrameProcess().send(Messages::WebPage::ResumeInspectorIfPausedInNewWindow(), m_page->webPageIDInMainFrameProcess()); +} + +void InspectorTargetProxy::activate(String& error) +{ + if (m_type != Inspector::InspectorTargetType::Page) + return InspectorTarget::activate(error); + + platformActivate(error); +} + +void InspectorTargetProxy::close(String& error, bool runBeforeUnload) +{ + if (m_type != Inspector::InspectorTargetType::Page) + return InspectorTarget::close(error, runBeforeUnload); + + if (runBeforeUnload) + m_page->tryClose(); + else + m_page->closePage(); +} + bool InspectorTargetProxy::isProvisional() const { return !!m_provisionalPage; diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h index edd6e7f1799279ed3d0eb81b6c2eef9f5b375134..d4231f84f3c52641f4d9e88559e8e1a4845b7163 100644 --- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h +++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h @@ -38,12 +38,12 @@ class WebPageProxy; // NOTE: This UIProcess side InspectorTarget doesn't care about the frontend channel, since // any target -> frontend messages will be routed to the WebPageProxy with a targetId. -class InspectorTargetProxy final : public Inspector::InspectorTarget { +class InspectorTargetProxy : public Inspector::InspectorTarget { WTF_MAKE_TZONE_ALLOCATED(InspectorTargetProxy); WTF_MAKE_NONCOPYABLE(InspectorTargetProxy); public: static std::unique_ptr create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); - static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); + static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId); InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); ~InspectorTargetProxy() = default; @@ -56,8 +56,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; String m_identifier; Inspector::InspectorTargetType m_type; diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp index 45eb87344ce4249eea90dc0a73a2c717f69f55fa..b79c9ce9e9fd3ceb41fe6f34861536ab0bdf2e54 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp @@ -26,13 +26,22 @@ #include "config.h" #include "WebPageInspectorController.h" +#include "APINavigation.h" +#include "APIPageConfiguration.h" #include "APIUIClient.h" #include "InspectorBrowserAgent.h" +#include "InspectorDialogAgent.h" +#include "InspectorScreencastAgent.h" #include "ProvisionalPageProxy.h" #include "WebFrameProxy.h" #include "WebPageInspectorAgentBase.h" +#include "WebPageInspectorEmulationAgent.h" +#include "WebPageInspectorInputAgent.h" #include "WebPageInspectorTarget.h" #include "WebPageProxy.h" +#include "WebPreferences.h" +#include +#include #include #include #include @@ -52,34 +61,115 @@ static String getTargetID(const ProvisionalPageProxy& provisionalPage) 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())) , m_inspectedPage(inspectedPage) { - auto targetAgent = makeUnique(m_frontendRouter.get(), m_backendDispatcher.get()); - m_targetAgent = targetAgent.get(); - m_agents.append(WTFMove(targetAgent)); } WebPageInspectorController::~WebPageInspectorController() = default; -Ref WebPageInspectorController::protectedInspectedPage() +WeakRef WebPageInspectorController::protectedInspectedPage() { - return m_inspectedPage.get(); + return m_inspectedPage; } void WebPageInspectorController::init() { - String pageTargetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); - createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page); + auto targetAgent = makeUnique(m_frontendRouter.get(), m_backendDispatcher.get()); + m_targetAgent = targetAgent.get(); + m_agents.append(WTFMove(targetAgent)); + auto emulationAgent = makeUnique(m_backendDispatcher.get(), m_inspectedPage); + m_emulationAgent = emulationAgent.get(); + m_agents.append(WTFMove(emulationAgent)); + auto inputAgent = makeUnique(m_backendDispatcher.get(), m_inspectedPage); + m_inputAgent = inputAgent.get(); + m_agents.append(WTFMove(inputAgent)); + m_agents.append(makeUnique(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage)); + auto screencastAgent = makeUnique(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage); + m_screecastAgent = screencastAgent.get(); + m_agents.append(WTFMove(screencastAgent)); + if (s_observer) + s_observer->didCreateInspectorController(m_inspectedPage); +} + +void WebPageInspectorController::didInitializeWebPage() +{ + String pageTargetID = WebPageInspectorTarget::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; + createInspectorTarget(pageTargetID, Inspector::InspectorTargetType::Page); } void WebPageInspectorController::pageClosed() { + String pageTargetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()); + destroyInspectorTarget(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 = WebPageInspectorTarget::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 @@ -93,6 +183,17 @@ 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; + } + + if (connectingFirstFrontend) + adjustPageSettings(); + m_frontendRouter->connectFrontend(frontendChannel); if (connectingFirstFrontend) @@ -112,8 +213,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(); + } auto inspectedPage = protectedInspectedPage(); inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); @@ -137,6 +240,8 @@ void WebPageInspectorController::disconnectAllFrontends() // Disconnect any remaining remote frontends. m_frontendRouter->disconnectAllFrontends(); + m_pendingNavigations.clear(); + auto inspectedPage = protectedInspectedPage(); inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); @@ -165,6 +270,75 @@ void WebPageInspectorController::setIndicating(bool indicating) } #endif +#if USE(SKIA) && !PLATFORM(GTK) +void WebPageInspectorController::didPaint(sk_sp&& surface) +{ + if (!m_frontendRouter->hasFrontends()) + return; + + m_screecastAgent->didPaint(WTFMove(surface)); +} +#endif +#if USE(CAIRO) || PLATFORM(GTK) +void WebPageInspectorController::didPaint(cairo_surface_t* surface) +{ + if (!m_frontendRouter->hasFrontends()) + return; + + m_screecastAgent->didPaint(surface); +} +#endif + + +void WebPageInspectorController::navigate(WebCore::ResourceRequest&& request, WebFrameProxy* frame, NavigationHandler&& completionHandler) +{ + auto navigation = m_inspectedPage->loadRequestForInspector(WTFMove(request), frame); + if (!navigation) { + completionHandler("Failed to navigate"_s, { }); + return; + } + + m_pendingNavigations.set(navigation->navigationID(), WTFMove(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::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { addTarget(InspectorTargetProxy::create(protectedInspectedPage(), targetId, type)); @@ -184,6 +358,52 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta 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(WebPageInspectorTarget::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(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess())); + ASSERT(target); + target->setResumeCallback(WTFMove(callback)); +} + bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const { if (!m_frontendRouter->hasFrontends()) @@ -203,7 +423,7 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage) { - addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page)); + addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage))); } void WebPageInspectorController::willDestroyProvisionalPage(const ProvisionalPageProxy& provisionalPage) @@ -287,4 +507,29 @@ void WebPageInspectorController::browserExtensionsDisabled(HashSet&& ext m_enabledBrowserAgent->extensionsDisabled(WTFMove(extensionIDs)); } +void WebPageInspectorController::adjustPageSettings() +{ + // 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). + m_inspectedPage->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. + m_inspectedPage->preferences().setUsesBackForwardCache(false); + + // Enable popup debugging. + // TODO: allow to set preferences over the inspector protocol or find a better place for this. + m_inspectedPage->preferences().setJavaScriptCanOpenWindowsAutomatically(true); + + // Enable media stream. + if (!m_inspectedPage->preferences().mediaDevicesEnabled()) { + m_inspectedPage->preferences().setMediaDevicesEnabled(true); + m_inspectedPage->preferences().setPeerConnectionEnabled(true); + } + + // Disable local storage partitioning. See https://github.com/microsoft/playwright/issues/32230 + m_inspectedPage->preferences().setStorageBlockingPolicy(static_cast(WebCore::StorageBlockingPolicy::AllowAll)); +} + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h index c219e0a072057a8d40d8a30a1d404851d6c12d43..42e40b5ff6bd1b49d7662a1c7d60bfd4b8d61e29 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h @@ -26,19 +26,43 @@ #pragma once #include "InspectorTargetProxy.h" +#include "ProcessTerminationReason.h" #include #include +#include #include #include #include #include #include #include +#include + +#if USE(SKIA) +#include +#include +#endif + +#if USE(CAIRO) || PLATFORM(GTK) +#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 { @@ -46,6 +70,23 @@ namespace WebKit { class InspectorBrowserAgent; 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; + virtual void didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) = 0; + +protected: + virtual ~WebPageInspectorControllerObserver() = default; +}; + class WebPageInspectorController { WTF_MAKE_TZONE_ALLOCATED(WebPageInspectorController); WTF_MAKE_NONCOPYABLE(WebPageInspectorController); @@ -54,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; @@ -67,11 +122,30 @@ public: #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); #endif +#if USE(SKIA) && !PLATFORM(GTK) + void didPaint(sk_sp&&); +#endif +#if USE(CAIRO) || PLATFORM(GTK) + void didPaint(cairo_surface_t*); +#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 createInspectorTarget(const String& targetId, Inspector::InspectorTargetType); void destroyInspectorTarget(const String& targetId); 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&&); @@ -86,11 +160,12 @@ public: void browserExtensionsDisabled(HashSet&&); private: - Ref protectedInspectedPage(); + WeakRef protectedInspectedPage(); WebPageAgentContext webPageAgentContext(); void createLazyAgents(); void addTarget(std::unique_ptr&&); + void adjustPageSettings(); const Ref m_frontendRouter; const Ref m_backendDispatcher; @@ -101,9 +176,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/Inspector/mac/ScreencastEncoderMac.mm b/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..6a04ee480bc3a8270a7de20b1cd0da718242b4c1 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm @@ -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 "ScreencastEncoder.h" + +#include +#include +#include + +namespace WebKit { + +void ScreencastEncoder::imageToARGB(CGImageRef image, uint8_t* argb_data, int width, int height, int offsetTop) +{ + size_t bitsPerComponent = 8; + size_t bytesPerPixel = 4; + size_t bytesPerRow = bytesPerPixel * width; + RetainPtr colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); + RetainPtr context = adoptCF(CGBitmapContextCreate(argb_data, width, height, bitsPerComponent, bytesPerRow, colorSpace.get(), (CGBitmapInfo)kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little)); + double imageWidth = CGImageGetWidth(image); + double imageHeight = CGImageGetHeight(image); + double pageHeight = imageHeight - offsetTop; + double ratio = 1; + if (imageWidth > width || pageHeight > height) { + ratio = std::min(width / imageWidth, height / pageHeight); + } + imageWidth *= ratio; + imageHeight *= ratio; + pageHeight *= ratio; + CGContextDrawImage(context.get(), CGRectMake(0, height - pageHeight, imageWidth, imageHeight), image); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..663f92f0df76042cf6385b056f8a917d688259f9 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp @@ -0,0 +1,88 @@ +/* + * 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; + +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(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ +} + +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..d0e11ed81a6257c011df23d5870da7403f8e9fe4 --- /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_FAST_ALLOCATED; +public: + InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorDialogAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + 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..59827ffa02a8a3c7890ab0b5a8f54244f6a0680b --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp @@ -0,0 +1,1011 @@ +/* + * 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 "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 "WebPageInspectorTarget.h" +#include "WebPageMessages.h" +#include "WebPageProxy.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 + +using namespace Inspector; + +namespace WebKit { + +class InspectorPlaywrightAgent::PageProxyChannel : public FrontendChannel { + WTF_MAKE_FAST_ALLOCATED; +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(WTFMove(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(); +} + +} // namespace + +BrowserContext::BrowserContext() = default; + +BrowserContext::~BrowserContext() = default; + +class InspectorPlaywrightAgent::BrowserContextDeletion { + WTF_MAKE_NONCOPYABLE(BrowserContextDeletion); + WTF_MAKE_FAST_ALLOCATED; +public: + BrowserContextDeletion(std::unique_ptr&& context, size_t numberOfPages, Ref&& callback) + : m_browserContext(WTFMove(context)) + , m_numberOfPages(numberOfPages) + , m_callback(WTFMove(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); + page.inspectorController().connectFrontend(*pageProxyChannel); + // Always pause new targets if controlled remotely. + page.inspectorController().setPauseOnStart(true); + m_pageProxyChannels.set(pageProxyID, WTFMove(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)); +} + +void InspectorPlaywrightAgent::didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) +{ + if (!m_isEnabled) + return; + + m_frontendDispatcher->screencastFinished(screencastID); +} + +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), WTFMove(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(WTFMove(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 = WTFMove(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(WTFMove(page)); + } + for (Ref page : pages) + page->closePage(); + + if (!m_defaultContext) { + m_client->closeBrowser(); + callback(String()); + return; + } + + m_defaultContext->dataStore->syncLocalStorage([this, callback = WTFMove(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) +{ + String errorString; + std::unique_ptr browserContext = m_client->createBrowserContext(errorString, proxyServer, proxyBypassList); + if (!browserContext) + return makeUnexpected(errorString); + + // 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, WTFMove(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(WTFMove(contextHolder), pages.size(), WTFMove(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; + } + + WebCore::ResourceRequest resourceRequest { 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(WTFMove(resourceRequest), frame, [callback = WTFMove(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(WTFMove(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(), WTFMove(clip), nominalResolution, [callback = WTFMove(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); + + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + NetworkProcessProxy& networkProcess = browserContext->dataStore->networkProcess(); + networkProcess.send(Messages::NetworkProcess::SetIgnoreCertificateErrors(sessionID, ignore), 0); + 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 = WTFMove(callback)](const Vector& allCookies) { + if (!callback->isActive()) + return; + auto cookies = JSON::ArrayOf::create(); + + for (const auto& cookie : allCookies) + cookies->addItem(buildObjectForCookie(cookie)); + callback->sendSuccess(WTFMove(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(WTFMove(cookie)); + } + + browserContext->dataStore->cookieStore().setCookies(WTFMove(cookies), + [callback = WTFMove(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 = WTFMove(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(WTFMove(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; + } + auto browserContext = getExistingBrowserContext(browserContextID); + if (!browserContext) { + callback->sendSuccess(); + 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..f9185788a118f57e98bec149909a206dc1aa5d99 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h @@ -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. + */ + +#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_MAKE_FAST_ALLOCATED; +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; + void didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) 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) 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..e7a3dcc533294bb6e12f65d79b5b716bd3c12236 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h @@ -0,0 +1,73 @@ +/* + * 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_MAKE_FAST_ALLOCATED; +public: + BrowserContext(); + ~BrowserContext(); + + RefPtr dataStore; + RefPtr processPool; + HashSet pages; + WeakPtr geolocationProvider; +}; + +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 272e0a6edea50acd35032a854d625b5af5a1472e..486c807ba879ecf534db1ffb593709d117e0c35a 100644 --- a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp +++ b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp @@ -168,6 +168,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 WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN // GTK/WPE port @@ -188,6 +195,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; WTF_ALLOW_UNSAFE_BUFFER_USAGE_END diff --git a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp index a108acd8a4503a07309fe8c54afc80b0f4175eae..1421d9a761042c31a6ecf3cc78ce3f0e96109abe 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.data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation); diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h index 0cffbf89f6b402b9aaa65bf9edd7387f0aff65da..baa97c9400538243f96af3bde2482dbd3542b38d 100644 --- a/Source/WebKit/UIProcess/PageClient.h +++ b/Source/WebKit/UIProcess/PageClient.h @@ -74,6 +74,11 @@ #include #endif +#if USE(SKIA) +#include +#include +#endif + OBJC_CLASS AVPlayerViewController; OBJC_CLASS CALayer; OBJC_CLASS NSFileWrapper; @@ -95,6 +100,12 @@ OBJC_CLASS WKView; #endif #endif +#if PLATFORM(GTK) || PLATFORM(WPE) +#if USE(CAIRO) +#include +#endif +#endif + namespace API { class Attachment; class HitTestResult; @@ -380,7 +391,20 @@ public: virtual void selectionDidChange() = 0; #endif -#if PLATFORM(COCOA) || PLATFORM(GTK) +// Paywright begin +#if PLATFORM(COCOA) + virtual RetainPtr takeSnapshotForAutomation() = 0; +#elif PLATFORM(WPE) +#if USE(SKIA) + virtual sk_sp takeViewSnapshot(std::optional&&, bool nominalResolution = false) = 0; +#elif USE(CAIRO) + virtual RefPtr takeViewSnapshot(std::optional&&, bool nominalResolution = false) = 0; +#endif +#elif PLATFORM(GTK) + 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..a8a92a6c5f4b03724decc97828291f6f27cfc6aa --- /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_MAKE_FAST_ALLOCATED; +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 6a324ab3945475beed2774ab596645c72a6f658e..9045758645d48123c574a2ba7529a433c1a99f57 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/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1ddac8c1442cb4da17f50d92599ef9aff6d4066 --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp @@ -0,0 +1,230 @@ +/* + * 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_MAKE_FAST_ALLOCATED; + +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::main().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.data() + start, end - start }); + RunLoop::main().dispatch([this, message = WTFMove(message)] { + if (!m_terminated) + m_playwrightAgent.dispatchMessageFromFrontend(message); + }); + } + ++end; + start = end; + } + if (start != 0 && start < line.size()) + memmove(line.data(), line.data() + start, line.size() - start); + line.shrink(line.size() - start); + } +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) + +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..6d04f9290135069359ce6bf8726546482fd1dc95 --- /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_MAKE_FAST_ALLOCATED; +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/WebContextMenuProxy.h b/Source/WebKit/UIProcess/WebContextMenuProxy.h index 697a350812e1bf73dd44cc3d723a6a291f9d59d1..a8e1edd710d88f48632d51fd05aa964732d727d3 100644 --- a/Source/WebKit/UIProcess/WebContextMenuProxy.h +++ b/Source/WebKit/UIProcess/WebContextMenuProxy.h @@ -49,6 +49,7 @@ public: void deref() const final { RefCounted::deref(); } virtual void show(); + virtual void hide() {} WebPageProxy* page() const { return m_page.get(); } RefPtr protectedPage() const; diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a8d10ae990997684766df46719c65aa8dd77f28 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp @@ -0,0 +1,159 @@ +/* + * 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; + +WebPageInspectorEmulationAgent::WebPageInspectorEmulationAgent(BackendDispatcher& backendDispatcher, WebPageProxy& page) + : InspectorAgentBase("Emulation"_s) + , m_backendDispatcher(EmulationBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +WebPageInspectorEmulationAgent::~WebPageInspectorEmulationAgent() +{ +} + +void WebPageInspectorEmulationAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ +} + +void WebPageInspectorEmulationAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ + 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()->isViewVisible() && m_page.configuration().relatedPage()) { + m_commandsToRunWhenShown.append([this, width, height, callback = WTFMove(callback)]() mutable { + setSize(width, height, WTFMove(callback)); + }); + } else { + setSize(width, height, WTFMove(callback)); + } +} + +void WebPageInspectorEmulationAgent::setSize(int width, int height, Ref&& callback) +{ + platformSetSize(width, height, [callback = WTFMove(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 && !!password) + m_page.setAuthCredentialsForAutomation(WebCore::Credential(username, password, WebCore::CredentialPersistence::Permanent), URL(origin)); + else + m_page.setAuthCredentialsForAutomation(std::optional(), std::optional()); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setActiveAndFocused(std::optional&& active) +{ + m_page.setActiveForAutomation(WTFMove(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, WTFMove(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(WTFMove(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..d00d00ce8fd800dc1497b36b8a495c5b9aef6f58 --- /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_FAST_ALLOCATED; +public: + WebPageInspectorEmulationAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorEmulationAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + void setDeviceMetricsOverride(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..6cb20d95c1cd8682b025cfdf4ac74f49fd8e9cda --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp @@ -0,0 +1,394 @@ +/* + * 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 "WebTouchEvent.h" +#include "WebWheelEvent.h" +#include +#include +#include + +#include "WebPageMessages.h" + +namespace WebKit { + +using namespace Inspector; + +namespace { + +template +class CallbackList { + WTF_MAKE_FAST_ALLOCATED; +public: + ~CallbackList() + { + for (const auto& callback : m_callbacks) + callback->sendFailure("Page closed"_s); + } + + void append(Ref&& callback) + { + m_callbacks.append(WTFMove(callback)); + } + + void sendSuccess() + { + for (const auto& callback : m_callbacks) + callback->sendSuccess(); + m_callbacks.clear(); + } + +private: + Vector> m_callbacks; +}; + +} // namespace + +class WebPageInspectorInputAgent::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(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ + 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.characterAt(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; + WallTime timestamp = WallTime::now(); + + // cancel any active drag on Escape + if (eventType == WebEventType::KeyDown && key == "Escape"_s && m_page.cancelDragIfNeeded()) { + callback->sendSuccess(); + return; + } + + m_keyboardCallbacks->append(WTFMove(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(WTFMove(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, WTFMove(modifiers), button, WTFMove(clickCount), eventButtons); +#elif PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN) + WallTime timestamp = WallTime::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::IntSize 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, WallTime::now()}, WTFMove(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(WTFMove(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)); + + WallTime timestamp = WallTime::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::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..26a2a3c0791c334f811ec99a630314f8e8521d02 --- /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_FAST_ALLOCATED; +public: + WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorInputAgent() override; + + void didProcessAllPendingKeyboardEvents(); + void didProcessAllPendingMouseEvents(); + void didProcessAllPendingWheelEvents(); + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) 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, WallTime 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 8596e12ab413647f88507c1bbfebcd5ca441a190..11ce2408b8358bc2ebe3abfc79c47662e991d7c0 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -203,6 +203,7 @@ #include #include #include +#include #include #include #include @@ -214,6 +215,7 @@ #include #include #include +#include #include #include #include @@ -238,6 +240,7 @@ #include #include #include +#include #include #include #include @@ -245,10 +248,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -336,6 +342,9 @@ #if USE(GBM) #include "AcceleratedBackingStoreDMABuf.h" #endif +#endif + +#if PLATFORM(GTK) || PLATFORM(WPE) #include #endif @@ -461,6 +470,8 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms; static constexpr Seconds audibleActivityClearDelay = 10_s; #endif +using namespace WebCore; + DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy")); #if PLATFORM(COCOA) @@ -983,6 +994,10 @@ WebPageProxy::~WebPageProxy() #endif internals().updatePlayingMediaDidChangeTimer.stop(); + +#if PLATFORM(COCOA) + releaseInspectorDragPasteboard(); +#endif } Ref WebPageProxy::Internals::protectedPage() const @@ -1556,7 +1571,7 @@ void WebPageProxy::didAttachToRunningProcess() #if ENABLE(FULLSCREEN_API) ASSERT(!m_fullScreenManager); - m_fullScreenManager = WebFullScreenManagerProxy::create(*this, protectedPageClient()->fullScreenManagerProxyClient()); + m_fullScreenManager = WebFullScreenManagerProxy::create(*this, m_fullScreenManagerClientOverride ? *m_fullScreenManagerClientOverride : protectedPageClient()->fullScreenManagerProxyClient()); #endif #if ENABLE(VIDEO_PRESENTATION_MODE) ASSERT(!m_playbackSessionManager); @@ -1722,6 +1737,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, *m_drawingArea, m_mainFrame->frameID(), std::nullopt)), 0); + m_inspectorController->didInitializeWebPage(); #if ENABLE(WINDOW_PROXY_PROPERTY_ACCESS_NOTIFICATION) internals().frameLoadStateObserver = makeUniqueWithoutRefCountedCheck(*this); @@ -1988,6 +2004,21 @@ Ref WebPageProxy::ensureProtectedRunningProcess() return ensureRunningProcess(); } +RefPtr WebPageProxy::loadRequestForInspector(WebCore::ResourceRequest&& request, WebFrameProxy* frame) +{ + if (!frame || frame == mainFrame()) + return loadRequest(WTFMove(request), WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow); + + auto navigation = m_navigationState->createLoadRequestNavigation(legacyMainFrameProcess().coreProcessIdentifier(), ResourceRequest(request), m_backForwardList->currentItem()); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.request = WTFMove(request); + loadParameters.shouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow; + loadParameters.shouldTreatAsContinuingLoad = ShouldTreatAsContinuingLoad::No; + m_legacyMainFrameProcess->send(Messages::WebPage::LoadRequestInFrameForInspector(WTFMove(loadParameters), frame->frameID()), m_webPageID); + return navigation; +} + RefPtr WebPageProxy::loadRequest(WebCore::ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, IsPerformingHTTPFallback isPerformingHTTPFallback, std::unique_ptr&& lastNavigationAction, API::Object* userData) { if (m_isClosed) @@ -2103,11 +2134,29 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref&& proces navigation->setIsLoadedWithNavigationShared(true); protectedProcess->markProcessAsRecentlyUsed(); - if (!protectedProcess->isLaunching() || !url.protocolIsFile()) - protectedProcess->send(Messages::WebPage::LoadRequest(WTFMove(loadParameters)), webPageID); + + // Pause loading for new window navigation. + Function continuation = [ + weakThis = WeakPtr { protectedThis }, + weakProcess = WeakPtr { protectedProcess }, + loadParameters = WTFMove(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(WTFMove(loadParameters)), webPageID); + else + innerProtectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTFMove(loadParameters), innerProtectedThis->internals().pageLoadState.resourceDirectoryURL(), innerProtectedThis->identifier(), true), webPageID); + innerProtectedProcess->startResponsivenessTimer(); + }; + if (protectedThis->m_inspectorController->shouldPauseLoadRequest()) + protectedThis->m_inspectorController->setContinueLoadingCallback(WTFMove(continuation)); else - protectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTFMove(loadParameters), protectedThis->pageLoadState().resourceDirectoryURL(), protectedThis->identifier(), true), webPageID); - protectedProcess->startResponsivenessTimer(); + continuation(); }); } @@ -2661,6 +2710,63 @@ void WebPageProxy::setControlledByAutomation(bool controlled) protectedWebsiteDataStore()->protectedNetworkProcess()->send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0); } +void WebPageProxy::setAuthCredentialsForAutomation(std::optional&& credentials, std::optional&& origin) +{ + m_credentialsForAutomation = WTFMove(credentials); + m_authOriginForAutomation = WTFMove(origin); +} + +void WebPageProxy::setPermissionsForAutomation(const UncheckedKeyHashMap>& permissions) +{ + m_permissionsForAutomation = permissions; +} + +static inline 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; +} + +void WebPageProxy::setOrientationOverride(std::optional&& angle) +{ + auto deviceOrientation = toScreenOrientationType(angle.value_or(0)); + if (m_screenOrientationManager) + m_screenOrientationManager->setCurrentOrientation(deviceOrientation); + m_legacyMainFrameProcess->send(Messages::WebPage::SetDeviceOrientation(angle.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::createInspectorTarget(IPC::Connection& connection, const String& targetId, Inspector::InspectorTargetType type) { MESSAGE_CHECK_BASE(!targetId.isEmpty(), connection); @@ -2920,6 +3026,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()) @@ -3683,7 +3807,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()) protectedLegacyMainFrameProcess()->assumeReadAccessToBaseURL(*this, url.string(), [] { }); @@ -3711,6 +3835,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; @@ -3722,7 +3848,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag dragData.setClientPosition(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()), WTFMove(completionHandler)); #else @@ -3757,14 +3883,35 @@ void WebPageProxy::didPerformDragControllerAction(std::optionalpageClient()) pageClient->didPerformDragControllerAction(); + m_dragEventsQueued--; + if (m_dragEventsQueued == 0 && internals().mouseEventQueue.isEmpty()) + m_inspectorController->didProcessAllPendingMouseEvents(); } -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) void WebPageProxy::startDrag(SelectionData&& selectionData, OptionSet dragOperationMask, std::optional&& dragImageHandle, IntPoint&& dragImageHotspot) { - if (RefPtr pageClient = this->pageClient()) { - RefPtr dragImage = dragImageHandle ? ShareableBitmap::create(WTFMove(*dragImageHandle)) : nullptr; - pageClient->startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage), WTFMove(dragImageHotspot)); + if (m_interceptDrags) { + m_dragSelectionData = WTFMove(selectionData); + m_dragSourceOperationMask = dragOperationMask; + } else { +#if PLATFORM(GTK) + if (RefPtr pageClient = this->pageClient()) { + RefPtr dragImage = dragImageHandle ? ShareableBitmap::create(WTFMove(*dragImageHandle)) : nullptr; + pageClient->startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage), WTFMove(dragImageHotspot)); + } +#endif + } + didStartDrag(); +} +#endif + +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) +void WebPageProxy::startDrag(WebCore::DragDataMap&& dragDataMap) +{ + if (m_interceptDrags) { + m_dragSelectionData = WTFMove(dragDataMap); + m_dragSourceOperationMask = WebCore::anyDragOperation(); } didStartDrag(); } @@ -3786,6 +3933,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() { if (!hasRunningProcess()) @@ -3793,6 +3958,26 @@ void WebPageProxy::didStartDrag() discardQueuedMouseEvents(); send(Messages::WebPage::DidStartDrag()); + + 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() @@ -3958,26 +4143,47 @@ void WebPageProxy::processNextQueuedMouseEvent() process->startResponsivenessTimer(); } - std::optional> sandboxExtensions; + m_lastMousePositionForDrag = 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(m_mainFrame->frameID(), eventWithCoalescedEvents, WTFMove(sandboxExtensions)); + sendMouseEvent(m_mainFrame->frameID(), eventWithCoalescedEvents, WTFMove(sandboxExtensions)); - internals().coalescedMouseEvents.clear(); + internals().coalescedMouseEvents.clear(); + } else { +#if PLATFORM(WIN) || PLATFORM(COCOA) + DragData dragData(*m_dragSelectionData, event.position(), event.globalPosition(), m_dragSourceOperationMask); +#else + DragData dragData(&*m_dragSelectionData, event.position(), 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, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload)); + } + m_dragSelectionData = std::nullopt; + dragEnded(event.position(), event.globalPosition(), m_dragSourceOperationMask); + } + didReceiveEventIPC(process->connection(), eventType, true, std::nullopt); + } } void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function&& action) @@ -4174,6 +4380,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) @@ -4310,7 +4518,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b) void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent) { -#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA) +#if ENABLE(ASYNC_SCROLLING) && PLATFORM(IOS_FAMILY) for (auto& touchPoint : touchStartEvent.touchPoints()) { auto location = touchPoint.locationInRootView(); auto update = [this, location](TrackingType& trackingType, EventTrackingRegions::EventType eventType) { @@ -4972,6 +5180,7 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr&& websitePolicies, 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 { }); @@ -5969,6 +6178,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()) @@ -6606,6 +6816,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref&& process, We RefPtr protectedPageClient { pageClient() }; protectedNavigationState()->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) @@ -6947,6 +7158,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref&& p m_failingProvisionalLoadURL = { }; + 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; @@ -8405,8 +8618,9 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w if (RefPtr page = originatingFrameInfo->page()) openerAppInitiatedState = page->lastNavigationWasAppInitiated(); - auto navigationDataForNewProcess = navigationActionData.hasOpener ? nullptr : makeUnique(navigationActionData); + m_inspectorController->willCreateNewPage(windowFeatures, request.url()); + auto navigationDataForNewProcess = navigationActionData.hasOpener ? nullptr : makeUnique(navigationActionData); auto completionHandler = [ this, protectedThis = Ref { *this }, @@ -8486,6 +8700,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w configuration->setOpenedMainFrameName(openedMainFrameName); if (!protectedPreferences()->siteIsolationEnabled()) configuration->setRelatedPage(*this); + configuration->setOpenerPageForInspector(*this); if (RefPtr openerFrame = WebFrameProxy::webFrame(originatingFrameInfoData.frameID); navigationActionData.hasOpener && openerFrame) { configuration->setOpenerInfo({ { @@ -8514,6 +8729,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w void WebPageProxy::showPage() { m_uiClient->showPage(this); + m_inspectorController->didShowPage(); } bool WebPageProxy::hasOpenedPage() const @@ -8645,6 +8861,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(); @@ -8683,6 +8903,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi } runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { + if (page.m_inspectorDialogAgent) + page.m_inspectorDialogAgent->javascriptDialogOpening("alert"_s, message); page.m_uiClient->runJavaScriptAlert(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)]() mutable { reply(); completion(); @@ -8705,6 +8927,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("confirm"_s, message); runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { page.m_uiClient->runJavaScriptConfirm(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](bool result) mutable { @@ -8729,6 +8953,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("prompt"_s, message, defaultValue); runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply), defaultValue](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { page.m_uiClient->runJavaScriptPrompt(page, message, defaultValue, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](auto& result) mutable { @@ -8864,6 +9090,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. WebProcessProxy::fromConnection(connection)->stopResponsivenessTimer(); @@ -9481,6 +9709,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo, } #if ENABLE(FULLSCREEN_API) +void WebPageProxy::setFullScreenManagerClientOverride(std::unique_ptr&& client) +{ + m_fullScreenManagerClientOverride = WTFMove(client); +} + WebFullScreenManagerProxy* WebPageProxy::fullScreenManager() { return m_fullScreenManager.get(); @@ -9608,6 +9841,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; + } + protectedPageClient()->requestDOMPasteAccess(pasteAccessCategory, requiresInteraction, elementRect, originIdentifier, WTFMove(completionHandler)); } @@ -10634,6 +10878,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional event if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); didFinishProcessingAllPendingMouseEvents(); + if (m_dragEventsQueued == 0) + m_inspectorController->didProcessAllPendingMouseEvents(); } } @@ -10669,6 +10915,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional eventTy if (!canProcessMoreKeyEvents) { if (RefPtr automationSession = configuration().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); + m_inspectorController->didProcessAllPendingKeyboardEvents(); } } @@ -11101,7 +11348,10 @@ void WebPageProxy::dispatchProcessDidTerminate(WebProcessProxy& process, Process if (protectedPreferences()->siteIsolationEnabled()) protectedBrowsingContextGroup()->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 @@ -11752,6 +12002,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc parameters.canUseCredentialStorage = m_canUseCredentialStorage; parameters.httpsUpgradeEnabled = preferences->upgradeKnownHostsToHTTPSEnabled() ? m_configuration->httpsUpgradeEnabled() : false; + + parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseInInspectorWhenShown(); #if ENABLE(APP_HIGHLIGHTS) parameters.appHighlightsVisible = appHighlightsVisibility() ? HighlightVisibility::Visible : HighlightVisibility::Hidden; @@ -11917,8 +12169,42 @@ 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 (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) @@ -12014,6 +12300,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 @@ -12078,6 +12370,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; } @@ -12092,6 +12390,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 de568bc247847234de4bd8a34d80726a4fa22a53..85881e1a1a695907016c0924e3df38f072455f61 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -26,6 +26,7 @@ #pragma once #include "APIObject.h" +#include "APIWebsitePolicies.h" #include "MessageReceiver.h" #include #include @@ -44,6 +45,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(DICTATION_ALTERNATIVES) #include @@ -128,6 +143,7 @@ class DragData; class Exception; class FloatPoint; class FloatQuad; +typedef UncheckedKeyHashMap> DragDataMap; class FloatRect; class FloatSize; class FontAttributeChanges; @@ -734,6 +750,8 @@ public: void setControlledByAutomation(bool); WebPageInspectorController& inspectorController() { return *m_inspectorController; } + InspectorDialogAgent* inspectorDialogAgent() { return m_inspectorDialogAgent; } + void setInspectorDialogAgent(InspectorDialogAgent * dialogAgent) { m_inspectorDialogAgent = dialogAgent; } #if PLATFORM(IOS_FAMILY) void showInspectorIndication(); @@ -767,6 +785,7 @@ public: bool hasSleepDisabler() const; #if ENABLE(FULLSCREEN_API) + void setFullScreenManagerClientOverride(std::unique_ptr&&); WebFullScreenManagerProxy* fullScreenManager(); RefPtr protectedFullScreenManager(); void setFullScreenClientForTesting(std::unique_ptr&&); @@ -858,6 +877,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); void setDrawingArea(RefPtr&&); @@ -889,6 +914,8 @@ public: RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback); RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback, std::unique_ptr&&, API::Object* userData = nullptr); + 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); @@ -977,6 +1004,7 @@ public: PageClient* pageClient() const; RefPtr protectedPageClient() const; + bool hasPageClient() const { return !!m_pageClient; } void setViewNeedsDisplay(const WebCore::Region&); void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin, WebCore::ScrollIsAnimated); @@ -1617,14 +1645,20 @@ public: void didStartDrag(); void dragCancelled(); void setDragCaretRect(const WebCore::IntRect&); + void setInterceptDrags(bool shouldIntercept); + bool cancelDragIfNeeded(); #if PLATFORM(COCOA) void startDrag(const WebCore::DragItem&, WebCore::ShareableBitmapHandle&& dragImageHandle); 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) +#if PLATFORM(GTK) || PLATFORM(WPE) void startDrag(WebCore::SelectionData&&, OptionSet, std::optional&& dragImage, WebCore::IntPoint&& dragImageHotspot); #endif +#if PLATFORM(WIN) + void startDrag(WebCore::DragDataMap&& dragDataMap); +#endif #endif void processDidBecomeUnresponsive(); @@ -1877,6 +1911,7 @@ public: void setViewportSizeForCSSViewportUnits(const WebCore::FloatSize&); WebCore::FloatSize viewportSizeForCSSViewportUnits() const; + bool shouldSendAutomationCredentialsForProtectionSpace(const WebProtectionSpace&); void didReceiveAuthenticationChallengeProxy(Ref&&, NegotiatedLegacyTLS); void negotiatedLegacyTLS(); void didNegotiateModernTLS(const URL&); @@ -1910,6 +1945,8 @@ public: #if PLATFORM(COCOA) || PLATFORM(GTK) 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>&&)>&&); @@ -2919,6 +2956,7 @@ private: RefPtr launchProcessForReload(); void requestNotificationPermission(const String& originString, CompletionHandler&&); + std::optional permissionForAutomation(const String& origin, const String& permission) const; void didChangeContentSize(const WebCore::IntSize&); void didChangeIntrinsicContentSize(const WebCore::IntSize&); @@ -3436,8 +3474,10 @@ private: String m_openedMainFrameName; RefPtr m_inspector; + InspectorDialogAgent* m_inspectorDialogAgent { nullptr }; #if ENABLE(FULLSCREEN_API) + std::unique_ptr m_fullScreenManagerClientOverride; RefPtr m_fullScreenManager; std::unique_ptr m_fullscreenClient; #endif @@ -3636,6 +3676,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 }; @@ -3807,6 +3863,10 @@ private: RefPtr messageBody; }; Vector m_pendingInjectedBundleMessages; + std::optional m_credentialsForAutomation; + std::optional m_authOriginForAutomation; + UncheckedKeyHashMap> m_permissionsForAutomation; + 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 0310e26fe8eb09a68db493035b108aa472dc573d..0182474dd3cb70bc87f239718ad52db972cc44ae 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, WebKit::UserData userData) + LogToStderr(String text) DidReceiveEventIPC(enum:uint8_t WebKit::WebEventType eventType, bool handled, struct std::optional remoteUserInputEventData) SetCursor(WebCore::Cursor cursor) @@ -333,10 +334,14 @@ messages -> WebPageProxy { StartDrag(struct WebCore::DragItem dragItem, WebCore::ShareableBitmapHandle dragImage) SetPromisedDataForImage(String pasteboardName, WebCore::SharedMemory::Handle imageHandle, String filename, String extension, String title, String url, String visibleURL, WebCore::SharedMemory::Handle archiveHandle, String originIdentifier) #endif -#if PLATFORM(GTK) && ENABLE(DRAG_SUPPORT) +#if (PLATFORM(GTK) || PLATFORM(WPE)) && ENABLE(DRAG_SUPPORT) StartDrag(WebCore::SelectionData selectionData, OptionSet dragOperationMask, std::optional dragImage, WebCore::IntPoint dragImageHotspot) #endif +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) + StartDrag(UncheckedKeyHashMap> dragDataMap) +#endif + #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT) DidHandleDragStartRequest(bool started) DidHandleAdditionalDragItemsRequest(bool added) diff --git a/Source/WebKit/UIProcess/WebProcessCache.cpp b/Source/WebKit/UIProcess/WebProcessCache.cpp index dc6f440403cccc5cd93f75806cffbf05cc56041c..e880beba2034cc2b87dcfb3e1e8bacf1bed78cf3 100644 --- a/Source/WebKit/UIProcess/WebProcessCache.cpp +++ b/Source/WebKit/UIProcess/WebProcessCache.cpp @@ -100,6 +100,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 4be8b8ead49ba2ab0ce16af74aa92fab01352358..8e310f0e3bcada1ec9383161b979660e29c50724 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.cpp +++ b/Source/WebKit/UIProcess/WebProcessPool.cpp @@ -445,10 +445,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr& void WebProcessPool::setOverrideLanguages(Vector&& languages) { - WebKit::setOverrideLanguages(WTFMove(languages)); + m_configuration->setOverrideLanguages(WTFMove(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()) @@ -456,9 +456,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) { @@ -939,7 +940,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.urlSchemesRegisteredAsEmptyDocument = copyToVector(m_schemesToRegisterAsEmptyDocument); diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp index 45a11c271082cd40635c6b21ee01c75bea749a4b..4ba89b3eafebfa67d8518ec99db6f23ae968df29 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.cpp +++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp @@ -203,6 +203,11 @@ Vector> WebProcessProxy::allProcesses() }); } +Vector> WebProcessProxy::allProcessesForInspector() +{ + return copyToVector(allProcesses()); +} + RefPtr WebProcessProxy::processForIdentifier(ProcessIdentifier identifier) { return allProcessMap().get(identifier); @@ -572,6 +577,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt if (WebKit::isInspectorProcessPool(protectedProcessPool())) 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 4471fdf4a46180f78cea1cf035671bfe3c83b8e2..0858fe7f56eb3d8648467f5b82c2d77d6c958b77 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.h +++ b/Source/WebKit/UIProcess/WebProcessProxy.h @@ -185,6 +185,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 ef4db4e5e75286a260646226dd48108810b1607e..bf1111ed48e9d3cb74b59d4258faefb814028540 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp @@ -319,7 +319,8 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W static Ref networkProcessForSession(PAL::SessionID sessionID) { -#if ((PLATFORM(GTK) || PLATFORM(WPE)) && !ENABLE(2022_GLIB_API)) +// Playwright wants to isolate per BrowserContext. +#if ((PLATFORM(GTK) || PLATFORM(WPE))) if (sessionID.isEphemeral()) { // Reuse a previous persistent session network process for ephemeral sessions. for (auto& dataStore : allDataStores().values()) { @@ -2511,6 +2512,12 @@ void WebsiteDataStore::originDirectoryForTesting(WebCore::ClientOrigin&& origin, protectedNetworkProcess()->websiteDataOriginDirectoryForTesting(m_sessionID, WTFMove(origin), type, WTFMove(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 f1a113cc08f6543ab22be75a03823f49a3f52017..3d98a33003ae86f2ac5982ba2deb5eb3238b1385 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h @@ -98,6 +98,7 @@ class DeviceIdHashSaltStorage; class DownloadProxy; class NetworkProcessProxy; class SOAuthorizationCoordinator; +class DownloadProxy; class VirtualAuthenticatorManager; class WebPageProxy; class WebProcessPool; @@ -113,6 +114,7 @@ enum class UnifiedOriginStorageLevel : uint8_t; enum class WebsiteDataFetchOption : uint8_t; enum class WebsiteDataType : uint32_t; +struct FrameInfoData; struct ITPThirdPartyData; struct NetworkProcessConnectionInfo; struct WebPushMessage; @@ -122,6 +124,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 Ref defaultDataStore(); @@ -318,11 +328,13 @@ public: const WebCore::CurlProxySettings& networkProxySettings() const { return m_proxySettings; } #endif -#if USE(SOUP) +#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN) void setPersistentCredentialStorageEnabled(bool); bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled && isPersistent(); } void setIgnoreTLSErrors(bool); bool ignoreTLSErrors() const { return m_ignoreTLSErrors; } +#endif +#if USE(SOUP) void setNetworkProxySettings(WebCore::SoupNetworkProxySettings&&); const WebCore::SoupNetworkProxySettings& networkProxySettings() const { return m_networkProxySettings; } void setCookiePersistentStorage(const String&, SoupCookiePersistentStorageType); @@ -420,6 +432,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) @@ -616,9 +634,11 @@ private: WebCore::CurlProxySettings m_proxySettings; #endif -#if USE(SOUP) +#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN) bool m_persistentCredentialStorageEnabled { true }; bool m_ignoreTLSErrors { true }; +#endif +#if USE(SOUP) WebCore::SoupNetworkProxySettings m_networkProxySettings; String m_cookiePersistentStoragePath; SoupCookiePersistentStorageType m_cookiePersistentStorageType { SoupCookiePersistentStorageType::SQLite }; @@ -645,6 +665,10 @@ private: RefPtr m_cookieStore; RefPtr m_networkProcess; + std::optional m_allowDownloadForAutomation; + String m_downloadPathForAutomation; + DownloadInstrumentation* m_downloadInstrumentation { nullptr }; + #if HAVE(APP_SSO) std::unique_ptr m_soAuthorizationCoordinator; #endif diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp index 19934de3173ecc0507c5e59956bcf6730a8a88b4..bc0e52f6f28caeca8b9b7aab14b7ff991d7e6b41 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/InspectorPlaywrightAgentClientGLib.cpp b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac01ad1653b22a0f22c45a196659e68fc22d7f32 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp @@ -0,0 +1,201 @@ +/* + * 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" +#if USE(CAIRO) +#include +#endif +#if USE(SKIA) +#include +#endif +#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(WTFMove(cstr)); + } + } + ignoreHosts.append(nullptr); + return parseRawProxySettings(proxyServer, ignoreHosts.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) +{ +#if !ENABLE(2022_GLIB_API) + GRefPtr data_manager = adoptGRef(webkit_website_data_manager_new_ephemeral()); +#endif + GRefPtr context = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, +#if !ENABLE(2022_GLIB_API) + "website-data-manager", data_manager.get(), +#endif + // WPE has PSON enabled by default and doesn't have such parameter. +#if PLATFORM(GTK) +#if !ENABLE(2022_GLIB_API) + "process-swap-on-cross-site-navigation-enabled", true, +#endif +#endif + nullptr))); + if (!context) { + error = "Failed to create GLib ephemeral context"_s; + return nullptr; + } + +#if ENABLE(2022_GLIB_API) + 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()); +#endif + + 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, WTFMove(context)); + + if (!proxyServer.isEmpty()) { + WebCore::SoupNetworkProxySettings contextProxySettings = parseProxySettings(proxyServer, proxyBypassList); + browserContext->dataStore->setNetworkProxySettings(WTFMove(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 = WTFMove(clip), nominalResolution, completionHandler = WTFMove(completionHandler)]() mutable { +#if PLATFORM(GTK) + RefPtr viewSnapshot = protectedPage->pageClient()->takeViewSnapshot(WTFMove(clip), nominalResolution); + if (viewSnapshot) { + std::optional data = WebAutomationSession::platformGetBase64EncodedPNGData(*viewSnapshot); + if (data) { + completionHandler(emptyString(), makeString("data:image/png;base64,"_s, *data)); + return; + } + } +#elif PLATFORM(WPE) +#if USE(SKIA) + sk_sp protectPtr = protectedPage->pageClient()->takeViewSnapshot(WTFMove(clip), nominalResolution); + SkImage* surface = protectPtr.get(); +#elif USE(CAIRO) + cairo_surface_t* surface = nullptr; + RefPtr protectPtr = protectedPage->pageClient()->takeViewSnapshot(WTFMove(clip), nominalResolution); + surface = protectPtr.get(); +#endif + if (surface) { + Vector encodeData = WebCore::encodeData(surface, "image/png"_s, std::nullopt); + completionHandler(emptyString(), makeString("data:image/png;base64,"_s, base64Encoded(encodeData))); + 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..441442d899e4088f5c24ae9f70c3e4ffa1e6d340 --- /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_MAKE_FAST_ALLOCATED; +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/SystemSettingsManagerProxy.cpp b/Source/WebKit/UIProcess/glib/SystemSettingsManagerProxy.cpp index c6e25e57892c2a0e1350b207ce53b6d2c3d6258a..bd91f75db5a05ba0a6f5a982c03980ecc57479ca 100644 --- a/Source/WebKit/UIProcess/glib/SystemSettingsManagerProxy.cpp +++ b/Source/WebKit/UIProcess/glib/SystemSettingsManagerProxy.cpp @@ -27,6 +27,7 @@ #include "config.h" #include "SystemSettingsManagerProxy.h" +#include "SystemSettingsManager.h" #include "SystemSettingsManagerMessages.h" #include "WebProcessPool.h" #include diff --git a/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp b/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp index 51ba8b585ca37a2eed54bce5218e1c92c2844cc6..dc04a2ca0b0ac2333036b897dd18d5303c5237c6 100644 --- a/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp +++ b/Source/WebKit/UIProcess/glib/WebProcessPoolGLib.cpp @@ -124,6 +124,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.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h index 5529f52048b24290f424e877cd9dbfb890e02ffb..c2b76b6188dd9596c4a1f31c137daff7d7644c7f 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h @@ -32,6 +32,7 @@ #include typedef struct _cairo cairo_t; +typedef struct _cairo_surface cairo_surface_t; #if USE(GTK4) typedef struct _GdkSnapshot GdkSnapshot; @@ -62,6 +63,8 @@ public: #else virtual bool paint(cairo_t*, const WebCore::IntRect&) = 0; #endif + virtual cairo_surface_t* surface() { return nullptr; } + virtual void realize() { }; virtual void unrealize() { }; virtual int renderHostFileDescriptor() { return -1; } diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp index 395a409b6302d4146606fc0b45a15cff63c7f327..666d9629e0155e8c03b0672f7a9274de7f04d642 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp @@ -812,4 +812,30 @@ RefPtr AcceleratedBackingStoreDMABuf::bufferAsNativeImageF return m_committedBuffer->asNativeImageForTesting(); } +// Playwright begin +cairo_surface_t* AcceleratedBackingStoreDMABuf::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/AcceleratedBackingStoreDMABuf.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h index 63dfbed03bd898c822d426a5449141fec2841226..eaf141843da3f02c5ba6fd0322f3175248a7195b 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h @@ -98,6 +98,7 @@ private: #else bool paint(cairo_t*, const WebCore::IntRect&) override; #endif + cairo_surface_t* surface() override; void unrealize() override; void update(const LayerTreeContext&) override; RendererBufferFormat bufferFormat() const override; @@ -253,6 +254,9 @@ 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..bf78de1915940c2d3292514cf0fe4e682b636f70 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp @@ -0,0 +1,48 @@ +/* + * 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 +#include + +namespace WebKit { + +void InspectorTargetProxy::platformActivate(String& error) const +{ +#if USE(GTK4) + GtkWidget* parent = GTK_WIDGET(gtk_widget_get_root(m_page->viewWidget())); +#else + GtkWidget* parent = gtk_widget_get_toplevel(m_page->viewWidget()); +#endif + 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/SystemSettingsManagerProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp index 9ef483a6b0ab1558c059304d727311ea7984184d..f532d2d2dbe2d7cb66323b6ea5fe2daace15d7b8 100644 --- a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp +++ b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp @@ -126,6 +126,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..7d9672b0f831b5b7f6acf14ede26e1e8e9a65389 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp @@ -0,0 +1,117 @@ +/* + * 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 +#include + +namespace WebKit { + +#if USE(GTK4) +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; +} +#endif + +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); +#if USE(GTK4) + // 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 righ await to not stall. + if (!viewAllocation.width && !viewAllocation.height && windowHasManyTabs(viewWidget)) { + callback(String()); + return; + } +#endif + 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; + // The callback can only be called if the page is still alive, so we can safely capture `this`. + drawingArea->waitForSizeUpdate([this, callback = WTFMove(callback), didNotHaveInitialAllocation, viewSize](const DrawingAreaProxyCoordinatedGraphics& drawingArea) mutable { +#if USE(GTK4) + 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(), WTFMove(callback)); + return; + } + callback("Failed to resize window"_s); +#else + UNUSED_PARAM(this); + UNUSED_PARAM(didNotHaveInitialAllocation); + UNUSED_PARAM(drawingArea); + callback(String()); +#endif + }); + } else { + callback("No backing store for window"_s); + } +#if USE(GTK4) + // 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); +#else + gtk_window_resize(GTK_WINDOW(window), width, height); +#endif +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36ab6e9aec9f8d79fb13a8a49beadaafb3da58f5 --- /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, WallTime timestamp) +{ + Vector commands; + const guint keyVal = WebCore::PlatformKeyboardEvent::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, + WTFMove(commands)); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp index cedf117035055756084863d1e8db8594e4a8b8d2..bae8c9d90d1f34324bbb98a52815af98d23e5257 100644 --- a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp +++ b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp @@ -78,8 +78,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/InspectorPlaywrightAgentClientMac.h b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h new file mode 100644 index 0000000000000000000000000000000000000000..2aabc02a4b5432f68a6e85fd9689775608f05a67 --- /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_MAKE_FAST_ALLOCATED; +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..a4b23bf4cf7c4cb6ef9d25d4121b20a611809479 --- /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 = WTFMove(clipRect), completionHandler = WTFMove(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::dataURL(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 8fc87c386fd82cdedc06ad1601d76919c6c27467..b5b2833b603e6996cf18c3416fde156940378f31 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.h +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.h @@ -61,6 +61,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(); @@ -176,6 +178,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; @@ -229,6 +234,10 @@ private: void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame, CompletionHandler&&) override; #endif +#if ENABLE(TOUCH_EVENTS) + void doneWithTouchEvent(const NativeWebTouchEvent&, 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 5a5366f3f439d4727ca7dab149e0a523ccc27ce2..e02ab71cdf13af0d9b7b1aa04667c1dce54ed340 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm @@ -110,6 +110,13 @@ namespace WebKit { using namespace WebCore; +static bool _headless = false; + +// static +void PageClientImpl::setHeadless(bool headless) { + _headless = headless; +} + PageClientImpl::PageClientImpl(NSView *view, WKWebView *webView) : PageClientImplCocoa(webView) , m_view(view) @@ -163,6 +170,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()); @@ -170,6 +180,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 (!m_impl) @@ -193,6 +206,9 @@ void PageClientImpl::makeFirstResponder() bool PageClientImpl::isViewVisible() { + if (_headless) + return true; + RetainPtr activeView = this->activeView(); RetainPtr activeViewWindow = activeWindow(); @@ -267,7 +283,8 @@ void PageClientImpl::didRelaunchProcess() void PageClientImpl::preferencesDidChange() { - m_impl->preferencesDidChange(); + if (m_impl) + m_impl->preferencesDidChange(); } void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip) @@ -475,6 +492,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { + if (!event.nativeEvent()) + return; m_impl->doneWithKeyEvent(event.nativeEvent(), eventWasHandled); } @@ -494,6 +513,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl RefPtr PageClientImpl::createPopupMenuProxy(WebPageProxy& page) { + if (_headless) + return nullptr; return WebPopupMenuProxyMac::create(m_view.get().get(), page.popupMenuClient()); } @@ -634,6 +655,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 m_impl->takeViewSnapshot(); @@ -850,6 +877,13 @@ void PageClientImpl::beganExitFullScreen(const IntRect& initialFrame, const IntR #endif // ENABLE(FULLSCREEN_API) +#if ENABLE(TOUCH_EVENTS) +void PageClientImpl::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled) +{ + notImplemented(); +} +#endif // ENABLE(TOUCH_EVENTS) + void PageClientImpl::navigationGestureDidBegin() { m_impl->dismissContentRelativeChildWindowsWithAnimation(true); @@ -1030,6 +1064,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event) { + // Simulated event. + if (!event.nativeEvent()) + return false; return m_impl->windowIsFrontWindowUnderMouse(event.nativeEvent()); } diff --git a/Source/WebKit/UIProcess/mac/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/WebContextMenuProxyMac.h b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h index a3c53c0bf913385d4d2d92900360d5f7d75927f8..e5570ef599ff1b59224648c353f8ab16f8fe7f88 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h @@ -81,6 +81,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 4cee7041f9b93d553b452447b33459832a5e4e36..2d5d79246c57be84ebf86f3935cd4583bf0cecdc 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm @@ -540,6 +540,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..dd52991f936aa1c046b404801ee97237d0a55748 --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm @@ -0,0 +1,135 @@ +/* + * 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 = NSEventTypeLeftMouseDragged; + 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; + } + + NativeWebMouseEvent nativeEvent(event, nil, [window contentView]); + 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, WallTime 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, [] () { })) + m_page.websiteDataStore().protectedNetworkProcess()->connection().waitForAsyncReplyAndDispatchImmediately(*replyID, 100_ms); + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp, + WTFMove(macCommands)); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.h b/Source/WebKit/UIProcess/mac/WebViewImpl.h index a0e1fc432a9b4b8938051d39725a1ec36ebd7a1b..f2a331f460879e43e9b069f50a099f10bbf8b8d8 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.h +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.h @@ -35,6 +35,7 @@ #include "WKLayoutMode.h" #include "WKTextAnimationType.h" #include +#include #include #include #include @@ -569,6 +570,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 1b42ae3cb6cdabee9830a1fb2ff55b9ae2325eb4..6998642cf147ec1af6e3feeb66d8688381791214 100644 --- a/Source/WebKit/UIProcess/mac/WebViewImpl.mm +++ b/Source/WebKit/UIProcess/mac/WebViewImpl.mm @@ -2462,6 +2462,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] }; @@ -4707,6 +4712,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/win/InspectorPlaywrightAgentClientWin.cpp b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f54a9445e5a7ecdb750c5c521da4f397776e633 --- /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(WTFMove(proxyURL), String(proxyBypassList)); + browserContext->dataStore->setNetworkProxySettings(WTFMove(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..df18883b2b7d22d73540cb084d3dd5291231097d --- /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_MAKE_FAST_ALLOCATED; +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/WebContextMenuProxyWin.cpp b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp index bae35256ed815f7dac0b11ae439531d4ef3cb108..81e063b50a0132f8b36f3461f95d2ce1968198f5 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp +++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp @@ -115,5 +115,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 e7f71156d7a897ab477d0d7f167b2c2992cdb161..325d8813afff13d86a4892a8e99738f19c2729ac 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h +++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h @@ -49,6 +49,7 @@ public: private: WebContextMenuProxyWin(WebPageProxy&, FrameInfoData&&, ContextMenuContextData&&, const UserData&); void showContextMenuWithItems(Vector>&&) override; + void hide() override; HMENU m_menu; FrameInfoData m_frameInfo; 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..8b474c730139b44a13c9d5b2d13ee20403e3e7f3 --- /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, WallTime 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 5180da3ec22d56e8a9520e31cad076d86ae5be9f..f01be74573843e7b374c34035c09f114bdc7349c 100644 --- a/Source/WebKit/UIProcess/win/WebView.cpp +++ b/Source/WebKit/UIProcess/win/WebView.cpp @@ -576,7 +576,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/InspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24da079059ed4a45131e18d7fbf56a29a54bd513 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.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 "InspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include + +namespace WebKit { + +void InspectorTargetProxy::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..7df77e30c2e7303dc6aaad560434e5b8e35f4f3c --- /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) +{ + return adoptRef(*new WebColorPickerWPE(page, initialColor, rect)); +} + +WebColorPickerWPE::WebColorPickerWPE(WebPageProxy& page, const Color& initialColor, const IntRect&) + : WebColorPicker(&page.colorPickerClient()) +{ +} + +WebColorPickerWPE::~WebColorPickerWPE() +{ + endPicker(); +} + +void WebColorPickerWPE::endPicker() +{ +} + +void WebColorPickerWPE::showColorPicker(const Color& color) +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h new file mode 100644 index 0000000000000000000000000000000000000000..da58334235809cfed62e90150784bf2506f7a8f2 --- /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&); + virtual ~WebColorPickerWPE(); + + void endPicker() override; + void showColorPicker(const WebCore::Color&) override; + +protected: + WebColorPickerWPE(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&); +}; + +} // 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..694eb24db4a407553da12fb0a25d8963fd0ef6ac --- /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::show(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..5d4b0d204b7dc564564d2126e9f256fa4f4bd6f6 --- /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 show(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..182398f24909cbc42cac897d66546991f46c1d5d --- /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 = WTFMove(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..a7d88f8c745f95af21db71dcfce368ba4832a328 --- /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, WallTime 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 07fb026a2a1ee93222d022a603b0057efbf848de..bedb13e953248741f32c61f8476e021233ce7e40 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj @@ -1546,6 +1546,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 */; }; @@ -2328,6 +2329,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 /* InspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.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, ); }; }; @@ -2427,6 +2440,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 */; }; @@ -2456,6 +2471,9 @@ EEA52F492D7055A700D578B5 /* WKStageMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE0D3CDC2D3709BE00072978 /* WKStageMode.swift */; }; EEFE72792D64FE5600DC6214 /* StageModeInteractionState.h in Headers */ = {isa = PBXBuildFile; fileRef = EEFE72782D64FE5600DC6214 /* StageModeInteractionState.h */; }; F404455C2D5CFB56000E587E /* AppKitSoftLink.h in Headers */ = {isa = PBXBuildFile; fileRef = F404455A2D5CFB56000E587E /* AppKitSoftLink.h */; }; + F303B849249A8D640031DE5C /* ScreencastEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = F303B848249A8D3A0031DE5C /* ScreencastEncoder.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, ); }; }; @@ -6365,6 +6383,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 = ""; }; @@ -8090,6 +8109,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 /* InspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorTargetProxyMac.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 = ""; }; @@ -8263,6 +8295,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 = ""; }; EB0D312D275AE13300863D8F /* com.apple.webkit.webpushd.mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.webkit.webpushd.mac.plist; sourceTree = ""; }; EB0D312E275AE13300863D8F /* com.apple.webkit.webpushd.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.webkit.webpushd.ios.plist; sourceTree = ""; }; @@ -8305,6 +8339,14 @@ 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 = ""; }; + F303B847249A8D3A0031DE5C /* ScreencastEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScreencastEncoder.cpp; sourceTree = ""; }; + F303B848249A8D3A0031DE5C /* ScreencastEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreencastEncoder.h; sourceTree = ""; }; + F31E2DA424C76E4B004B2775 /* WebMFileWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebMFileWriter.cpp; sourceTree = ""; }; + F31E2DA524C76E4C004B2775 /* WebMFileWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMFileWriter.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 = ""; }; + F3970344249BD4CE003E1A22 /* ScreencastEncoderMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreencastEncoderMac.mm; 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; name = WKDatePickerPopoverController.h; path = ios/forms/WKDatePickerPopoverController.h; sourceTree = ""; }; F40C3B702AB40167007A3567 /* WKDatePickerPopoverController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKDatePickerPopoverController.mm; path = ios/forms/WKDatePickerPopoverController.mm; sourceTree = ""; }; @@ -8710,6 +8752,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 */, @@ -11841,6 +11884,7 @@ 99788ACA1F421DCA00C08000 /* _WKAutomationSessionConfiguration.mm */, 990D28A81C6404B000986977 /* _WKAutomationSessionDelegate.h */, 990D28AF1C65203900986977 /* _WKAutomationSessionInternal.h */, + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */, 5C4609E222430E4C009943C2 /* _WKContentRuleListAction.h */, 5C4609E322430E4D009943C2 /* _WKContentRuleListAction.mm */, 5C4609E422430E4D009943C2 /* _WKContentRuleListActionInternal.h */, @@ -13218,6 +13262,7 @@ E34B110C27C46BC6006D2F2E /* libWebCoreTestShim.dylib */, E34B110F27C46D09006D2F2E /* libWebCoreTestSupport.dylib */, DDE992F4278D06D900F60D26 /* libWebKitAdditions.a */, + F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */, 57A9FF15252C6AEF006A2040 /* libWTF.a */, 5750F32A2032D4E500389347 /* LocalAuthentication.framework */, 570DAAB0230273D200E8FC04 /* NearField.framework */, @@ -13799,6 +13844,12 @@ children = ( 9197940423DBC4BB00257892 /* InspectorBrowserAgent.cpp */, 9197940323DBC4BB00257892 /* InspectorBrowserAgent.h */, + F3867F0324607D2B008F0F31 /* InspectorScreencastAgent.cpp */, + F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */, + F303B847249A8D3A0031DE5C /* ScreencastEncoder.cpp */, + F303B848249A8D3A0031DE5C /* ScreencastEncoder.h */, + F31E2DA424C76E4B004B2775 /* WebMFileWriter.cpp */, + F31E2DA524C76E4C004B2775 /* WebMFileWriter.h */, ); path = Agents; sourceTree = ""; @@ -13807,6 +13858,7 @@ isa = PBXGroup; children = ( A5D3504D1D78F0D2005124A9 /* RemoteWebInspectorUIProxyMac.mm */, + F3970344249BD4CE003E1A22 /* ScreencastEncoderMac.mm */, 1CA8B935127C774E00576C2B /* WebInspectorUIProxyMac.mm */, 99A7ACE326012919006D57FD /* WKInspectorResourceURLSchemeHandler.h */, 99A7ACE42601291A006D57FD /* WKInspectorResourceURLSchemeHandler.mm */, @@ -14560,6 +14612,7 @@ E1513C65166EABB200149FCB /* AuxiliaryProcessProxy.h */, 46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */, 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */, + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */, 5C6D69352AC3935D0099BDAF /* BrowsingContextGroup.cpp */, 5C6D69362AC3935D0099BDAF /* BrowsingContextGroup.h */, 5CA98549210BEB5A0057EB6B /* BrowsingWarning.h */, @@ -14584,6 +14637,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 */, @@ -14613,6 +14668,7 @@ 4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */, 4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */, 411B89CB27B2B89600F9EBD3 /* QueryPermissionResultCallback.h */, + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */, 5CCB54DC2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.cpp */, 5CCB54DB2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.h */, FABBBC802D35AC6800820017 /* RemotePageFullscreenManagerProxy.cpp */, @@ -14716,6 +14772,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 */, @@ -14894,6 +14952,7 @@ BC646C1911DD399F006455B0 /* WKBackForwardListItemRef.h */, BC646C1611DD399F006455B0 /* WKBackForwardListRef.cpp */, BC646C1711DD399F006455B0 /* WKBackForwardListRef.h */, + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */, BCB9E24A1120E15C00A137E0 /* WKContext.cpp */, BCB9E2491120E15C00A137E0 /* WKContext.h */, 1AE52F9319201F6B00A1FA37 /* WKContextConfigurationRef.cpp */, @@ -15468,6 +15527,9 @@ 07EF07592745A8160066EA04 /* DisplayCaptureSessionManager.h */, 07EF07582745A8160066EA04 /* DisplayCaptureSessionManager.mm */, 7AFA6F682A9F57C50055322A /* DisplayLinkMac.cpp */, + D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */, + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */, + D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */, 1AFDE65B1954E8D500C48FFA /* LegacySessionStateCoding.cpp */, 0FCB4E5818BBE3D9000FCFC9 /* PageClientImplMac.h */, 0FCB4E5918BBE3D9000FCFC9 /* PageClientImplMac.mm */, @@ -15491,6 +15553,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 */, @@ -16577,6 +16641,7 @@ 99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */, 990D28AC1C6420CF00986977 /* _WKAutomationSessionDelegate.h in Headers */, 990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */, + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */, 5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */, 5C4609E8224317BB009943C2 /* _WKContentRuleListActionInternal.h in Headers */, 9B4CE9512CD99B7C00351173 /* _WKContentWorldConfiguration.h in Headers */, @@ -16885,6 +16950,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 */, @@ -17067,7 +17133,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 */, C5BCE5DF1C50766A00CDE3FA /* InteractionInformationAtPosition.h in Headers */, 2D4D2C811DF60BF3002EB10C /* InteractionInformationRequest.h in Headers */, @@ -17328,6 +17398,7 @@ 0F6E7C532C4C386800F1DB85 /* RemoteDisplayListRecorderMessages.h in Headers */, F451C0FE2703B263002BA03B /* RemoteDisplayListRecorderProxy.h in Headers */, A78A5FE42B0EB39E005036D3 /* RemoteImageBufferSetIdentifier.h in Headers */, + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */, 2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */, 2DDF731518E95060004F5A66 /* RemoteLayerBackingStoreCollection.h in Headers */, 1AB16AEA164B3A8800290D62 /* RemoteLayerTreeContext.h in Headers */, @@ -17384,6 +17455,7 @@ E1E552C516AE065F004ED653 /* SandboxInitializationParameters.h in Headers */, E36FF00327F36FBD004BE21A /* SandboxStateVariables.h in Headers */, 7BAB111025DD02B3008FC479 /* ScopedActiveMessageReceiveQueue.h in Headers */, + F303B849249A8D640031DE5C /* ScreencastEncoder.h in Headers */, 6D4DF20C2D824242001F964C /* ScreenTimeWebsiteDataSupport.h in Headers */, 463BB93A2B9D08D80098C5C3 /* ScriptMessageHandlerIdentifier.h in Headers */, F4E28A362C923814008120DD /* ScriptTelemetry.h in Headers */, @@ -17745,6 +17817,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 */, A543E30C215C8A8D00279CD9 /* WebPageInspectorTarget.h in Headers */, A543E30D215C8A9000279CD9 /* WebPageInspectorTargetController.h in Headers */, A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */, @@ -20348,7 +20422,43 @@ 522F792928D50EBB0069B45B /* HidService.mm in Sources */, 2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */, 2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */, + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */, + D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */, + 1CC94E532AC92F190045F269 /* JSWebExtensionAPIAction.mm in Sources */, + 1C2B4D4B2A819D0D00C528A1 /* JSWebExtensionAPIAlarms.mm in Sources */, + 1C8ECFEA2AFC7DCB007BAA62 /* JSWebExtensionAPICommands.mm in Sources */, + 1C40052C2B2B953D00F2D9EE /* JSWebExtensionAPICookies.mm in Sources */, + 331102402B17B99800B21C8C /* JSWebExtensionAPIDeclarativeNetRequest.mm in Sources */, + 1C517F452B74393C00C46EDC /* JSWebExtensionAPIDevTools.mm in Sources */, + 1C517F432B74393C00C46EDC /* JSWebExtensionAPIDevToolsExtensionPanel.mm in Sources */, + 1C517F472B74393C00C46EDC /* JSWebExtensionAPIDevToolsInspectedWindow.mm in Sources */, + 1C517F462B74393C00C46EDC /* JSWebExtensionAPIDevToolsNetwork.mm in Sources */, + 1C517F412B74393C00C46EDC /* JSWebExtensionAPIDevToolsPanels.mm in Sources */, + B6114A7F29394A1600380B1B /* JSWebExtensionAPIEvent.mm in Sources */, + 1C5DC471290B33A20061EC62 /* JSWebExtensionAPIExtension.mm in Sources */, + B6CCAAB929A445E90092E846 /* JSWebExtensionAPILocalization.mm in Sources */, + 1CCEE4532B0989FC0034E059 /* JSWebExtensionAPIMenus.mm in Sources */, + 1C5DC4552908AC900061EC62 /* JSWebExtensionAPINamespace.mm in Sources */, + 1C386F362AF409F9004108F0 /* JSWebExtensionAPINotifications.mm in Sources */, + B61AFA4929510D0F008220B1 /* JSWebExtensionAPIPermissions.mm in Sources */, + 1C9A15CF2ABDF1E2002CC12A /* JSWebExtensionAPIPort.mm in Sources */, + 1C5DC472290B33A60061EC62 /* JSWebExtensionAPIRuntime.mm in Sources */, + B63E9A6F2AAF2B2D005F4561 /* JSWebExtensionAPIScripting.mm in Sources */, + 029D6BB22C407AA30068CF99 /* JSWebExtensionAPISidebarAction.mm in Sources */, + 029D6BB12C407AA30068CF99 /* JSWebExtensionAPISidePanel.mm in Sources */, + B63C10342B51C0B6004A69B8 /* JSWebExtensionAPIStorage.mm in Sources */, + B63C10372B51C102004A69B8 /* JSWebExtensionAPIStorageArea.mm in Sources */, + 1C5ACFAB2A96F8D500C041C0 /* JSWebExtensionAPITabs.mm in Sources */, + 1C15497F2926C073001B9E5B /* JSWebExtensionAPITest.mm in Sources */, 1C0F05BE2CFA5D2E007D1F62 /* JSWebExtensionAPIUnified.mm in Sources */, + 3375A3772942A19D0028536D /* JSWebExtensionAPIWebNavigation.mm in Sources */, + 33F68338293FF6F5005C63C0 /* JSWebExtensionAPIWebNavigationEvent.mm in Sources */, + B63A99772B7EA002004611FD /* JSWebExtensionAPIWebPageNamespace.mm in Sources */, + B63A99782B7EA002004611FD /* JSWebExtensionAPIWebPageRuntime.mm in Sources */, + 3399E1532B59EFD7008BFB60 /* JSWebExtensionAPIWebRequest.mm in Sources */, + 337042022B58A0B70077FF78 /* JSWebExtensionAPIWebRequestEvent.mm in Sources */, + 1C5ACFA62A96F8C400C041C0 /* JSWebExtensionAPIWindows.mm in Sources */, + 1C5ACFA72A96F8C400C041C0 /* JSWebExtensionAPIWindowsEvent.mm in Sources */, 1C5DC45F2909B05A0061EC62 /* JSWebExtensionWrapperCocoa.mm in Sources */, C14D37FE24ACE086007FF014 /* LaunchServicesDatabaseManager.mm in Sources */, C1710CF724AA643200D7C112 /* LaunchServicesDatabaseObserver.mm in Sources */, @@ -20746,6 +20856,8 @@ 074E87E12CF8EA3D0059E469 /* WebPage+NavigationDeciding.swift in Sources */, 078B04A02CF18EAB00B453A6 /* WebPage+NavigationPreferences.swift in Sources */, 07CB79962CE9435700199C49 /* WebPage.swift in Sources */, + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */, + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */, 7CE9CE101FA0767A000177DE /* WebPageUpdatePreferences.cpp in Sources */, 079A4DA12D72CC0D00CA387F /* WebPageWebView.swift in Sources */, 7CEB00DD1FA69ABE0065473B /* WebPreferencesFeatures.cpp in Sources */, diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp index ae80809efafab3264b06e7bac45771c72d4408b8..849694aea1738dac5e2a0741f31def13c34c8608 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp @@ -269,6 +269,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } #endif + if (m_emulateOfflineState) { + scheduleInternallyFailedLoad(resourceLoader); + return; + } + #if ENABLE(PDFJS) if (tryLoadingUsingPDFJSHandler(resourceLoader, trackingParameters)) return; @@ -283,12 +288,16 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } if (InspectorInstrumentationWebKit::shouldInterceptRequest(resourceLoader)) { - InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedThis = Ref { *this }, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, 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](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(WEBLOADERSTRATEGY_SCHEDULELOAD); @@ -413,7 +422,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(); @@ -425,10 +434,10 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL && resourceLoader.frameLoader()->notifier().isInitialRequestIdentifier(identifier) ? MainFrameMainResource::Yes : MainFrameMainResource::No; if (!page->allowsLoadFromURL(request.url(), mainFrameMainResource)) { - RunLoop::protectedMain()->dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] { + RunLoop::protectedMain()->dispatch([resourceLoader = Ref { resourceLoader }, error = platformStrategies()->loaderStrategy()->blockedError(request)] { resourceLoader->didFail(error); }); - return; + return false; } } @@ -438,14 +447,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 - }; - loadParameters.createSandboxExtensionHandlesIfNecessary(); - loadParameters.identifier = identifier; loadParameters.parentPID = legacyPresentingApplicationPID(); loadParameters.contentSniffingPolicy = contentSniffingPolicy; @@ -529,14 +530,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) @@ -583,6 +581,25 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL if (RefPtr frameLoader = resourceLoader.frameLoader()) loadParameters.requiredCookiesVersion = frameLoader->requiredCookiesVersion(); + 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 + }; + loadParameters.createSandboxExtensionHandlesIfNecessary(); + + 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); @@ -597,7 +614,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } auto loader = WebResourceLoader::create(resourceLoader, trackingParameters); - m_webResourceLoaders.set(identifier, WTFMove(loader)); + m_webResourceLoaders.set(*resourceLoader.identifier(), WTFMove(loader)); } void WebLoaderStrategy::scheduleInternallyFailedLoad(WebCore::ResourceLoader& resourceLoader) @@ -1015,7 +1032,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier bool WebLoaderStrategy::isOnLine() const { - return m_isOnLine; + return m_emulateOfflineState ? false : m_isOnLine; } void WebLoaderStrategy::addOnlineStateChangeListener(Function&& listener) @@ -1042,6 +1059,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet void WebLoaderStrategy::setOnLineState(bool isOnLine) { + if (m_emulateOfflineState) { + m_isOnLine = isOnLine; + return; + } + if (m_isOnLine == isOnLine) return; @@ -1050,6 +1072,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 6492031de6ed6effab3f28e5321419f3390f7651..678139fc26f26e2224a70b0087ddb849280b8ace 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 @@ -96,6 +97,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; } @@ -164,6 +168,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 9add95853b90e6cae9dd4627ab8bf9a9006bc7a8..f3af1c6680d1dc6d8f6db951a26a526d7079cd95 100644 --- a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp +++ b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp @@ -202,9 +202,6 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR coreLoader->didReceiveResponse(inspectorResponse, [this, protectedThis = Ref { *this }, interceptedRequestIdentifier, policyDecisionCompletionHandler = WTFMove(policyDecisionCompletionHandler), overrideData = WTFMove(overrideData)]() mutable { RefPtr coreLoader = m_coreLoader; - if (policyDecisionCompletionHandler) - policyDecisionCompletionHandler(); - if (!m_coreLoader || !coreLoader->identifier()) { m_interceptController.continueResponse(interceptedRequestIdentifier); return; @@ -221,6 +218,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 e532ffcbe13d86fa0de4fbb2c63214615539ba2d..77cf20de73c57756eea1c10349fa666ce733b304 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp @@ -491,6 +491,8 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev { // Notify the bundle client. auto page = protectedPage(); + if (level == MessageLevel::Error) + page->send(Messages::WebPageProxy::LogToStderr(message)); // FIXME: Remove this after rdar://143399667 is fixed. page->injectedBundleUIClient().willAddMessageToConsole(page.ptr(), source, level, message, lineNumber, columnNumber, sourceID); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp index dd03326b1ad54e1d363d722cfe86bb779fbeead1..f54d631dc4034c995cbd74ec6b545c3c7dd25990 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->allowedDragSourceActions(); } -#if !PLATFORM(COCOA) && !PLATFORM(GTK) +#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE) && !PLATFORM(WIN) void WebDragClient::startDrag(DragItem, DataTransfer&, Frame&) { } diff --git a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm index 6bd8b7c5de08a061c0a155f4783affe9050b8103..610f2b7870588de14f6b658967a9f9acb1a01baa 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm +++ b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm @@ -128,7 +128,8 @@ static WebCore::CachedImage* 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; WebCore::CachedImage* 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..66972b66094050b2429a927861ff7d0d30925ef0 --- /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 "ArgumentCodersWPE.h" +#include "MessageSenderInlines.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include +#include +#include +#include +#include + +//#include + +namespace WebKit { +using namespace WebCore; + +void WebDragClient::didConcludeEditDrag() +{ +} + +void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame& frame) +{ + m_page->willStartDrag(); + m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().createDragDataMap())); +} + +}; // namespace WebKit. + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp b/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..226b3bf6bd83d2606a0aeb627ae9302fd3bcf874 --- /dev/null +++ b/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp @@ -0,0 +1,56 @@ +/* + * 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 "WebPage.h" +#include "WebPageProxyMessages.h" +#include +#include +#include +#include +#include + +namespace WebKit { +using namespace WebCore; + +void WebDragClient::didConcludeEditDrag() +{ +} + +void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame&) +{ + m_page->willStartDrag(); + + std::optional handle; + m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().selectionData(), dataTransfer.sourceOperationMask(), WTFMove(handle), dataTransfer.dragLocation())); +} + +}; // namespace WebKit. + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp index ac7fa01ba9a3828cf4c48cacc862aab95145093e..89414a407a49d30b937f26cd9cd570c59c51aab3 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp @@ -39,6 +39,7 @@ #include "WebPreferencesKeys.h" #include "WebProcess.h" #include +#include #include #include #include diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h index 2b955369c53a76ca65613a549bff0d490db48a4c..f67651d2cc64a7f164ff91ad5f613a661976bdbb 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h @@ -138,6 +138,7 @@ public: #if PLATFORM(WPE) && USE(GBM) && ENABLE(WPE_PLATFORM) void preferredBufferFormatsDidChange(); #endif + private: void updateRootLayer(); WebCore::FloatRect visibleContentsRect() const; diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp index c07ca9e847d03c27877cf650b67b96b3c3f7bddb..b966edc8778d4a68c6e5bae0c0883ab3bfd0a387 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 70a6c3c9ed0fcf42393df2c0fb66eb50d290030d..06fb88ca78db70de4bd4ed9cdf33172bee1a958e 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +446,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 f9c1d07d4e1f4b5421a627a179ed4f86cf1a1b92..9a8089ed85eebbfb8af0804dfbc0698bcb5993d6 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h @@ -77,6 +77,8 @@ public: void clearCache() final; + void setCookieFromResponse(WebCore::ResourceLoader&, const String& setCookieValue); + #if HAVE(ALLOW_ONLY_PARTITIONED_COOKIES) void setOptInCookiePartitioningEnabled(bool); #endif diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index 4f0c774675bcc9adc7fddd608953bde8840e30dd..224289ffe67a7e16f93d8373eb573849dfb38b06 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -243,6 +243,7 @@ #include #include #include +#include #include #include #include @@ -1152,6 +1153,12 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) setLinkDecorationFilteringData(WTFMove(parameters.linkDecorationFilteringData)); setAllowedQueryParametersForAdvancedPrivacyProtections(WTFMove(parameters.allowedQueryParametersForAdvancedPrivacyProtections)); #endif + // 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 ? InspectorController::PauseCondition::WHEN_CREATION_FINISHED : InspectorController::PauseCondition::WHEN_SHOWN); if (parameters.windowFeatures) { page->applyWindowFeatures(*parameters.windowFeatures); page->chrome().show(); @@ -2094,6 +2101,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(), loadParameters.request }; + frame->coreLocalFrame()->loader().load(WTFMove(frameLoadRequest)); + ASSERT(!m_pendingFrameNavigationID); +} + void WebPage::loadRequest(LoadParameters&& loadParameters) { WEBPAGE_RELEASE_LOG_FORWARDABLE(Loading, WEBPAGE_LOADREQUEST, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), loadParameters.existingNetworkResourceLoadIdentifierToResume ? loadParameters.existingNetworkResourceLoadIdentifierToResume->toUInt64() : 0); @@ -2290,7 +2313,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 @@ -2866,7 +2891,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; @@ -3623,6 +3648,13 @@ void WebPage::flushDeferredScrollEvents() protectedCorePage()->flushDeferredScrollEvents(); } +#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)) @@ -3884,6 +3916,97 @@ 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::IntSize radius(radiusX,radiusY); + const WebCore::IntPoint 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, WallTime::now()}, WTFMove(touchPoints), {}, {}); + + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(m_page->mainFrame().frameID(), touchEvent, m_page.get()).wasHandled(); + } + { + Vector touchPoints; + WebPlatformTouchPoint::State state = WebPlatformTouchPoint::State::Released; + touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force)); + + WebTouchEvent touchEvent({WebEventType::TouchEnd, eventModifiers, WallTime::now()}, WTFMove(touchPoints), {}, {}); + + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(m_page->mainFrame().frameID(), touchEvent, m_page.get()).wasHandled() || handled; + } + if (!handled) { + FloatPoint adjustedPoint; + + auto* localMainFrame = dynamicDowncast(m_page->mainFrame()); + if (!localMainFrame) + return; + + Node* 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, + WallTime::now(), + force, + syntheticClickType + )); + localMainFrame->eventHandler().handleMousePressEvent(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::Left, + PlatformEvent::Type::MousePressed, + 1, + modifiers, + WallTime::now(), + force, + syntheticClickType + )); + localMainFrame->eventHandler().handleMouseReleaseEvent(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::Left, + PlatformEvent::Type::MouseReleased, + 1, + modifiers, + WallTime::now(), + force, + syntheticClickType + )); + } + completionHandler(); +} #endif void WebPage::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint) @@ -3972,6 +4095,16 @@ void WebPage::sendMessageToTargetBackend(const String& targetId, const String& m m_inspectorTargetController->sendMessageToTargetBackend(targetId, message); } +void WebPage::resumeInspectorIfPausedInNewWindow() +{ + m_page->inspectorController().resumeIfPausedInNewWindow(); +} + +void WebPage::didAddWebPageToWebProcess() +{ + m_page->inspectorController().didFinishPageCreation(); +} + void WebPage::insertNewlineInQuotedContent() { RefPtr frame = protectedCorePage()->checkedFocusController()->focusedOrMainFrame(); @@ -4215,6 +4348,7 @@ void WebPage::setMainFrameDocumentVisualUpdatesAllowed(bool allowed) void WebPage::show() { send(Messages::WebPageProxy::ShowPage()); + m_page->inspectorController().didShowPage(); } void WebPage::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension) @@ -5426,7 +5560,7 @@ RefPtr WebPage::protectedNotificationPermi #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) @@ -7913,6 +8047,10 @@ void WebPage::didCommitLoad(WebFrame* frame) m_needsFixedContainerEdgesUpdate = true; flushDeferredDidReceiveMouseEvent(); +// Playwright begin + if (frame->isMainFrame()) + send(Messages::WebPageProxy::ViewScaleFactorDidChange(viewScaleFactor())); +// Playwright end } void WebPage::didFinishDocumentLoad(WebFrame& frame) @@ -8222,6 +8360,9 @@ Ref WebPage::createDocumentLoader(LocalFrame& frame, const Resou 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 8bd2bc55df904c4d23bf47d38981581faf89b2af..c0f2d51469875510b65b252b2ba4c15ef252b9c6 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -1272,11 +1273,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(WebCore::DragData&&, SandboxExtensionHandle&&, Vector&&, CompletionHandler&&); #endif @@ -1291,6 +1292,9 @@ public: void didStartDrag(); void dragCancelled(); OptionSet allowedDragSourceActions() const { return m_allowedDragSourceActions; } +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_page->setDragPasteboardName(pasteboardName); } +#endif #endif #if ENABLE(MODEL_PROCESS) @@ -1377,8 +1381,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(); @@ -1531,6 +1538,8 @@ public: void connectInspector(const String& targetId, Inspector::FrontendChannel::ConnectionType); void disconnectInspector(const String& targetId); void sendMessageToTargetBackend(const String& targetId, const String& message); + void resumeInspectorIfPausedInNewWindow(); + void didAddWebPageToWebProcess(); void insertNewlineInQuotedContent(); @@ -1949,6 +1958,7 @@ public: void showContextMenuFromFrame(const FrameInfoData&, const ContextMenuContextData&, const UserData&); #endif void loadRequest(LoadParameters&&); + void loadRequestInFrameForInspector(LoadParameters&&, WebCore::FrameIdentifier); void setObscuredContentInsets(const WebCore::FloatBoxExtent&); @@ -2145,6 +2155,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&); @@ -2913,6 +2924,7 @@ private: UserActivity m_userActivity; 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 16e97e9e8d9158d290c98231e2a2a9c3b3d2f567..49d4d7eaaba21b3460dd84583a48501deb337664 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in @@ -58,10 +58,13 @@ messages -> WebPage WantsAsyncDispatchMessage { MouseEvent(WebCore::FrameIdentifier frameID, WebKit::WebMouseEvent event, std::optional> sandboxExtensions) SetLastKnownMousePosition(WebCore::FrameIdentifier frameID, WebCore::IntPoint eventPoint, WebCore::IntPoint globalPoint); +#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) @@ -153,6 +156,7 @@ messages -> WebPage WantsAsyncDispatchMessage { ConnectInspector(String targetId, Inspector::FrontendChannel::ConnectionType connectionType) DisconnectInspector(String targetId) SendMessageToTargetBackend(String targetId, String message) + ResumeInspectorIfPausedInNewWindow(); #if ENABLE(REMOTE_INSPECTOR) SetIndicating(bool indicating); @@ -163,6 +167,7 @@ messages -> WebPage WantsAsyncDispatchMessage { #endif #if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS) TouchEvent(WebKit::WebTouchEvent event) -> (enum:uint8_t std::optional eventType, bool handled) + FakeTouchTap(WebCore::IntPoint position, uint8_t modifiers) -> () Async #endif CancelPointer(WebCore::PointerID pointerId, WebCore::IntPoint documentPoint) @@ -190,6 +195,7 @@ messages -> WebPage WantsAsyncDispatchMessage { CreateProvisionalFrame(struct WebKit::ProvisionalFrameCreationParameters creationParameters) DestroyProvisionalFrame(WebCore::FrameIdentifier frameID); 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) @@ -351,10 +357,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(WebCore::DragData dragData, WebKit::SandboxExtensionHandle sandboxExtensionHandle, Vector sandboxExtensionsForUpload) -> (bool handled) #endif @@ -370,6 +376,10 @@ messages -> WebPage WantsAsyncDispatchMessage { StageModeSessionDidEnd(std::optional elementID) #endif +#if PLATFORM(MAC) && ENABLE(DRAG_SUPPORT) + SetDragPasteboardName(String pasteboardName) +#endif + #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT) RequestDragStart(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) diff --git a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp index 40ec42bb4f998774a2ce4a19e82f68512ad2ebb8..080794e14bfbb3a336d8a89791baee0e1aec3c75 100644 --- a/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp +++ b/Source/WebKit/WebProcess/WebPage/glib/WebPageGLib.cpp @@ -210,16 +210,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; @@ -230,6 +237,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 932e27ac30ca12459321e4bc1386e7489f647831..ae8dafebd63dbc78c4000dad9f86f3f2208b69b9 100644 --- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm +++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm @@ -703,21 +703,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 f17f5d719d892309ed9c7093384945866b5117b9..adffe0aa4440c626879e3f5701dd5fea4b2d1a0f 100644 --- a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp +++ b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -81,21 +82,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 757208df2beb144defe64fe4181d972f823ec89a..5c1bc069b031a5787515e787ed9abe441c124971 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp @@ -93,6 +93,7 @@ #include "WebsiteData.h" #include "WebsiteDataStoreParameters.h" #include "WebsiteDataType.h" +#include #include #include #include @@ -388,6 +389,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(); } @@ -395,6 +404,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter platformInitializeProcess(parameters); updateCPULimit(); + + Inspector::IdentifiersFactory::initializeWithProcessID(parameters.processIdentifier->toUInt64()); } void WebProcess::initializeConnection(IPC::Connection* connection) @@ -975,6 +986,8 @@ void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters& accessibilityRelayProcessSuspended(false); } ASSERT(result.iterator->value); + + result.iterator->value->didAddWebPageToWebProcess(); } void WebProcess::removeWebPage(PageIdentifier pageID) diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm index c0fa99b99c2d0464f976bed096ee774db8a7e3c9..7b9fb12ef6198e8a052efe0e6d37768ad161d3aa 100644 --- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm @@ -4223,7 +4223,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 e7d231ff9a7a975d442f9b790a0aad2d666e9972..263d30a59c67e4bd930a1961941a9742760df4d3 100644 --- a/Source/WebKitLegacy/mac/WebView/WebView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebView.mm @@ -3992,7 +3992,7 @@ + (void)_doNotStartObservingNetworkReachability } #endif // PLATFORM(IOS_FAMILY) -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(IOS_TOUCH_EVENTS) - (NSArray *)_touchEventRegions { @@ -4034,7 +4034,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/FindLibVPX.cmake b/Source/cmake/FindLibVPX.cmake new file mode 100644 index 0000000000000000000000000000000000000000..dd6a53e2d57318489b7e49dd7373706d5d9dc387 --- /dev/null +++ b/Source/cmake/FindLibVPX.cmake @@ -0,0 +1,25 @@ +# Find LibVPX + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBVPX REQUIRED vpx) + +find_path(LIBVPX_INCLUDE_DIRS + NAMES vpx/vp8.h + HINTS ${PC_LIBVPX_INCLUDEDIR} + ${PC_LIBVPX_INCLUDE_DIRS} +) + +find_library(LIBVPX_LIBRARIES + NAMES vpx + HINTS ${PC_LIBVPX_LIBDIR} + ${PC_LIBVPX_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibVPX REQUIRED_VARS LIBVPX_INCLUDE_DIRS LIBVPX_LIBRARIES + VERSION_VAR PC_LIBVPX_VERSION) + +mark_as_advanced( + LIBVPX_INCLUDE_DIRS + LIBVPX_LIBRARIES +) diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake index dc6bd15038f36e65b47974960a414b0d7c170e63..da2dba81c6cb4617cc2b946f24060ec8fcf46c87 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 gio gio-unix gobject gthread gmodule) + +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(Libtasn1 REQUIRED) @@ -24,6 +28,10 @@ find_package(ZLIB REQUIRED) find_package(WebP REQUIRED COMPONENTS demux) find_package(ATSPI 2.5.3) +# Playwright begin +find_package(LibVPX REQUIRED) +# Playwright end + include(GStreamerDefinitions) include(FindGLibCompileResources) @@ -71,6 +79,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) @@ -149,6 +161,20 @@ endif () 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_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) # Finalize the value for all options. Do not attempt to use an option before diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake index 8c12c0a16e14d3d537704114afc15f6935e17dcd..0c70ff37d45230597a5210e166d242a78bfb8730 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -23,6 +23,9 @@ find_package(WebP REQUIRED COMPONENTS demux) find_package(WPE REQUIRED) find_package(ZLIB REQUIRED) +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}) @@ -85,6 +88,21 @@ if (WPE_VERSION VERSION_GREATER_EQUAL 1.13.90) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC ON) endif () +# 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_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. @@ -120,6 +138,11 @@ WEBKIT_OPTION_DEPEND(USE_QT6 ENABLE_WPE_PLATFORM) WEBKIT_OPTION_DEPEND(USE_SKIA_OPENTYPE_SVG USE_SKIA) 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 ee7c004624e7da8e0a7af18356fc9a378f82020a..9fcabed645095932d997ed5a69a9a5534ac3cb35 100644 --- a/Source/cmake/OptionsWin.cmake +++ b/Source/cmake/OptionsWin.cmake @@ -73,6 +73,27 @@ find_package(ZLIB 1.2.11 REQUIRED) find_package(LibPSL 0.20.2 REQUIRED) find_package(WebP REQUIRED COMPONENTS demux) +# Playwright begin +set(LIBVPX_PACKAGE_PATH "C:\\vcpkg\\packages\\libvpx_x64-windows") +file(TO_CMAKE_PATH "${LIBVPX_PACKAGE_PATH}" LIBVPX_PACKAGE_PATH) +message(STATUS "Using LIBVPX_PACKAGE_PATH = ${LIBVPX_PACKAGE_PATH}") + +find_library(LIBVPX_CUSTOM_LIBRARY vpx.lib + HINTS ${LIBVPX_PACKAGE_PATH}/lib + REQUIRED + NO_DEFAULT_PATH +) +message(STATUS "Found LIBVPX_CUSTOM_LIBRARY = ${LIBVPX_CUSTOM_LIBRARY}") + +find_path(LIBVPX_CUSTOM_INCLUDE_DIR + NAMES vpx/vp8.h + HINTS ${LIBVPX_PACKAGE_PATH}/include + REQUIRED + NO_DEFAULT_PATH +) +message(STATUS "Found LIBVPX_CUSTOM_INCLUDE_DIR = ${LIBVPX_CUSTOM_INCLUDE_DIR}") +# Playwright end + WEBKIT_OPTION_BEGIN() # FIXME: Most of these options should not be public. @@ -131,6 +152,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 de1cb6c496ccce806010ec1da8f6a4d6d731e0c1..17ea31b9623d939fc2db0249b04caeb8f78fd725 100644 --- a/Source/cmake/WebKitCompilerFlags.cmake +++ b/Source/cmake/WebKitCompilerFlags.cmake @@ -122,7 +122,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) if (DEVELOPER_MODE AND DEVELOPER_MODE_FATAL_WARNINGS) if (MSVC) set(FATAL_WARNINGS_FLAG /WX) diff --git a/Tools/DumpRenderTree/DerivedSources.make b/Tools/DumpRenderTree/DerivedSources.make index 576835410df6deac60f0158f1d2d1ef1e5f4c78d..9b492cfe5fef8de340a80f2af70a7d68672ef2e4 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_DEFINE_DEPENDENCIES) @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 6d48c378699e87f55bbd2550d4971a295b831a24..efb0d8e1e0f7db5d4ce81bc58a97e6c4034ff0b3 100644 --- a/Tools/MiniBrowser/gtk/BrowserTab.c +++ b/Tools/MiniBrowser/gtk/BrowserTab.c @@ -117,19 +117,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; } @@ -180,6 +199,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); @@ -746,6 +770,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); @@ -798,6 +823,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..2862876cb515da09db653e71659d64215a636758 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,28 @@ static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event) } #endif +#if GTK_CHECK_VERSION(3, 98, 0) +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; +} +#else +static void zeroPreferredSize(GtkWidget* widget, gint* minimumSize, gint* naturalSize) +{ + *minimumSize = 10; + *naturalSize = 10; +} +#endif + static void browser_window_class_init(BrowserWindowClass *klass) { GObjectClass *gobjectClass = G_OBJECT_CLASS(klass); @@ -1515,6 +1535,19 @@ 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. +#if GTK_CHECK_VERSION(3, 98, 0) + GtkWidgetClass* browserWidgetClass = GTK_WIDGET_CLASS(klass); + browserWidgetClass->measure = zero_widget_measure; +#else + GtkWidgetClass* browserWidgetClass = GTK_WIDGET_CLASS(klass); + browserWidgetClass->get_preferred_width = zeroPreferredSize; + browserWidgetClass->get_preferred_height = zeroPreferredSize; +#endif +// 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 8433f5360dc4a5f43b68b67192fb3d9bf5064cf1..9fa8f53e90fe5a32be1c8e7a9daa64047640e9f6 100644 --- a/Tools/MiniBrowser/gtk/main.c +++ b/Tools/MiniBrowser/gtk/main.c @@ -75,9 +75,14 @@ static char* timeZone; static gboolean enableITP; static gboolean exitAfterLoad; static gboolean webProcessCrashed; +static gboolean inspectorPipe; +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; @@ -182,6 +187,10 @@ 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 }, + { "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 } }; @@ -739,6 +748,70 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } +static WebKitSettings* createPlaywrightSettings() { + WebKitSettings* webkitSettings = webkit_settings_new(); +#if GTK_CHECK_VERSION(3, 98, 0) + // 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); +#else + // Playwright: revert to the default state before https://github.com/WebKit/WebKit/commit/a73a25b9ea9229987c8fa7b2e092e6324cb17913 + webkit_settings_set_hardware_acceleration_policy(webkitSettings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER); + webkit_settings_set_hardware_acceleration_policy(webkitSettings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND); +#endif + 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(), +#if GTK_CHECK_VERSION(3, 98, 0) + "network-session", webkit_web_context_get_network_session_for_automation(context), +#else + "is-ephemeral", webkit_web_context_is_ephemeral(context), +#endif + "is-controlled-by-automation", TRUE, + NULL)); +#if GTK_CHECK_VERSION(3, 98, 0) + GtkWidget *newWindow = browser_window_new(NULL, context, webkit_web_context_get_network_session_for_automation(context)); +#else + GtkWidget *newWindow = browser_window_new(NULL, context); +#endif + 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 startup(GApplication *application) { const char *actionAccels[] = { @@ -797,17 +870,30 @@ static void setupDarkMode(GtkSettings *settings) static void activate(GApplication *application, WebKitSettings *webkitSettings) { + if (inspectorPipe) + configureBrowserInspectorPipe(); + + 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 || privateMode || automationMode) { networkSession = webkit_network_session_new_ephemeral(); - else { + } else { char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); char *cacheDirectory = g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); networkSession = webkit_network_session_new(dataDirectory, cacheDirectory); @@ -815,6 +901,8 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) g_free(cacheDirectory); } + webkit_web_context_set_network_session_for_automation(webContext, networkSession); + webkit_network_session_set_itp_enabled(networkSession, enableITP); if (!automationMode) { @@ -849,9 +937,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 || privateMode || automationMode) { manager = webkit_website_data_manager_new_ephemeral(); - else { + } else { char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL); char *cacheDirectory = 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); @@ -901,6 +992,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); @@ -965,9 +1057,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); @@ -1017,7 +1107,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); @@ -1069,9 +1159,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 6a898a5bd79a4e6f2f26be7f63347cef7a5c0ab4..d895941dab0f7a0bdfafcf60f203aa82c46874a6 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp @@ -52,6 +52,9 @@ static gboolean headlessMode; static gboolean privateMode; 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; @@ -130,6 +133,9 @@ static const GOptionEntry commandLineOptions[] = #endif { "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 } }; @@ -288,15 +294,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) { auto backend = createViewBackend(defaultWindowWidthLegacyAPI, defaultWindowHeightLegacyAPI); WebKitWebViewBackend* viewBackend = nullptr; @@ -311,12 +340,27 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi }, backend.release()); } - auto* newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, - "backend", viewBackend, - "related-view", webView, - "settings", webkit_web_view_get_settings(webView), - "user-content-manager", webkit_web_view_get_user_content_manager(webView), - nullptr)); +// 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, + "backend", viewBackend, + "related-view", webView, + nullptr)); + } else { + newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "backend", viewBackend, + "web-context", webContext, + "is-controlled-by-automation", TRUE, + nullptr)); + } #if ENABLE_WPE_PLATFORM if (auto* wpeView = webkit_web_view_get_wpe_view(newWebView)) { @@ -328,9 +372,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; } @@ -418,13 +466,105 @@ void loadConfigFile(WPESettings* settings) } #endif +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) { g_application_hold(application); + if (noStartupWindow) + return; #if ENABLE_2022_GLIB_API WebKitNetworkSession* networkSession = nullptr; if (!automationMode) { - networkSession = privateMode ? webkit_network_session_new_ephemeral() : webkit_network_session_new(nullptr, nullptr); + 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 { + networkSession = webkit_network_session_new(nullptr, nullptr); + } webkit_network_session_set_itp_enabled(networkSession, enableITP); if (proxy) { @@ -451,10 +591,18 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* 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 - auto* manager = (privateMode || automationMode) ? webkit_website_data_manager_new_ephemeral() : webkit_website_data_manager_new(nullptr); + 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 { + manager = webkit_website_data_manager_new(NULL); + } webkit_website_data_manager_set_itp_enabled(manager, enableITP); if (proxy) { @@ -485,6 +633,7 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* } #endif + persistentWebContext = webContext; WebKitUserContentManager* userContentManager = nullptr; if (contentFilter) { GFile* contentFilterFile = g_file_new_for_commandline_arg(contentFilter); @@ -563,6 +712,15 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* "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, "backend", viewBackend, "web-context", webContext, @@ -609,12 +767,16 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* } #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; @@ -622,16 +784,11 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend* 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); @@ -728,8 +885,14 @@ int main(int argc, char *argv[]) } } + openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr); + GApplication* application = g_application_new("org.wpewebkit.MiniBrowser", G_APPLICATION_NON_UNIQUE); g_signal_connect(application, "activate", G_CALLBACK(activate), backend.release()); + + 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/build-webkit b/Tools/Scripts/build-webkit index df483701f5b9c69718669fff32bb35475c7bf0c9..5cff91cb4618417691586a5771291eec9f89bee3 100755 --- a/Tools/Scripts/build-webkit +++ b/Tools/Scripts/build-webkit @@ -274,7 +274,7 @@ if (isAppleCocoaWebKit()) { push @projects, ("Source/WebKit"); if (!isEmbeddedWebKit()) { - push @projects, ("Tools/MiniBrowser"); + push @projects, ("Tools/Playwright"); # WebInspectorUI must come after JavaScriptCore and WebCore but before WebKit and WebKit2 my $webKitIndex = first { $projects[$_] eq "Source/WebKitLegacy" } 0..$#projects; diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt index 9e53f459e444b9c10fc5248f0e8059df6c1e0041..c17c875a7dd3ca05c4489578ab32378bca45a7c9 100644 --- a/Tools/WebKitTestRunner/CMakeLists.txt +++ b/Tools/WebKitTestRunner/CMakeLists.txt @@ -95,6 +95,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 ce8aa4f20d8e0f14a51ae27d8d9440b55e0ea433..cf93f834e135f932ffba7e7101052fcbd9e6b4b2 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -711,6 +711,7 @@ PlatformWebView* TestController::createOtherPlatformWebView(PlatformWebView* par nullptr, // requestStorageAccessConfirm nullptr, // shouldAllowDeviceOrientationAndMotionAccess nullptr, // runWebAuthenticationPanel + 0, // handleJavaScriptDialog nullptr, // decidePolicyForSpeechRecognitionPermissionRequest nullptr, // decidePolicyForMediaKeySystemPermissionRequest nullptr, // queryPermission @@ -1186,6 +1187,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 9419696018c076d0e5b4ef04ea7c58be9504cd96..06c537e3c022517449068a11ea59400413e8f4dc 100644 --- a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm +++ b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm @@ -961,4 +961,51 @@ void EventSenderProxy::waitForPendingMouseEvents() } } +#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 3a0b7425900b14ce2aa0d48aa914cd69bff1f332..0ce07cc1368c6f521b51d6300dca9c4d078beef3 100644 --- a/Tools/jhbuild/jhbuild-minimal.modules +++ b/Tools/jhbuild/jhbuild-minimal.modules @@ -67,8 +67,8 @@ + version="1.16.0" + hash="sha256:c7f3a3c6b3d006790d486dc7cceda2b6d2e329de07f33bc47dfc53f00f334b2a"/> @@ -77,8 +77,8 @@ + version="1.14.3" + hash="sha256:10121842595a850291db3e82f3db0b9984df079022d386ce42c2b8508159dc6c"> @@ -186,7 +186,6 @@ - libsoup-3.0.pc @@ -194,8 +193,8 @@ diff --git a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp index df22308266c6f69d24a60905f8d05e4e80f21b9b..2d0838070dc10793418cbb648b095a5ffa76f1b8 100644 --- a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp +++ b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp @@ -210,32 +210,30 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) return; } +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; +} + #if defined(USE_CAIRO) && USE_CAIRO - uint32_t bufferStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_width); + uint32_t bufferStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); #elif defined(USE_SKIA) && USE_SKIA - auto info = SkImageInfo::MakeN32Premul(m_width, m_height, SkColorSpace::MakeSRGB()); + auto info = SkImageInfo::MakeN32Premul(width, height, SkColorSpace::MakeSRGB()); uint32_t bufferStride = info.minRowBytes(); #endif - 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); } @@ -244,7 +242,7 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer) cairo_surface_destroy(m_snapshot); m_snapshot = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_ARGB32, - m_width, m_height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_width)); + width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); static cairo_user_data_key_t bufferKey; cairo_surface_set_user_data(m_snapshot, &bufferKey, buffer, diff --git a/WebKit.xcworkspace/contents.xcworkspacedata b/WebKit.xcworkspace/contents.xcworkspacedata index 3ad442a8691847c6921c5f66a805b7b0523b1e27..95407368a95d2f7d6fb697110912014cabe29afa 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 ded307890926eaf0ca169aaef39ea08bd982a47a..2db0c0abdda702fdff9314ba341b63c5d09289bc 100644 --- a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme +++ b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme @@ -188,6 +188,20 @@ ReferencedContainer = "container:Tools/MobileMiniBrowser/MobileMiniBrowser.xcodeproj"> + + + +