diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index f7c6662f7fe56709f45094c073f55c5081ca887e..606faf1918b3a80211d4aea9797a98a5596dcc10 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -1154,18 +1154,22 @@ 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/Database.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Debugger.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Browser.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Emulation.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/GenericTypes.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Heap.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Input.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Inspector.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/LayerTree.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Network.json ${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 diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make index e9d804d9e8be5c345ef47219e0e996d319bbf907..9a73a9d88e1b2825458d40d33500d23c67d4d08b 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make @@ -244,18 +244,22 @@ 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/Database.json \ $(JavaScriptCore)/inspector/protocol/Debugger.json \ $(JavaScriptCore)/inspector/protocol/Browser.json \ + $(JavaScriptCore)/inspector/protocol/Emulation.json \ $(JavaScriptCore)/inspector/protocol/GenericTypes.json \ $(JavaScriptCore)/inspector/protocol/Heap.json \ + $(JavaScriptCore)/inspector/protocol/Input.json \ $(JavaScriptCore)/inspector/protocol/Inspector.json \ $(JavaScriptCore)/inspector/protocol/LayerTree.json \ $(JavaScriptCore)/inspector/protocol/Network.json \ $(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 \ diff --git a/Source/JavaScriptCore/bindings/ScriptValue.cpp b/Source/JavaScriptCore/bindings/ScriptValue.cpp index dece6ac51e3a85b1e094e405effc6203887ddfd4..9bf7519d894eceb06b40d754c4fb7940399eba84 100644 --- a/Source/JavaScriptCore/bindings/ScriptValue.cpp +++ b/Source/JavaScriptCore/bindings/ScriptValue.cpp @@ -81,7 +81,10 @@ static RefPtr jsToInspectorValue(JSGlobalObject* globalObject, JSVa PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); object.methodTable(vm)->getOwnPropertyNames(&object, globalObject, propertyNames, EnumerationMode()); for (auto& name : propertyNames) { - auto inspectorValue = jsToInspectorValue(globalObject, object.get(globalObject, name), maxDepth); + JSValue childValue = object.get(globalObject, name); + if (childValue.isUndefined()) + continue; + auto inspectorValue = jsToInspectorValue(globalObject, childValue, maxDepth); if (!inspectorValue) return nullptr; inspectorObject->setValue(name.string(), WTFMove(inspectorValue)); diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp index 95cd87b01b15cb8667e57bc5bb51a71f06bc3760..0481fa93227f297be9d9cf000c5a72235956a390 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp @@ -30,14 +30,21 @@ namespace Inspector { namespace { +static uint64_t s_processID = 0; static long s_lastUsedIdentifier = 0; } static String addPrefixToIdentifier(const String& identifier) { - return makeString("0.", identifier); + return makeString(s_processID, ".", identifier); } +void IdentifiersFactory::initializeWithProcessID(uint64_t processID) { + ASSERT(!s_processID); + s_processID = processID; +} + + String IdentifiersFactory::createIdentifier() { return addPrefixToIdentifier(String::number(++s_lastUsedIdentifier)); diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.h b/Source/JavaScriptCore/inspector/IdentifiersFactory.h index eb25aedee4cd9ebe007e06c2515b37ee095b06f4..badf6559595c8377db1089ca3c25008e1be2c8f1 100644 --- a/Source/JavaScriptCore/inspector/IdentifiersFactory.h +++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.h @@ -31,6 +31,7 @@ namespace Inspector { class JS_EXPORT_PRIVATE IdentifiersFactory { public: + static void initializeWithProcessID(uint64_t); static String createIdentifier(); static String requestId(unsigned long identifier); }; diff --git a/Source/JavaScriptCore/inspector/InjectedScript.cpp b/Source/JavaScriptCore/inspector/InjectedScript.cpp index cc849f051fa40518a9d1a03429bc2b4dbcfb3102..11b05346f6098fa23f51ba9abc1af0e0e60a626c 100644 --- a/Source/JavaScriptCore/inspector/InjectedScript.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScript.cpp @@ -287,9 +287,13 @@ RefPtr InjectedScript::wrapObject(JSC::JSValue auto callResult = callFunctionWithEvalEnabled(wrapFunction); if (!callResult) return nullptr; + auto callResultValue = callResult.value(); + // callResultValue could be missing if the execution was terminated + if (!callResultValue) + return nullptr; RefPtr resultObject; - bool castSucceeded = toInspectorValue(globalObject(), callResult.value())->asObject(resultObject); + bool castSucceeded = toInspectorValue(globalObject(), callResultValue)->asObject(resultObject); ASSERT_UNUSED(castSucceeded, castSucceeded); return BindingTraits::runtimeCast(resultObject); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp index 038cb646d31706905deff8935040d63c0afd00f9..2fca7b043f15a8cce3819cc827912fb719a345db 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp @@ -102,7 +102,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple m_dispatchers.set(domain, dispatcher); } -void BackendDispatcher::dispatch(const String& message) +BackendDispatcher::DispatchResult BackendDispatcher::dispatch(const String& message, Mode mode, Interceptor&& interceptor) { Ref protect(*this); @@ -120,29 +120,32 @@ void BackendDispatcher::dispatch(const String& message) if (!JSON::Value::parseJSON(message, parsedMessage)) { reportProtocolError(ParseError, "Message must be in JSON format"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } if (!parsedMessage->asObject(messageObject)) { reportProtocolError(InvalidRequest, "Message must be a JSONified object"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } RefPtr requestIdValue; if (!messageObject->getValue("id"_s, requestIdValue)) { reportProtocolError(InvalidRequest, "'id' property was not found"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } if (!requestIdValue->asInteger(requestId)) { reportProtocolError(InvalidRequest, "The type of 'id' property must be integer"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } } + if (interceptor && interceptor(messageObject) == DispatchResult::Finished) + return DispatchResult::Finished; + { // We could be called re-entrantly from a nested run loop, so restore the previous id. SetForScope> scopedRequestId(m_currentRequestId, requestId); @@ -151,29 +154,31 @@ void BackendDispatcher::dispatch(const String& message) if (!messageObject->getValue("method"_s, methodValue)) { reportProtocolError(InvalidRequest, "'method' property wasn't found"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } String methodString; if (!methodValue->asString(methodString)) { reportProtocolError(InvalidRequest, "The type of 'method' property must be string"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } Vector domainAndMethod = methodString.splitAllowingEmptyEntries('.'); if (domainAndMethod.size() != 2 || !domainAndMethod[0].length() || !domainAndMethod[1].length()) { reportProtocolError(InvalidRequest, "The 'method' property was formatted incorrectly. It should be 'Domain.method'"_s); sendPendingErrors(); - return; + return DispatchResult::Finished; } String domain = domainAndMethod[0]; SupplementalBackendDispatcher* domainDispatcher = m_dispatchers.get(domain); if (!domainDispatcher) { + if (mode == Mode::ContinueIfDomainIsMissing) + return DispatchResult::Continue; reportProtocolError(MethodNotFound, "'" + domain + "' domain was not found"); sendPendingErrors(); - return; + return DispatchResult::Finished; } String method = domainAndMethod[1]; @@ -182,6 +187,7 @@ void BackendDispatcher::dispatch(const String& message) if (m_protocolErrors.size()) sendPendingErrors(); } + return DispatchResult::Finished; } // FIXME: remove this function when legacy InspectorObject symbols are no longer needed . diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h index 95d9d81188e735e8f1b70cc0deee2682cb6714f0..4c67ce34302f74e0d07f64ae53a4eaf18df6669a 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h @@ -82,7 +82,11 @@ public: }; void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); - void dispatch(const String& message); + + enum class DispatchResult { Finished, Continue }; + enum class Mode { FailIfDomainIsMissing, ContinueIfDomainIsMissing }; + using Interceptor = WTF::Function&)>; + DispatchResult dispatch(const String& message, Mode mode = Mode::FailIfDomainIsMissing, 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 4b95964db4d902b4b7f4b0b4c40afea51654ff2f..966a5927702b65edb343369decafda7fc83eaec7 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.h +++ b/Source/JavaScriptCore/inspector/InspectorTarget.h @@ -56,8 +56,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"; } + virtual void close(String& error, bool /* runBeforeUnload */) { error = "Target cannot be closed"; } private: + virtual void willResume() { } + WTF::Function m_resumeCallback; bool m_isPaused { false }; }; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp index 8fcb5a1e55750d325a84824d86c49cfe6fb04268..ed2525df326bfe649793701a112eefa30952e375 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp @@ -87,6 +87,28 @@ void InspectorTargetAgent::sendMessageToTarget(ErrorString& errorString, const S target->sendMessageToTargetBackend(message); } +void InspectorTargetAgent::activate(ErrorString& errorString, const String& targetId) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) { + errorString = "Missing target for given targetId"_s; + return; + } + + target->activate(errorString); +} + +void InspectorTargetAgent::close(ErrorString& errorString, const String& targetId, const bool* runBeforeUnload) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) { + errorString = "Missing target for given targetId"_s; + return; + } + + target->close(errorString, runBeforeUnload && *runBeforeUnload); +} + 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."); @@ -144,7 +166,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) @@ -159,6 +191,18 @@ void InspectorTargetAgent::didCommitProvisionalTarget(const String& oldTargetID, m_frontendDispatcher->didCommitProvisionalTarget(oldTargetID, committedTargetID); } +void InspectorTargetAgent::ensureConnected(const String& targetID) +{ + if (!m_isConnected) + return; + + auto* target = m_targets.get(targetID); + if (!target) + return; + + target->connect(connectionType()); +} + FrontendChannel::ConnectionType InspectorTargetAgent::connectionType() const { return m_router.hasLocalFrontend() ? Inspector::FrontendChannel::ConnectionType::Local : Inspector::FrontendChannel::ConnectionType::Remote; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h index 1eb7abb2fa21d7a8ec0833160f53e5c523ec4317..7709bcc2ec69aab0589ca1b954db1fb241bb583b 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h @@ -52,15 +52,21 @@ public: void setPauseOnStart(ErrorString&, bool pauseOnStart) override; void resume(ErrorString&, const String& targetId) override; void sendMessageToTarget(ErrorString&, const String& targetId, const String& message) final; + void activate(ErrorString&, const String& targetId) override; + void close(ErrorString&, const String& targetId, const bool* runBeforeUnload) override; // Target lifecycle. void targetCreated(InspectorTarget&); void targetDestroyed(InspectorTarget&); + void targetCrashed(InspectorTarget&); void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID); + void ensureConnected(const String& targetID); // Target messages. void sendMessageFromTargetToFrontend(const String& targetId, const String& message); + 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 38cb48bedf2b168149ff79423b7fafc1e63ce8b3..e3d044934f5a0dc2331534439daa53116019548f 100644 --- a/Source/JavaScriptCore/inspector/protocol/DOM.json +++ b/Source/JavaScriptCore/inspector/protocol/DOM.json @@ -79,6 +79,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", @@ -167,6 +177,16 @@ { "name": "borderColor", "$ref": "RGBAColor", "optional": true, "description": "The border highlight fill color (default: transparent)." }, { "name": "marginColor", "$ref": "RGBAColor", "optional": true, "description": "The margin highlight fill color (default: transparent)." } ] + }, + { + "id": "FilePayload", + "type": "object", + "description": "Data to construct File object.", + "properties": [ + { "name": "name", "type": "string", "description": "File name." }, + { "name": "type", "type": "string", "description": "File type." }, + { "name": "data", "type": "string", "description": "Base64-encoded file data." } + ] } ], "commands": [ @@ -481,7 +501,9 @@ "name": "resolveNode", "description": "Resolves JavaScript node object for given node id.", "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": "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": [ @@ -542,6 +564,45 @@ "parameters": [ { "name": "allow", "type": "boolean" } ] + }, + { + "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": "files", "type": "array", "items": { "$ref": "FilePayload" }, "description": "Files to set" } + ] } ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Dialog.json b/Source/JavaScriptCore/inspector/protocol/Dialog.json new file mode 100644 index 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..552e5dd60fa53fada79f8d6e333f52bc10a2bead --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Emulation.json @@ -0,0 +1,39 @@ +{ + "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": "deviceScaleFactor", "type": "number" }, + { "name": "fixedLayout", "type": "boolean" } + ] + }, + { + "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": "setActiveAndFocused", + "description": "Makes page focused for test.", + "parameters": [ + { "name": "active", "type": "boolean", "optional": true } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Input.json b/Source/JavaScriptCore/inspector/protocol/Input.json new file mode 100644 index 0000000000000000000000000000000000000000..34909cce9f6d8d7c74be4c96e40f80cadb2f931d --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Input.json @@ -0,0 +1,165 @@ +{ + "domain": "Input", + "availability": ["web"], + "types": [ + { + "id": "TimeSinceEpoch", + "description": "UTC time in seconds, counted from January 1, 1970.", + "type": "number" + } + ], + "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" + } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Network.json b/Source/JavaScriptCore/inspector/protocol/Network.json index 777a54166ed6664561b3f8249a6abb4ac59d0480..e738f34f65fa8137a16bf7b66bc237b85b2f5208 100644 --- a/Source/JavaScriptCore/inspector/protocol/Network.json +++ b/Source/JavaScriptCore/inspector/protocol/Network.json @@ -231,7 +231,8 @@ "name": "setInterceptionEnabled", "description": "Enable interception of network requests.", "parameters": [ - { "name": "enabled", "type": "boolean" } + { "name": "enabled", "type": "boolean" }, + { "name": "interceptRequests", "type": "boolean", "optional": true } ] }, { @@ -258,7 +259,18 @@ "name": "interceptContinue", "description": "Continue an interception with no modifications.", "parameters": [ - { "name": "requestId", "$ref": "RequestId", "description": "Identifier for the intercepted Network request or response to continue." } + { "name": "requestId", "$ref": "RequestId", "description": "Identifier for the intercepted Network request or response to continue." }, + { "name": "method", "type": "string", "optional": true,"description": "HTTP request method." }, + { "name": "headers", "$ref": "Headers", "optional": true, "description": "HTTP response headers. Pass through original values if unmodified." }, + { "name": "postData", "type": "string", "optional": true, "description": "HTTP POST request data." } + ] + }, + { + "name": "interceptAsError", + "description": "Abort the intercepted request with given reason.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Identifier for the intercepted Network request." }, + { "name": "reason", "type": "string", "description": "Deliver error reason for the request." } ] }, { @@ -266,13 +278,20 @@ "description": "Provide response content for an intercepted response.", "parameters": [ { "name": "requestId", "$ref": "RequestId", "description": "Identifier for the intercepted Network response to modify." }, - { "name": "content", "type": "string" }, - { "name": "base64Encoded", "type": "boolean", "description": "True, if content was sent as base64." }, + { "name": "content", "type": "string", "optional": true }, + { "name": "base64Encoded", "type": "boolean", "optional": true, "description": "True, if content was sent as base64." }, { "name": "mimeType", "type": "string", "optional": true, "description": "MIME Type for the data." }, { "name": "status", "type": "integer", "optional": true, "description": "HTTP response status code. Pass through original values if unmodified." }, { "name": "statusText", "type": "string", "optional": true, "description": "HTTP response status text. Pass through original values if unmodified." }, { "name": "headers", "$ref": "Headers", "optional": true, "description": "HTTP response headers. Pass through original values if unmodified." } ] + }, + { + "name": "setEmulateOfflineState", + "description": "Emulate offline state overriding the actual state.", + "parameters": [ + { "name": "offline", "type": "boolean", "description": "True to emulate offline." } + ] } ], "events": [ @@ -356,6 +375,14 @@ { "name": "response", "$ref": "Response", "description": "Original response content that would proceed if this is continued." } ] }, + { + "name": "requestIntercepted", + "description": "Fired when HTTP request has been intercepted. The frontend must response with Network.interceptContinue or Network.interceptWithRespons` to continue this response.", + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Identifier for this intercepted network. Corresponds with an earlier Network.requestWillBeSent." }, + { "name": "request", "$ref": "Request", "description": "Original request content that would proceed if this is continued." } + ] + }, { "name": "webSocketWillSendHandshakeRequest", "description": "Fired when WebSocket is about to initiate handshake.", diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json index a8fc5332ac92424b00a3dec62152fd3c5f28544e..6aa07fd2ee4e0dff43b151d1cee7497f4aa0505b 100644 --- a/Source/JavaScriptCore/inspector/protocol/Page.json +++ b/Source/JavaScriptCore/inspector/protocol/Page.json @@ -110,6 +110,41 @@ { "name": "session", "type": "boolean", "description": "True in case of session cookie." }, { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." } ] + }, + { + "id": "AXNode", + "type": "object", + "description": "Accessibility Node", + "properties": [ + { "name": "role", "type": "string", "description": "The role."}, + { "name": "name", "type": "string","optional": true, "description": "A human readable name for the node."}, + { "name": "value", "type": "any", "optional": true, "description": "The current value of the node."}, + { "name": "description", "type": "string", "optional": true, "description": "An additional human readable description of the node."}, + { "name": "keyshortcuts", "type": "string", "optional": true, "description": "Keyboard shortcuts associated with this node."}, + { "name": "roledescription", "type": "string", "optional": true, "description": "A human readable alternative to the role."}, + { "name": "valuetext", "type": "string", "optional": true, "description": "A description of the current value."}, + { "name": "disabled", "type": "boolean", "optional": true, "description": "Whether the node is disabled."}, + { "name": "expanded", "type": "boolean", "optional": true, "description": "Whether the node is expanded or collapsed."}, + { "name": "focused", "type": "boolean", "optional": true, "description": "Whether the node is focused."}, + { "name": "modal", "type": "boolean", "optional": true, "description": "Whether the node is modal."}, + { "name": "multiline", "type": "boolean", "optional": true, "description": "Whether the node text input supports multiline."}, + { "name": "multiselectable", "type": "boolean", "optional": true, "description": "Whether more than one child can be selected."}, + { "name": "readonly", "type": "boolean", "optional": true, "description": "Whether the node is read only."}, + { "name": "required", "type": "boolean", "optional": true, "description": "Whether the node is required."}, + { "name": "selected", "type": "boolean", "optional": true, "description": "Whether the node is selected in its parent node."}, + { "name": "checked", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Whether the checkbox is checked, or \"mixed\"."}, + { "name": "pressed", "type": "string", "optional": true, "enum": ["true", "false", "mixed"], "description": "Whether the toggle button is checked, or \"mixed\"."}, + { "name": "level", "type": "integer", "optional": true, "description": "The level of a heading."}, + { "name": "valuemin", "type": "number", "optional": true, "description": "The minimum value in a node."}, + { "name": "valuemax", "type": "number", "optional": true, "description": "The maximum value in a node."}, + { "name": "autocomplete", "type": "string", "optional": true, "description": "What kind of autocomplete is supported by a control."}, + { "name": "haspopup", "type": "string", "optional": true, "description": "What kind of popup is currently being shown for a node."}, + { "name": "invalid", "type": "string", "optional": true, "enum": ["true", "false", "grammar", "spelling"], "description": "Whether and in what way this node's value is invalid."}, + { "name": "orientation", "type": "string", "optional": true, "description": "Whether the node is oriented horizontally or vertically."}, + { "name": "focusable", "type": "boolean", "optional": true, "description": "Whether the node is focusable."}, + { "name": "children", "type": "array", "optional": true, "items": { "$ref": "AXNode"}, "description": "Child AXNodes of this node, if any."}, + { "name": "found", "type": "boolean", "optional": true, "description": "True if this AXNode corresponds with the ObjectId passed into acessibilitySnapshot."} + ] } ], "commands": [ @@ -129,11 +164,21 @@ { "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.", "parameters": [ - { "name": "url", "type": "string", "description": "URL to navigate the page to." } + { "name": "url", "type": "string", "description": "URL to navigate the page to." }, + { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to navigate."}, + { "name": "referrer", "type": "string", "optional": true, "description": "Referrer URL." } ] }, { @@ -246,6 +291,20 @@ { "name": "appearance", "$ref": "Appearance", "description": "Appearance name to force. Empty string disables the override." } ] }, + { + "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.", @@ -276,19 +335,78 @@ "returns": [ { "name": "data", "type": "string", "description": "Base64-encoded web archive." } ] + }, + { + "name": "insertText", + "description": "Insert text into the current selection of the page.", + "parameters": [ + { "name": "text", "type": "string", "description": "Text to insert." } + ] + }, + { + "name": "accessibilitySnapshot", + "description": "Serializes and returns all of the accessibility nodes of the page.", + "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": "setScreenSizeOverride", + "description": "Overrides screen size with provided values.", + "parameters": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" } + ] } ], "events": [ { "name": "domContentEventFired", "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", "parameters": [ - { "name": "timestamp", "type": "number" } + { "name": "timestamp", "type": "number" }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has fired load event." } ] }, { @@ -298,6 +416,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.", @@ -334,12 +460,36 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ] }, + { + "name": "navigatedWithinDocument", + "description": "Fired when same-document navigation happens, e.g. due to history API usage or anchor navigation.", + "parameters": [ + { + "name": "frameId", + "description": "Id of the frame.", + "$ref": "Network.FrameId" + }, + { + "name": "url", + "description": "Frame's new url.", + "type": "string" + } + ] + }, { "name": "defaultAppearanceDidChange", "description": "Fired when page's default appearance changes, even if there is a forced appearance.", "parameters": [ { "name": "appearance", "$ref": "Appearance", "description": "Name of the appearance that is active (not considering any forced appearance.)" } ] + }, + { + "name": "fileChooserOpened", + "description": "Fired when the page shows file chooser for it's .", + "parameters": [ + { "name": "frameId", "$ref": "Network.FrameId", "description": "Frame where file chooser is opened." }, + { "name": "element", "$ref": "Runtime.RemoteObject", "description": "Input element." } + ] } ] } diff --git a/Source/JavaScriptCore/inspector/protocol/Playwright.json b/Source/JavaScriptCore/inspector/protocol/Playwright.json new file mode 100644 index 0000000000000000000000000000000000000000..612d9f32dc50445747e97f07089b5c2e6713c7a2 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Playwright.json @@ -0,0 +1,211 @@ +{ + "domain": "Playwright", + "availability": ["web"], + "types": [ + { + "id": "ContextID", + "type": "string", + "description": "Id of Browser context." + }, + { + "id": "PageProxyID", + "type": "string", + "description": "Id of WebPageProxy." + }, + { + "id": "PageProxyInfo", + "type": "object", + "description": "Tab info object", + "properties": [ + { "name": "pageProxyId", "$ref": "PageProxyID" }, + { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." }, + { "name": "openerId", "$ref": "PageProxyID", "optional": true, "description": "Unique identifier of the opening page. Only set for pages created by window.open()." } + ] + }, + { + "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": "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": "close", + "async": true, + "description": "Close browser." + }, + { + "name": "createContext", + "description": "Creates new ephemeral browser context.", + "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": "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": "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": "grantPermissions", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }, + { "name": "origin", "type": "string" }, + { "name": "permissions", "type": "array", "items": { "type": "string" } } + ], + "description": "Overrides the permissions." + }, + { + "name": "resetPermissions", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ], + "description": "Clears permission overrides." + }, + { + "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." } + ] + } + ], + "events": [ + { + "name": "pageProxyCreated", + "parameters": [ + { "name": "pageProxyInfo", "$ref": "PageProxyInfo" } + ] + }, + { + "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." } + ] + } + ] +} 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/inspector/protocol/Worker.json b/Source/JavaScriptCore/inspector/protocol/Worker.json index 9e2bee913d37c79fedbb918176a43022b84fa45b..ad8926d773144114dad3842fa0fe239155a15d9e 100644 --- a/Source/JavaScriptCore/inspector/protocol/Worker.json +++ b/Source/JavaScriptCore/inspector/protocol/Worker.json @@ -16,7 +16,7 @@ "description": "Sent after the frontend has sent all initialization messages and can resume this worker. This command is required to allow execution in the worker.", "parameters": [ { "name": "workerId", "type": "string" } - ] + ] }, { "name": "sendMessageToWorker", @@ -32,7 +32,8 @@ "name": "workerCreated", "parameters": [ { "name": "workerId", "type": "string" }, - { "name": "url", "type": "string" } + { "name": "url", "type": "string" }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame this worker belongs to." } ] }, { diff --git a/Source/JavaScriptCore/runtime/DateConversion.cpp b/Source/JavaScriptCore/runtime/DateConversion.cpp index 955756ba405f400970610f9a68c7ed42a67cb015..1520c0a1475a90de2795e4ccd8919c1bb1384066 100644 --- a/Source/JavaScriptCore/runtime/DateConversion.cpp +++ b/Source/JavaScriptCore/runtime/DateConversion.cpp @@ -100,17 +100,23 @@ String formatDateTime(const GregorianDateTime& t, DateTimeFormat format, bool as appendNumber<2>(builder, offset / 60); appendNumber<2>(builder, offset % 60); -#if OS(WINDOWS) - TIME_ZONE_INFORMATION timeZoneInformation; - GetTimeZoneInformation(&timeZoneInformation); - const WCHAR* winTimeZoneName = t.isDST() ? timeZoneInformation.DaylightName : timeZoneInformation.StandardName; - String timeZoneName(winTimeZoneName); + String timeZoneName; + if (!WTF::timeZoneDisplayNameForAutomation().isEmpty()) { + timeZoneName = WTF::timeZoneDisplayNameForAutomation(); + } else { + #if OS(WINDOWS) + TIME_ZONE_INFORMATION timeZoneInformation; + GetTimeZoneInformation(&timeZoneInformation); + const WCHAR* winTimeZoneName = t.isDST() ? timeZoneInformation.DaylightName : timeZoneInformation.StandardName; + timeZoneName = String(winTimeZoneName); #else - struct tm gtm = t; - char timeZoneName[70]; - strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); + struct tm gtm = t; + char tzName[70]; + strftime(tzName, sizeof(tzName), "%Z", >m); + timeZoneName = String(tzName); #endif - if (timeZoneName[0]) { + } + if (!timeZoneName.isEmpty()) { builder.appendLiteral(" ("); builder.append(timeZoneName); builder.append(')'); diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp index 9817a45ea2f3a22844ed3e56816cff94eb051423..67f7459a556ed22740fbfcd2b1b7b530d34d5bb5 100644 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #if JSC_ICU_HAS_UFIELDPOSITER @@ -113,6 +114,10 @@ void IntlDateTimeFormat::setBoundFormat(VM& vm, JSBoundFunction* format) static String defaultTimeZone() { + String tz = WTF::timeZoneForAutomation(); + if (!tz.isEmpty()) + return tz; + // 6.4.3 DefaultTimeZone () (ECMA-402 2.0) // The DefaultTimeZone abstract operation returns a String value representing the valid (6.4.1) and canonicalized (6.4.2) time zone name for the host environment’s current time zone. diff --git a/Source/WTF/wtf/DateMath.cpp b/Source/WTF/wtf/DateMath.cpp index 1999737341553001d5246b8190e9ea11d615a158..540ed892bca8110f8013477da7bd9b459a17e60d 100644 --- a/Source/WTF/wtf/DateMath.cpp +++ b/Source/WTF/wtf/DateMath.cpp @@ -77,11 +77,16 @@ #include #include #include +#include #include #include +#include #include +#include #include +#include #include +#include #if OS(WINDOWS) #include @@ -107,6 +112,18 @@ template inline bool startsWithLettersIgnoringASCIICase(const c return equalLettersIgnoringASCIICase(string, lowercaseLetters, length - 1); } +struct TimeZoneForAutomation { + UCalendar* cal; + String id; + String displayName; +}; + +static TimeZoneForAutomation& innerTimeZoneForAutomation() +{ + static NeverDestroyed> timeZoneForAutomation; + return *timeZoneForAutomation.get(); +} + /* Constants */ const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; @@ -333,6 +350,14 @@ static double calculateDSTOffset(time_t localTime, double utcOffset) // Returns combined offset in millisecond (UTC + DST). LocalTimeOffset calculateLocalTimeOffset(double ms, TimeType inputTimeType) { + TimeZoneForAutomation& tz = innerTimeZoneForAutomation(); + if (tz.cal) { + UErrorCode status = U_ZERO_ERROR; + ucal_setMillis(tz.cal, ms, &status); + int32_t offset = ucal_get(tz.cal, UCAL_ZONE_OFFSET, &status); + int32_t dstOffset = ucal_get(tz.cal, UCAL_DST_OFFSET, &status); + return LocalTimeOffset(dstOffset, offset + dstOffset); + } #if HAVE(TM_GMTOFF) double localToUTCTimeOffset = inputTimeType == LocalTime ? calculateUTCOffset() : 0; #else @@ -1034,4 +1059,65 @@ String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, u return stringBuilder.toString(); } +bool setTimeZoneForAutomation(const String& timeZone) +{ + innerTimeZoneForAutomation().displayName = String(); + if (innerTimeZoneForAutomation().cal) { + ucal_close(innerTimeZoneForAutomation().cal); + innerTimeZoneForAutomation().cal = nullptr; + } + if (timeZone.isEmpty()) { + innerTimeZoneForAutomation().id = String(); + return true; + } + + // Timezone is ascii. + Vector buffer(timeZone.length()); + UChar* bufferStart = buffer.data(); + CString ctz = timeZone.utf8(); + if (!Unicode::convertUTF8ToUTF16(ctz.data(), ctz.data() + ctz.length(), &bufferStart, bufferStart + timeZone.length())) + return false; + + Vector canonicalBuffer(32); + UErrorCode status = U_ZERO_ERROR; + auto canonicalLength = ucal_getCanonicalTimeZoneID(buffer.data(), buffer.size(), canonicalBuffer.data(), canonicalBuffer.size(), nullptr, &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + canonicalBuffer.grow(canonicalLength); + ucal_getCanonicalTimeZoneID(buffer.data(), buffer.size(), canonicalBuffer.data(), canonicalLength, nullptr, &status); + } + if (!U_SUCCESS(status)) + return false; + + UCalendar* cal = ucal_open(canonicalBuffer.data(), canonicalLength, nullptr, UCAL_TRADITIONAL, &status); + if (!U_SUCCESS(status)) + return false; + + Vector displayNameBuffer(32); + auto displayNameLength = ucal_getTimeZoneDisplayName(cal, UCAL_STANDARD, defaultLanguage().utf8().data(), displayNameBuffer.data(), displayNameBuffer.size(), &status); + if (status == U_BUFFER_OVERFLOW_ERROR) { + status = U_ZERO_ERROR; + displayNameBuffer.grow(displayNameLength); + ucal_getTimeZoneDisplayName(cal, UCAL_STANDARD, defaultLanguage().utf8().data(), displayNameBuffer.data(), displayNameLength, &status); + } + if (!U_SUCCESS(status)) + return false; + + TimeZoneForAutomation& tzfa = innerTimeZoneForAutomation(); + tzfa.cal = cal; + tzfa.id = String(canonicalBuffer.data(), canonicalLength); + tzfa.displayName = String(displayNameBuffer.data(), displayNameLength); + return true; +} + +String timeZoneForAutomation() +{ + return innerTimeZoneForAutomation().id; +} + +String timeZoneDisplayNameForAutomation() +{ + return innerTimeZoneForAutomation().displayName; +} + } // namespace WTF diff --git a/Source/WTF/wtf/DateMath.h b/Source/WTF/wtf/DateMath.h index 602f89a49d454cc5e5acd030024227d49d98c61f..41811e65bd0f15b443fb90d37ee4d0a21780a518 100644 --- a/Source/WTF/wtf/DateMath.h +++ b/Source/WTF/wtf/DateMath.h @@ -389,6 +389,10 @@ inline int dayInMonthFromDayInYear(int dayInYear, bool leapYear) return d - step; } +WTF_EXPORT_PRIVATE bool setTimeZoneForAutomation(const String& timeZone); +WTF_EXPORT_PRIVATE String timeZoneForAutomation(); +WTF_EXPORT_PRIVATE String timeZoneDisplayNameForAutomation(); + // Returns combined offset in millisecond (UTC + DST). WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds, TimeType = UTCTime); diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h index 44004c2e0da3c19384459f5b305f6c6e8fe5d6ac..15478b41e06a7aff27ca9a25ab3afcffdc317608 100644 --- a/Source/WTF/wtf/PlatformHave.h +++ b/Source/WTF/wtf/PlatformHave.h @@ -379,7 +379,7 @@ #define HAVE_NSHTTPCOOKIESTORAGE__INITWITHIDENTIFIER_WITH_INACCURATE_NULLABILITY 1 #endif -#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || PLATFORM(IOS) || PLATFORM(MACCATALYST) +#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || PLATFORM(IOS) || PLATFORM(MACCATALYST) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN) #define HAVE_OS_DARK_MODE_SUPPORT 1 #endif diff --git a/Source/WebCore/Modules/geolocation/Geolocation.cpp b/Source/WebCore/Modules/geolocation/Geolocation.cpp index 6d5be9a591a272cd67d6e9d097b30505bdf8ae5e..8f67ba28c380e844c8e4191ee704466559d88f97 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp @@ -356,8 +356,9 @@ bool Geolocation::shouldBlockGeolocationRequests() bool isSecure = SecurityOrigin::isSecure(document()->url()); bool hasMixedContent = !document()->foundMixedContent().isEmpty(); bool isLocalOrigin = securityOrigin()->isLocal(); + bool isPotentiallyTrustworthy = securityOrigin()->isPotentiallyTrustworthy(); if (securityOrigin()->canRequestGeolocation()) { - if (isLocalOrigin || (isSecure && !hasMixedContent) || isRequestFromIBooks()) + if (isLocalOrigin || isPotentiallyTrustworthy || (isSecure && !hasMixedContent) || isRequestFromIBooks()) return false; } diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt index c80b21a94fc00b0a619b44ef35470e63d86e72f1..3d72a82e755de4bf92895ad499788d5ff459168b 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt @@ -649,7 +649,7 @@ WHLSLStandardLibraryFunctionMap.cpp #endif -#if ENABLE_IOS_TOUCH_EVENTS +#if ENABLE_TOUCH_EVENTS JSTouch.cpp JSTouchEvent.cpp diff --git a/Source/WebCore/WebCore.order b/Source/WebCore/WebCore.order index 34f1a72596fb89c8b647fff3348cca3d959c014c..ab6e42c4da2a8a77f66ce532a3a12bb9ee991207 100644 --- a/Source/WebCore/WebCore.order +++ b/Source/WebCore/WebCore.order @@ -3094,7 +3094,6 @@ __ZN7WebCore14DocumentLoader23stopLoadingSubresourcesEv __ZN7WebCore14DocumentLoader18stopLoadingPlugInsEv __ZN7WebCore14DocumentLoader15detachFromFrameEv __ZN7WebCore20ApplicationCacheHost22setDOMApplicationCacheEPNS_19DOMApplicationCacheE -__ZN7WebCore24InspectorInstrumentation27loaderDetachedFromFrameImplEPNS_19InstrumentingAgentsEPNS_14DocumentLoaderE __ZN7WebCore14DocumentLoaderD0Ev __ZN7WebCore14DocumentLoaderD2Ev __ZN7WebCore14DocumentLoader17clearMainResourceEv diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj index 6d625ee04539635a97fe0d9b21a6b2d970ef2ddf..5d27dbb03899a0ef914452436b6c2a2149d3f708 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj @@ -4972,6 +4972,14 @@ EDE3A5000C7A430600956A37 /* ColorMac.h in Headers */ = {isa = PBXBuildFile; fileRef = EDE3A4FF0C7A430600956A37 /* ColorMac.h */; settings = {ATTRIBUTES = (Private, ); }; }; EDEC98030AED7E170059137F /* WebCorePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEC98020AED7E170059137F /* WebCorePrefix.h */; }; 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 */; }; + F050E17223AD669F0011CE47 /* TouchEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = F050E17023AD669F0011CE47 /* TouchEvent.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 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, ); }; }; F12171F516A8CED2000053CA /* WebVTTElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F12171F316A8BC63000053CA /* WebVTTElement.cpp */; }; F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; @@ -15456,6 +15464,14 @@ EDEC98020AED7E170059137F /* WebCorePrefix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebCorePrefix.h; sourceTree = ""; tabWidth = 4; usesTabs = 0; }; 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 = ""; }; @@ -20694,7 +20710,12 @@ 2D2E34A921A4E191004598B5 /* EditableImageReference.h */, 1AF326770D78B9440068F0C4 /* EditorClient.h */, 93C09A800B064F00005ABD4D /* EventHandler.cpp */, + F050E16F23AD669E0011CE47 /* TouchEvent.cpp */, + F050E17023AD669F0011CE47 /* TouchEvent.h */, 93C09A520B064DB3005ABD4D /* EventHandler.h */, + F050E16923AD660C0011CE47 /* Touch.cpp */, + F050E16C23AD66630011CE47 /* TouchList.cpp */, + F050E16B23AD66620011CE47 /* TouchList.h */, E0FEF371B27C53EAC1C1FBEE /* EventSource.cpp */, E0FEF371B17C53EAC1C1FBEE /* EventSource.h */, E0FEF371B07C53EAC1C1FBEE /* EventSource.idl */, @@ -25934,7 +25955,9 @@ 1A2E6E560CC551E0004A2062 /* sql */, B2C3D9EC0D006C1D00EF6F26 /* text */, DFDB912CF8E88A6DA1AD264F /* AbortableTaskQueue.h */, + F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */, 49AE2D94134EE5F90072920A /* CalculationValue.cpp */, + F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */, 49AE2D95134EE5F90072920A /* CalculationValue.h */, C330A22113EC196B0000B45B /* ColorChooser.h */, C37CDEBC149EF2030042090D /* ColorChooserClient.h */, @@ -28162,6 +28185,7 @@ BCCFBAE70B5152ED0001F1D7 /* DocumentParser.h */, AD6E71AA1668899D00320C13 /* DocumentSharedObjectPool.cpp */, AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, + F050E17323AD6A800011CE47 /* DocumentTouch.cpp */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, 6BDB5DC5227CA0EB00919770 /* DocumentStorageAccess.idl */, @@ -29046,6 +29070,7 @@ 93C4F6EB1108F9A50099D0DB /* AccessibilityScrollbar.h in Headers */, 29489FC712C00F0300D83F0F /* AccessibilityScrollView.h in Headers */, 0709FC4E1025DEE30059CDBA /* AccessibilitySlider.h in Headers */, + F050E16D23AD66630011CE47 /* TouchList.h in Headers */, 29D7BCFA1444AF7D0070619C /* AccessibilitySpinButton.h in Headers */, 69A6CBAD1C6BE42C00B836E9 /* AccessibilitySVGElement.h in Headers */, AAC08CF315F941FD00F1E188 /* AccessibilitySVGRoot.h in Headers */, @@ -30908,6 +30933,7 @@ 6E4ABCD5138EA0B70071D291 /* JSHTMLUnknownElement.h in Headers */, E44614170CD6826900FADA75 /* JSHTMLVideoElement.h in Headers */, 81BE20D311F4BC3200915DFA /* JSIDBCursor.h in Headers */, + F050E17823AD70C50011CE47 /* PlatformTouchPoint.h in Headers */, 7C3D8EF01E0B21430023B084 /* JSIDBCursorDirection.h in Headers */, C585A68311D4FB08004C3E4B /* JSIDBDatabase.h in Headers */, C585A69711D4FB13004C3E4B /* JSIDBFactory.h in Headers */, @@ -32821,9 +32847,11 @@ A7DBF8DE1276919C006B6008 /* TextCheckingHelper.h in Headers */, B2C3DA3A0D006C1D00EF6F26 /* TextCodec.h in Headers */, 26E98A10130A9FCA008EB7B2 /* TextCodecASCIIFastPath.h in Headers */, + F050E16823AC9C080011CE47 /* PlatformTouchEvent.h in Headers */, B2C3DA3C0D006C1D00EF6F26 /* TextCodecICU.h in Headers */, B2C3DA3E0D006C1D00EF6F26 /* TextCodecLatin1.h in Headers */, 57EF5E601D20C83900171E60 /* TextCodecReplacement.h in Headers */, + F050E17223AD669F0011CE47 /* TouchEvent.h in Headers */, B2C3DA400D006C1D00EF6F26 /* TextCodecUserDefined.h in Headers */, B2C3DA420D006C1D00EF6F26 /* TextCodecUTF16.h in Headers */, 9343CB8212F25E510033C5EE /* TextCodecUTF8.h in Headers */, @@ -33707,6 +33735,7 @@ CDDE02ED18B3ED6D00CF7FF1 /* CDMSessionAVFoundationObjC.mm in Sources */, CDDE02F018B5651300CF7FF1 /* CDMSessionAVStreamSession.mm in Sources */, CDE5959D1BF2757100A1CBE8 /* CDMSessionMediaSourceAVFObjC.mm in Sources */, + F050E17123AD669F0011CE47 /* TouchEvent.cpp in Sources */, A14090FB1AA51E1D0091191A /* ContentFilterUnblockHandlerCocoa.mm in Sources */, 07AFF4231EFB144900B545B3 /* CoreAudioCaptureSourceIOS.mm in Sources */, 46C696CC1E7205FC00597937 /* CPUMonitor.cpp in Sources */, @@ -33781,6 +33810,7 @@ 51058ADF1D67C229009A538C /* MockGamepad.cpp in Sources */, 51058AE11D67C229009A538C /* MockGamepadProvider.cpp in Sources */, CDF2B0121820540600F2B424 /* MockMediaPlayerMediaSource.cpp in Sources */, + F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */, CDF2B0141820540600F2B424 /* MockMediaSourcePrivate.cpp in Sources */, CDF2B0161820540700F2B424 /* MockSourceBufferPrivate.cpp in Sources */, 2D9BF7421DBFDC27007A7D99 /* NavigatorEME.cpp in Sources */, @@ -33867,6 +33897,7 @@ 538EC8881F993F9C004D22A8 /* UnifiedSource23.cpp in Sources */, DE5F85801FA1ABF4006DB63A /* UnifiedSource24-mm.mm in Sources */, 538EC8891F993F9D004D22A8 /* UnifiedSource24.cpp in Sources */, + F050E16E23AD66630011CE47 /* TouchList.cpp in Sources */, DE5F85811FA1ABF4006DB63A /* UnifiedSource25-mm.mm in Sources */, 538EC88A1F993F9D004D22A8 /* UnifiedSource25.cpp in Sources */, DE5F85821FA1ABF4006DB63A /* UnifiedSource26-mm.mm in Sources */, @@ -34399,6 +34430,7 @@ 2D8B92F1203D13E1009C868F /* UnifiedSource516.cpp in Sources */, 2D8B92F2203D13E1009C868F /* UnifiedSource517.cpp in Sources */, 2D8B92F3203D13E1009C868F /* UnifiedSource518.cpp in Sources */, + F050E16A23AD660C0011CE47 /* Touch.cpp in Sources */, 2D8B92F4203D13E1009C868F /* UnifiedSource519.cpp in Sources */, 2D8B92F5203D13E1009C868F /* UnifiedSource520.cpp in Sources */, 2D8B92F6203D13E1009C868F /* UnifiedSource521.cpp in Sources */, diff --git a/Source/WebCore/css/MediaQueryEvaluator.cpp b/Source/WebCore/css/MediaQueryEvaluator.cpp index 2ac163067f2e00a595c425a91fc3a55617baf689..0f492b539ed56f7f963fdf5a72ab75f8f7ea89ab 100644 --- a/Source/WebCore/css/MediaQueryEvaluator.cpp +++ b/Source/WebCore/css/MediaQueryEvaluator.cpp @@ -387,7 +387,7 @@ static bool deviceAspectRatioEvaluate(CSSValue* value, const CSSToLengthConversi if (!value) return true; - auto size = screenRect(frame.mainFrame().view()).size(); + auto size = frame.page()->screenSize(); bool result = compareAspectRatioValue(value, size.width(), size.height(), op); LOG_WITH_STREAM(MediaQueries, stream << " deviceAspectRatioEvaluate: " << op << " " << aspectRatioValueAsString(value) << " actual screen size " << size << ": " << result); return result; @@ -505,7 +505,7 @@ static bool deviceHeightEvaluate(CSSValue* value, const CSSToLengthConversionDat if (!value) return true; int length; - auto height = screenRect(frame.mainFrame().view()).height(); + auto height = frame.page()->screenSize().height(); if (!computeLength(value, !frame.document()->inQuirksMode(), conversionData, length)) return false; @@ -520,8 +520,10 @@ static bool deviceWidthEvaluate(CSSValue* value, const CSSToLengthConversionData // assume if we have a device, assume non-zero if (!value) return true; + if (!frame.mainFrame().view()) + return false; int length; - auto width = screenRect(frame.mainFrame().view()).width(); + auto width = frame.page()->screenSize().width(); if (!computeLength(value, !frame.document()->inQuirksMode(), conversionData, length)) return false; diff --git a/Source/WebCore/dom/UserGestureIndicator.cpp b/Source/WebCore/dom/UserGestureIndicator.cpp index dfec93b644f72a51bad0bebf396da61c57f6e428..353833a7614a55566862c196bafc598a475536a1 100644 --- a/Source/WebCore/dom/UserGestureIndicator.cpp +++ b/Source/WebCore/dom/UserGestureIndicator.cpp @@ -56,8 +56,7 @@ UserGestureIndicator::UserGestureIndicator(Optional if (state) currentToken() = UserGestureToken::create(state.value(), gestureType); - - if (document && currentToken()->processingUserGesture() && state) { + if (document && state && currentToken()->processingUserGesture()) { document->updateLastHandledUserGestureTimestamp(currentToken()->startTime()); if (processInteractionStyle == ProcessInteractionStyle::Immediate) ResourceLoadObserver::shared().logUserInteractionWithReducedTimeResolution(document->topDocument()); diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp index 4e41fd3f807e8f34bfef3f63f0ba6119a619821e..1f7be602cb2134f8867bf95afe0c9337bce57055 100644 --- a/Source/WebCore/html/FileInputType.cpp +++ b/Source/WebCore/html/FileInputType.cpp @@ -36,6 +36,7 @@ #include "HTMLNames.h" #include "Icon.h" #include "InputTypeNames.h" +#include "InspectorInstrumentation.h" #include "LocalizedStrings.h" #include "RenderFileUploadControl.h" #include "RuntimeEnabledFeatures.h" @@ -205,6 +206,11 @@ void FileInputType::handleDOMActivateEvent(Event& event) if (input.isDisabledFormControl()) return; + bool intercept = false; + InspectorInstrumentation::runOpenPanel(input.document().frame(), element(), &intercept); + if (intercept) + return; + if (!UserGestureIndicator::processingUserGesture()) return; diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp index 7d50ddc7a38a3723e4ee7d66ca97c8acb37c726a..7ee70c6dd4bb84012a682ed648dc3c0cbd8ad211 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp @@ -510,4 +510,24 @@ void InspectorController::didComposite(Frame& frame) InspectorInstrumentation::didComposite(frame); } +void InspectorController::pauseWhenShown() +{ + m_pauseWhenShown = true; +} + +void InspectorController::resumeIfPausedInNewWindow() +{ + m_pauseWhenShown = false; +} + +void InspectorController::didShowNewWindow() +{ + if (!m_pauseWhenShown) + return; + while (m_pauseWhenShown) { + if (RunLoop::cycle() == RunLoop::CycleResult::Stop) + break; + } +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorController.h b/Source/WebCore/inspector/InspectorController.h index cd4497c9cdf7e3dc7fe89ffdbf188d47f2aaa00d..8cadb40ac6cd04fa3921866a6c4d3142518cb0c3 100644 --- a/Source/WebCore/inspector/InspectorController.h +++ b/Source/WebCore/inspector/InspectorController.h @@ -100,6 +100,10 @@ public: WEBCORE_EXPORT void willComposite(Frame&); WEBCORE_EXPORT void didComposite(Frame&); + WEBCORE_EXPORT void pauseWhenShown(); + WEBCORE_EXPORT void resumeIfPausedInNewWindow(); + WEBCORE_EXPORT void didShowNewWindow(); + bool isUnderTest() const { return m_isUnderTest; } void setIsUnderTest(bool isUnderTest) { m_isUnderTest = isUnderTest; } WEBCORE_EXPORT void evaluateForTestInFrontend(const String& script); @@ -149,6 +153,7 @@ private: bool m_isAutomaticInspection { false }; bool m_pauseAfterInitialization = { false }; bool m_didCreateLazyAgents { false }; + bool m_pauseWhenShown { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp index 3dc7b494d6656a91c7dd9c68e1c9eaf789666d01..54ff59eaec197fdd12248cd4542b91db2b5bb83a 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -621,6 +621,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, Frame& frame, const ResourceError&) +{ + if (auto* pageRuntimeAgent = instrumentingAgents.pageRuntimeAgent()) + pageRuntimeAgent->didReceiveMainResourceError(frame); +} + void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents) { if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent()) @@ -653,20 +659,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { - if (!frame.isMainFrame()) - return; - if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent()) - pageAgent->domContentEventFired(); + pageAgent->domContentEventFired(frame); } void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, Frame* frame) { - if (!frame || !frame->isMainFrame()) + if (!frame) return; if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent()) - pageAgent->loadEventFired(); + pageAgent->loadEventFired(*frame); } void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) @@ -744,12 +747,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins pageDOMDebuggerAgent->frameDocumentUpdated(frame); } -void InspectorInstrumentation::loaderDetachedFromFrameImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader& loader) -{ - if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.inspectorPageAgent()) - inspectorPageAgent->loaderDetachedFromFrame(loader); -} - void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { if (frame.isMainFrame()) { @@ -786,6 +783,12 @@ void InspectorInstrumentation::frameClearedScheduledNavigationImpl(Instrumenting inspectorPageAgent->frameClearedScheduledNavigation(frame); } +void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) +{ + if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.inspectorPageAgent()) + inspectorPageAgent->didNavigateWithinPage(frame); +} + void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents, bool useDarkAppearance) { if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.inspectorPageAgent()) @@ -1288,6 +1291,31 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins layerTreeAgent->renderLayerDestroyed(renderLayer); } +void InspectorInstrumentation::runOpenPanelImpl(InstrumentingAgents& instrumentingAgents, HTMLInputElement* element, bool* intercept) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent()) + pageAgent->runOpenPanel(element, intercept); +} + +void InspectorInstrumentation::frameAttachedImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { + if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent()) + pageAgent->frameAttached(frame); +} + +bool InspectorInstrumentation::shouldBypassCSPImpl(InstrumentingAgents& instrumentingAgents) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.inspectorPageAgent()) + return pageAgent->shouldBypassCSP(); + return false; +} + +bool InspectorInstrumentation::interceptRequestImpl(InstrumentingAgents& instrumentingAgents, ResourceLoader& loader, Function&& handler) +{ + if (InspectorNetworkAgent* networkAgent = instrumentingAgents.inspectorNetworkAgent()) + return networkAgent->interceptRequest(loader, WTFMove(handler)); + return false; +} + InstrumentingAgents& InspectorInstrumentation::instrumentingAgentsForWorkerGlobalScope(WorkerGlobalScope& workerGlobalScope) { return workerGlobalScope.inspectorController().m_instrumentingAgents; diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index b246eaa559a75265c890dfa47d01d311c186a403..57460008e1925fe15ea37d1eee194836afed8370 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -45,11 +45,13 @@ #include "HitTestResult.h" #include "InspectorInstrumentationPublic.h" #include "Page.h" +#include "ResourceLoader.h" #include "StorageArea.h" #include "WebAnimation.h" #include #include #include +#include #include #include @@ -77,6 +79,7 @@ class DOMWrapperWorld; class Document; class DocumentLoader; class EventListener; +class HTMLInputElement; class HTTPHeaderMap; class InspectorTimelineAgent; class InstrumentingAgents; @@ -197,6 +200,7 @@ public: static void didReceiveData(Frame*, unsigned long identifier, const char* data, int dataLength, int encodedDataLength); static void didFinishLoading(Frame*, DocumentLoader*, unsigned long identifier, const NetworkLoadMetrics&, ResourceLoader*); static void didFailLoading(Frame*, DocumentLoader*, unsigned long identifier, const ResourceError&); + static void didReceiveMainResourceError(Frame&, const ResourceError&); static void willSendRequest(WorkerGlobalScope&, unsigned long identifier, ResourceRequest&); static void didReceiveResourceResponse(WorkerGlobalScope&, unsigned long identifier, const ResourceResponse&); @@ -223,11 +227,11 @@ public: static void frameDetachedFromParent(Frame&); static void didCommitLoad(Frame&, DocumentLoader*); static void frameDocumentUpdated(Frame&); - static void loaderDetachedFromFrame(Frame&, DocumentLoader&); static void frameStartedLoading(Frame&); static void frameStoppedLoading(Frame&); static void frameScheduledNavigation(Frame&, Seconds delay); static void frameClearedScheduledNavigation(Frame&); + static void didNavigateWithinPage(Frame&); static void defaultAppearanceDidChange(Page&, bool useDarkAppearance); static void willDestroyCachedResource(CachedResource&); @@ -317,6 +321,11 @@ public: static void layerTreeDidChange(Page*); static void renderLayerDestroyed(Page*, const RenderLayer&); + static void runOpenPanel(Frame*, HTMLInputElement*, bool*); + static void frameAttached(Frame*); + static bool shouldBypassCSP(ScriptExecutionContext*); + static bool interceptRequest(ResourceLoader&, Function&&); + static void frontendCreated(); static void frontendDeleted(); static bool hasFrontends() { return InspectorInstrumentationPublic::hasFrontends(); } @@ -417,6 +426,7 @@ private: static void didReceiveDataImpl(InstrumentingAgents&, unsigned long identifier, const char* data, int dataLength, int encodedDataLength); static void didFinishLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const NetworkLoadMetrics&, ResourceLoader*); static void didFailLoadingImpl(InstrumentingAgents&, unsigned long identifier, DocumentLoader*, const ResourceError&); + static void didReceiveMainResourceErrorImpl(InstrumentingAgents&, Frame&, const ResourceError&); static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&); static void didLoadXHRSynchronouslyImpl(InstrumentingAgents&); static void scriptImportedImpl(InstrumentingAgents&, unsigned long identifier, const String& sourceString); @@ -427,11 +437,11 @@ private: static void frameDetachedFromParentImpl(InstrumentingAgents&, Frame&); static void didCommitLoadImpl(InstrumentingAgents&, Frame&, DocumentLoader*); static void frameDocumentUpdatedImpl(InstrumentingAgents&, Frame&); - static void loaderDetachedFromFrameImpl(InstrumentingAgents&, DocumentLoader&); static void frameStartedLoadingImpl(InstrumentingAgents&, Frame&); static void frameStoppedLoadingImpl(InstrumentingAgents&, Frame&); static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay); static void frameClearedScheduledNavigationImpl(InstrumentingAgents&, Frame&); + static void didNavigateWithinPageImpl(InstrumentingAgents&, Frame&); static void defaultAppearanceDidChangeImpl(InstrumentingAgents&, bool useDarkAppearance); static void willDestroyCachedResourceImpl(CachedResource&); @@ -517,6 +527,11 @@ private: static void layerTreeDidChangeImpl(InstrumentingAgents&); static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&); + static void runOpenPanelImpl(InstrumentingAgents&, HTMLInputElement*, bool*); + static void frameAttachedImpl(InstrumentingAgents&, Frame&); + static bool shouldBypassCSPImpl(InstrumentingAgents&); + static bool interceptRequestImpl(InstrumentingAgents&, ResourceLoader&, Function&&); + static InstrumentingAgents& instrumentingAgentsForPage(Page&); static InstrumentingAgents& instrumentingAgentsForWorkerGlobalScope(WorkerGlobalScope&); @@ -1097,6 +1112,13 @@ inline void InspectorInstrumentation::didFailLoading(Frame* frame, DocumentLoade didFailLoadingImpl(*instrumentingAgents, identifier, loader, error); } +inline void InspectorInstrumentation::didReceiveMainResourceError(Frame& frame, const ResourceError& error) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame)) + didReceiveMainResourceErrorImpl(*instrumentingAgents, frame, error); +} + inline void InspectorInstrumentation::didFailLoading(WorkerGlobalScope& workerGlobalScope, unsigned long identifier, const ResourceError& error) { didFailLoadingImpl(instrumentingAgentsForWorkerGlobalScope(workerGlobalScope), identifier, nullptr, error); @@ -1192,13 +1214,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(Frame& frame) frameDocumentUpdatedImpl(*instrumentingAgents, frame); } -inline void InspectorInstrumentation::loaderDetachedFromFrame(Frame& frame, DocumentLoader& loader) -{ - FAST_RETURN_IF_NO_FRONTENDS(void()); - if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame)) - loaderDetachedFromFrameImpl(*instrumentingAgents, loader); -} - inline void InspectorInstrumentation::frameStartedLoading(Frame& frame) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1227,6 +1242,13 @@ inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& fra frameClearedScheduledNavigationImpl(*instrumentingAgents, frame); } +inline void InspectorInstrumentation::didNavigateWithinPage(Frame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame)) + didNavigateWithinPageImpl(*instrumentingAgents, frame); +} + inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page, bool useDarkAppearance) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1677,6 +1699,36 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren renderLayerDestroyedImpl(*instrumentingAgents, renderLayer); } +inline void InspectorInstrumentation::runOpenPanel(Frame* frame, HTMLInputElement* element, bool* intercept) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(*frame)) + runOpenPanelImpl(*instrumentingAgents, element, intercept); +} + +inline void InspectorInstrumentation::frameAttached(Frame* frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(frame)) + frameAttachedImpl(*instrumentingAgents, *frame); +} + +inline bool InspectorInstrumentation::shouldBypassCSP(ScriptExecutionContext* context) +{ + FAST_RETURN_IF_NO_FRONTENDS(false); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForContext(context)) + return shouldBypassCSPImpl(*instrumentingAgents); + return false; +} + +inline bool InspectorInstrumentation::interceptRequest(ResourceLoader& loader, Function&& handler) +{ + FAST_RETURN_IF_NO_FRONTENDS(false); + if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForFrame(loader.frame())) + return interceptRequestImpl(*instrumentingAgents, loader, WTFMove(handler)); + return false; +} + inline InstrumentingAgents* InspectorInstrumentation::instrumentingAgentsForContext(ScriptExecutionContext* context) { return context ? instrumentingAgentsForContext(*context) : nullptr; diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp index 954aaf121a9fa507d83bc10ae37de1f128f7dcfc..9f16be3dbcf4857742ec2ab131e2b2f962a2a47c 100644 --- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp @@ -30,6 +30,11 @@ namespace WebCore { +bool InspectorInstrumentationWebKit::interceptRequestInternal(ResourceLoader& loader, Function&& handler) +{ + return InspectorInstrumentation::interceptRequest(loader, WTFMove(handler)); +} + bool InspectorInstrumentationWebKit::shouldInterceptResponseInternal(const Frame& frame, const ResourceResponse& response) { return InspectorInstrumentation::shouldInterceptResponse(frame, response); diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h index b67e89b80b4e7a8586cac81ade5d58a1bcb0d431..c468bc0981d1fb13272b28095f9f7584840b5861 100644 --- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h +++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h @@ -27,6 +27,7 @@ #include "InspectorInstrumentationPublic.h" #include +#include namespace WebCore { @@ -36,14 +37,22 @@ class SharedBuffer; class WEBCORE_EXPORT InspectorInstrumentationWebKit { public: + static bool interceptRequest(ResourceLoader&, Function&&); static bool shouldInterceptResponse(const Frame*, const ResourceResponse&); static void interceptResponse(const Frame*, const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); private: + static bool interceptRequestInternal(ResourceLoader&, Function&&); static bool shouldInterceptResponseInternal(const Frame&, const ResourceResponse&); static void interceptResponseInternal(const Frame&, const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); }; +inline bool InspectorInstrumentationWebKit::interceptRequest(ResourceLoader& loader, Function&& handler) +{ + FAST_RETURN_IF_NO_FRONTENDS(false); + return interceptRequestInternal(loader, WTFMove(handler)); +} + inline bool InspectorInstrumentationWebKit::shouldInterceptResponse(const Frame* frame, const ResourceResponse& response) { FAST_RETURN_IF_NO_FRONTENDS(false); diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp index d2ca5bbe109aaad182bae185c4d52d8aaecda84d..4fa24557c5a86a967e8d13579e75ce50d72947a4 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -61,12 +61,16 @@ #include "Event.h" #include "EventListener.h" #include "EventNames.h" +#include "File.h" +#include "FileList.h" #include "Frame.h" #include "FrameTree.h" #include "FrameView.h" #include "FullscreenManager.h" +#include "FloatQuad.h" #include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "HTMLParserIdioms.h" @@ -93,11 +97,14 @@ #include "Page.h" #include "Pasteboard.h" #include "PseudoElement.h" +#include "RenderLayer.h" +#include "RenderObject.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" #include "ScriptState.h" #include "SelectorChecker.h" #include "ShadowRoot.h" +#include "SharedBuffer.h" #include "StaticNodeList.h" #include "StyleProperties.h" #include "StyleResolver.h" @@ -128,7 +135,8 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const UChar ellipsisUChar[] = { 0x2026, 0 }; -static Color parseColor(const JSON::Object* colorObject) +// static +Color InspectorDOMAgent::parseColor(const JSON::Object* colorObject) { if (!colorObject) return Color::transparent; @@ -157,7 +165,7 @@ static Color parseConfigColor(const String& fieldName, const JSON::Object* confi RefPtr colorObject; configObject->getObject(fieldName, colorObject); - return parseColor(colorObject.get()); + return InspectorDOMAgent::parseColor(colorObject.get()); } static bool parseQuad(const JSON::Array& quadArray, FloatQuad* quad) @@ -438,6 +446,20 @@ Node* InspectorDOMAgent::assertNode(ErrorString& errorString, int nodeId) return node; } +Node* InspectorDOMAgent::assertNode(ErrorString& errorString, const int* 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(ErrorString& errorString, int nodeId) { Node* node = assertNode(errorString, nodeId); @@ -1329,16 +1351,7 @@ void InspectorDOMAgent::highlightSelector(ErrorString& errorString, const JSON:: void InspectorDOMAgent::highlightNode(ErrorString& errorString, const JSON::Object& highlightInspectorObject, const int* 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; - + Node* node = assertNode(errorString, nodeId, objectId); if (!node) return; @@ -1486,18 +1499,147 @@ void InspectorDOMAgent::setInspectedNode(ErrorString& errorString, int nodeId) m_suppressEventListenerChangedEvent = false; } -void InspectorDOMAgent::resolveNode(ErrorString& errorString, int nodeId, const String* objectGroup, RefPtr& result) +static FloatPoint contentsToRootView(FrameView& containingView, const FloatPoint& point) { - String objectGroupName = objectGroup ? *objectGroup : emptyString(); - Node* node = assertNode(errorString, nodeId); + return containingView.convertToRootView(point - toFloatSize(containingView.documentScrollPositionRelativeToViewOrigin())); +} + +static void frameQuadToViewport(FrameView& containingView, FloatQuad& quad, float pageScaleFactor) +{ + // Return css (not dip) coordinates by scaling back. + quad.setP1(contentsToRootView(containingView, quad.p1()).scaled(1 / pageScaleFactor)); + quad.setP2(contentsToRootView(containingView, quad.p2()).scaled(1 / pageScaleFactor)); + quad.setP3(contentsToRootView(containingView, quad.p3()).scaled(1 / pageScaleFactor)); + quad.setP4(contentsToRootView(containingView, quad.p4()).scaled(1 / pageScaleFactor)); +} + +static RefPtr buildObjectForQuad(const FloatQuad& quad) +{ + auto result = Inspector::Protocol::DOM::Quad::create(); + result->addItem(quad.p1().x()); + result->addItem(quad.p1().y()); + result->addItem(quad.p2().x()); + result->addItem(quad.p2().y()); + result->addItem(quad.p3().x()); + result->addItem(quad.p3().y()); + result->addItem(quad.p4().x()); + result->addItem(quad.p4().y()); + return result; +} + +static RefPtr> buildArrayOfQuads(const Vector& quads) +{ + auto result = JSON::ArrayOf::create(); + for (const auto& quad : quads) + result->addItem(buildObjectForQuad(quad)); + return result; +} + +void InspectorDOMAgent::describeNode(ErrorString& errorString, const String& objectId, Optional& contentFrameId, Optional& ownerFrameId) +{ + Node* node = nodeForObjectId(objectId); + if (!node) { + errorString = "Node not found"_s; + return; + } + + auto* pageAgent = m_instrumentingAgents.inspectorPageAgent(); + if (!pageAgent) { + errorString = "Page agent must be enabled"_s; + return; + } + + String frameId = pageAgent->frameId(node->document().frame()); + if (!frameId.isEmpty()) + ownerFrameId = frameId; + + if (is(*node)) { + const auto& frameOwner = downcast(*node); + String frameId = pageAgent->frameId(frameOwner.contentFrame()); + if (!frameId.isEmpty()) + contentFrameId = frameId; + } +} + +void InspectorDOMAgent::scrollIntoViewIfNeeded(ErrorString& errorString, const String& objectId, const JSON::Object* rect) +{ + Node* node = nodeForObjectId(objectId); + if (!node) { + errorString = "Node not found"_s; + return; + } + node->document().updateLayoutIgnorePendingStylesheets(); + if (!node->isConnected()) { + errorString = "Node is detached from document"_s; + return; + } + RenderObject* renderer = node->renderer(); + if (!renderer) { + errorString = "Node does not have a layout object"_s; + return; + } + bool insideFixed; + LayoutRect absoluteBounds = renderer->absoluteBoundingBoxRect(true, &insideFixed); + if (rect) { + double x = 0.0; + double y = 0.0; + double width = 0.0; + double height = 0.0; + if (!rect->getDouble("x", x) || !rect->getDouble("y", y) || !rect->getDouble("width", width) || !rect->getDouble("height", height)) { + errorString = "Malformed rect"_s; + return; + } + 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))); + } + // Note: we should use ScrollAlignment::alignCenterIfNotVisible, but + // RenderLayer insists on no horizontal scroll if enough of the rect is visible. + ScrollAlignment alignment = ScrollAlignment::alignCenterAlways; + renderer->scrollRectToVisible(absoluteBounds, insideFixed, { SelectionRevealMode::Reveal, alignment, alignment, ShouldAllowCrossOriginScrolling::Yes }); +} + +void InspectorDOMAgent::getContentQuads(ErrorString& errorString, const String& objectId, RefPtr>& contentQuads) +{ + Node* node = nodeForObjectId(objectId); + if (!node) { + errorString = "Node not found"_s; + return; + } + RenderObject* renderer = node->renderer(); + if (!renderer) { + errorString = "Node doesn't have renderer"_s; + return; + } + + // Ensure quads are up to date. + renderer->document().updateLayoutIgnorePendingStylesheets(); + + Frame* containingFrame = renderer->document().frame(); + FrameView* containingView = containingFrame ? containingFrame->view() : nullptr; + if (!containingView) { + errorString = "Internal error: no containing view"_s; + return; + } + Vector quads; + renderer->absoluteQuads(quads); + for (auto& quad : quads) + frameQuadToViewport(*containingView, quad, m_inspectedPage.pageScaleFactor()); + contentQuads = buildArrayOfQuads(quads); +} + +void InspectorDOMAgent::resolveNode(ErrorString& errorString, const int* nodeId, const String* objectId, const int* contextId, const String* objectGroup, RefPtr& result) +{ + Node* node = assertNode(errorString, nodeId, objectId); if (!node) return; - RefPtr object = resolveNode(node, objectGroupName); - if (!object) { + String objectGroupName = objectGroup ? *objectGroup : emptyString(); + result = resolveNode(node, objectGroupName, contextId); + if (!result) { errorString = "Missing injected script for given nodeId"_s; return; } - result = object; } void InspectorDOMAgent::getAttributes(ErrorString& errorString, int nodeId, RefPtr>& result) @@ -2662,7 +2804,7 @@ void InspectorDOMAgent::pushNodeByPathToFrontend(ErrorString& errorString, const errorString = "Missing node for given path"_s; } -RefPtr InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) +RefPtr InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup, const int* contextId) { Document* document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) @@ -2671,12 +2813,16 @@ RefPtr InspectorDOMAgent::resolveNod if (!frame) return nullptr; - auto& state = *mainWorldExecState(frame); - auto injectedScript = m_injectedScriptManager.injectedScriptFor(&state); + InjectedScript injectedScript; + if (contextId) { + injectedScript = m_injectedScriptManager.injectedScriptForId(*contextId); + } else { + injectedScript = m_injectedScriptManager.injectedScriptFor(mainWorldExecState(frame)); + } if (injectedScript.hasNoValue()) return nullptr; - return injectedScript.wrapObject(nodeAsScriptValue(state, node), objectGroup); + return injectedScript.wrapObject(nodeAsScriptValue(*injectedScript.globalObject(), node), objectGroup); } Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value) @@ -2697,4 +2843,46 @@ void InspectorDOMAgent::setAllowEditingUserAgentShadowTrees(ErrorString&, bool a m_allowEditingUserAgentShadowTrees = allow; } +void InspectorDOMAgent::setInputFiles(ErrorString& errorString, const String& objectId, const JSON::Array& files) { + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) { + errorString = "Can not find element's context for given id"_s; + return; + } + Node* node = scriptValueAsNode(injectedScript.findObjectById(objectId)); + if (!node) { + errorString = "Can not find element for given id"_s; + return; + } + if (node->nodeType() != Node::ELEMENT_NODE || node->nodeName() != "INPUT") { + errorString = "Not an input node"_s; + return; + } + HTMLInputElement* element = static_cast(node); + Vector> fileObjects; + for (unsigned i = 0; i < files.length(); ++i) { + RefPtr item = files.get(i); + RefPtr obj; + if (!item->asObject(obj)) { + errorString = "Invalid file payload format"_s; + return; + } + String name; + String type; + String data; + if (!obj->getString("name", name) || !obj->getString("type", type) || !obj->getString("data", data)) { + errorString = "Invalid file payload format"_s; + return; + } + Vector buffer; + if (!base64Decode(data, buffer)) { + errorString = "Unable to decode given content"_s; + return; + } + fileObjects.append(File::create(Blob::create(SharedBuffer::create(WTFMove(buffer)), type), name)); + } + RefPtr fileList = FileList::create(WTFMove(fileObjects)); + element->setFiles(WTFMove(fileList)); +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h index 7df0e83eb53d75c41c554f1401235ba21719414c..ae6f961a7b7fe63ece60e34210bf333bedef2eee 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -54,6 +54,7 @@ namespace WebCore { class AXCoreObject; class CharacterData; +class Color; class DOMEditor; class Document; class Element; @@ -88,6 +89,7 @@ public: static String toErrorString(Exception&&); static String documentURLString(Document*); + static Color parseColor(const JSON::Object*); // 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. @@ -129,7 +131,7 @@ public: void performSearch(ErrorString&, const String& query, const JSON::Array* nodeIds, const bool* caseSensitive, String* searchId, int* resultCount) override; void getSearchResults(ErrorString&, const String& searchId, int fromIndex, int toIndex, RefPtr>&) override; void discardSearchResults(ErrorString&, const String& searchId) override; - void resolveNode(ErrorString&, int nodeId, const String* objectGroup, RefPtr& result) override; + void resolveNode(ErrorString&, const int* nodeId, const String* objectId, const int* contextId, const String* objectGroup, RefPtr& result) override; void getAttributes(ErrorString&, int nodeId, RefPtr>& result) override; void setInspectModeEnabled(ErrorString&, bool enabled, const JSON::Object* highlightConfig, const bool* showRulers) override; void requestNode(ErrorString&, const String& objectId, int* nodeId) override; @@ -148,6 +150,10 @@ public: void focus(ErrorString&, int nodeId) override; void setInspectedNode(ErrorString&, int nodeId) override; void setAllowEditingUserAgentShadowTrees(ErrorString&, bool allow) final; + void describeNode(ErrorString&, const String& objectId, Optional& contentFrameId, Optional& ownerFrameId) override; + void scrollIntoViewIfNeeded(ErrorString&, const String& objectId, const JSON::Object* rect) override; + void getContentQuads(ErrorString&, const String& objectId, RefPtr>&) override; + void setInputFiles(ErrorString&, const String& objectId, const JSON::Array& files) override; // InspectorInstrumentation int identifierForNode(Node&); @@ -185,7 +191,7 @@ public: Node* nodeForId(int nodeId); int boundNodeId(const Node*); - RefPtr resolveNode(Node*, const String& objectGroup); + RefPtr resolveNode(Node*, const String& objectGroup, const int* contextId); bool handleMousePress(); void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); void inspect(Node*); @@ -196,12 +202,15 @@ public: void reset(); Node* assertNode(ErrorString&, int nodeId); + Node* assertNode(ErrorString&, const int* nodeId, const String* objectId); Element* assertElement(ErrorString&, int nodeId); Document* assertDocument(ErrorString&, int nodeId); bool hasBreakpointForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture); int idForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture); + Node* nodeForObjectId(const String& objectId); + private: #if ENABLE(VIDEO) void mediaMetricsTimerFired(); @@ -228,9 +237,8 @@ private: Ref buildObjectForEventListener(const RegisteredEventListener&, int identifier, EventTarget&, const AtomString& eventType, bool disabled, bool hasBreakpoint); RefPtr buildObjectForAccessibilityProperties(Node*); void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf&); - + Node* nodeForPath(const String& path); - Node* nodeForObjectId(const String& objectId); void discardBindings(); diff --git a/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.h b/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.h index b578660fbb3ce176e4e0aeb5a22021dc880e47f0..a7c968bc9f88c7d26e1887bb53106b4af2464753 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.h @@ -40,6 +40,7 @@ class DOMStorageFrontendDispatcher; namespace WebCore { +class Color; class Frame; class Page; class SecurityOrigin; diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp index ee9edb30dd7b3461c4d491dfaf7929011d498bc9..71b51b0261494112b23800fe02f5e31bb90769bb 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp @@ -44,6 +44,7 @@ #include "DocumentLoader.h" #include "DocumentThreadableLoader.h" #include "Frame.h" +#include "FormData.h" #include "FrameLoader.h" #include "HTTPHeaderMap.h" #include "HTTPHeaderNames.h" @@ -56,6 +57,7 @@ #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "NetworkResourcesData.h" +#include "NetworkStateNotifier.h" #include "Page.h" #include "PlatformStrategies.h" #include "ProgressTracker.h" @@ -99,6 +101,11 @@ using namespace Inspector; namespace { +String inspectorInitiatorPrefix() +{ + return "InspectorPageAgent.navigate referrer:"_s; +} + class InspectorThreadableLoaderClient final : public ThreadableLoaderClient { WTF_MAKE_NONCOPYABLE(InspectorThreadableLoaderClient); public: @@ -453,6 +460,13 @@ void InspectorNetworkAgent::willSendRequest(unsigned long identifier, DocumentLo for (auto& entry : m_extraRequestHeaders) request.setHTTPHeaderField(entry.key, entry.value); + if (request.initiatorIdentifier().startsWith(inspectorInitiatorPrefix())) { + String referrer = request.initiatorIdentifier().substring(inspectorInitiatorPrefix().length()); + if (!referrer.isEmpty()) + request.setHTTPReferrer(referrer); + request.setInitiatorIdentifier(String()); + } + auto protocolResourceType = InspectorPageAgent::resourceTypeJSON(type); Document* document = loader && loader->frame() ? loader->frame()->document() : nullptr; @@ -841,6 +855,7 @@ void InspectorNetworkAgent::disable(ErrorString&) m_resourcesData->clear(); m_extraRequestHeaders.clear(); + continuePendingRequests(); continuePendingResponses(); setResourceCachingDisabled(false); @@ -864,6 +879,16 @@ bool InspectorNetworkAgent::shouldIntercept(URL url) return false; } +void InspectorNetworkAgent::continuePendingRequests() +{ + for (auto& pendingRequest : m_pendingInterceptRequests.values()) { + ResourceLoader* loader = pendingRequest->m_loader.get(); + if (loader->identifier()) + pendingRequest->m_callback(false); + } + m_pendingInterceptRequests.clear(); +} + void InspectorNetworkAgent::continuePendingResponses() { for (auto& pendingInterceptResponse : m_pendingInterceptResponses.values()) @@ -1020,17 +1045,15 @@ void InspectorNetworkAgent::resolveWebSocket(ErrorString& errorString, const Str result = injectedScript.wrapObject(webSocketAsScriptValue(state, webSocket), objectGroupName); } -void InspectorNetworkAgent::setInterceptionEnabled(ErrorString& errorString, bool enabled) +void InspectorNetworkAgent::setInterceptionEnabled(ErrorString&, bool enabled, const bool* interceptRequests) { - if (m_interceptionEnabled == enabled) { - errorString = m_interceptionEnabled ? "Interception already enabled"_s : "Interception already disabled"_s; - return; - } - m_interceptionEnabled = enabled; + m_interceptRequests = interceptRequests && *interceptRequests; if (!m_interceptionEnabled) continuePendingResponses(); + if (!m_interceptionEnabled || !m_interceptRequests) + continuePendingRequests(); } void InspectorNetworkAgent::addInterception(ErrorString& errorString, const String& url, const bool* optionalCaseSensitive, const bool* optionalIsRegex, const String* networkStageString) @@ -1112,19 +1135,128 @@ void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response, m_frontendDispatcher->responseIntercepted(requestId, buildObjectForResourceResponse(response, nullptr)); } -void InspectorNetworkAgent::interceptContinue(ErrorString& errorString, const String& requestId) -{ +bool InspectorNetworkAgent::interceptRequest(ResourceLoader& loader, Function&& handler) { + if (!m_interceptionEnabled || !m_interceptRequests) + return false; + String requestId = IdentifiersFactory::requestId(loader.identifier()); + auto pendingRequest = makeUnique(); + pendingRequest->m_loader = &loader; + pendingRequest->m_callback = WTFMove(handler); + m_pendingInterceptRequests.set(requestId, WTFMove(pendingRequest)); + m_frontendDispatcher->requestIntercepted(requestId, buildObjectForResourceRequest(loader.request())); + return true; +} + +void InspectorNetworkAgent::interceptContinue(ErrorString& errorString, const String& requestId, const String* method, const JSON::Object* headers, const String* postData) +{ + auto pendingRequest = m_pendingInterceptRequests.take(requestId); + if (pendingRequest) { + ResourceLoader* loader = pendingRequest->m_loader.get(); + if (!loader->identifier()) { + // Do not throw upon continue of canceled requests. + return; + } + // Safe to const cast at this point, we are only adjusting the method / headers / post. + ResourceRequest* request = const_cast(&loader->request()); + if (method) + request->setHTTPMethod(*method); + if (headers) { + HTTPHeaderMap explicitHeaders; + for (auto& header : *headers) { + String headerValue; + if (header.value->asString(headerValue)) + explicitHeaders.add(header.key, headerValue); + } + request->setHTTPHeaderFields(WTFMove(explicitHeaders)); + } + if (postData) { + Vector buffer; + if (!base64Decode(*postData, buffer)) { + errorString = "Unable to decode given postData"_s; + return; + } + Ref data = FormData::create(buffer); + request->setHTTPBody(WTFMove(data)); + } + pendingRequest->m_callback(false); + return; + } + auto pendingInterceptResponse = m_pendingInterceptResponses.take(requestId); - if (!pendingInterceptResponse) { - errorString = "Missing pending intercept response for given requestId"_s; + if (pendingInterceptResponse) { + pendingInterceptResponse->respondWithOriginalResponse(); return; } - pendingInterceptResponse->respondWithOriginalResponse(); + errorString = "Missing pending intercept response for given requestId"_s; } -void InspectorNetworkAgent::interceptWithResponse(ErrorString& errorString, const String& requestId, const String& content, bool base64Encoded, const String* mimeType, const int* status, const String* statusText, const JSON::Object* headers) +void InspectorNetworkAgent::interceptAsError(ErrorString& errorString, const String& requestId, const String& reason) { + auto pendingRequest = m_pendingInterceptRequests.take(requestId); + if (pendingRequest) { + ResourceLoader* loader = pendingRequest->m_loader.get(); + if (!loader->identifier()) { + errorString = "Unable to abort request, it has already been processed"_s; + return; + } + ResourceError error(errorDomainWebKitInternal, 0, loader->url(), "Request intercepted"_s, ResourceError::Type::General); + if (reason == "AccessControl") + error = ResourceError(errorDomainWebKitInternal, 0, loader->url(), "Access denied"_s, ResourceError::Type::AccessControl); + else if (reason == "Cancellation") + error = ResourceError(errorDomainWebKitInternal, 0, loader->url(), "Request canceled"_s, ResourceError::Type::Cancellation); + else if (reason == "Timeout") + error = ResourceError(errorDomainWebKitInternal, 0, loader->url(), "Request timed out"_s, ResourceError::Type::Timeout); + loader->didFail(error); + pendingRequest->m_callback(true); + return; + } + + errorString = "Missing pending intercept response for given requestId"_s; +} + +void InspectorNetworkAgent::interceptWithResponse(ErrorString& errorString, const String& requestId, const String* content, const bool* base64Encoded, const String* mimeType, const int* status, const String* statusText, const JSON::Object* headers) +{ + auto pendingRequest = m_pendingInterceptRequests.take(requestId); + if (pendingRequest && status && statusText && mimeType && headers) { + RefPtr loader = pendingRequest->m_loader.get(); + if (!loader->identifier()) { + errorString = "Unable to fulfill request, it has already been processed"_s; + return; + } + RefPtr data; + if (base64Encoded && *base64Encoded && content) { + Vector buffer; + if (!base64Decode(*content, buffer)) { + errorString = "Unable to decode given content"_s; + return; + } + data = SharedBuffer::create(WTFMove(buffer)); + } else if (content) { + data = SharedBuffer::create(content->utf8().data(), content->utf8().length()); + } + + ResourceResponse response(pendingRequest->m_loader->url(), *mimeType, data->size(), String()); + response.setSource(ResourceResponse::Source::InspectorOverride); + response.setHTTPStatusCode(*status); + response.setHTTPStatusText(*statusText); + HTTPHeaderMap explicitHeaders; + for (auto& header : *headers) { + String headerValue; + if (header.value->asString(headerValue)) + explicitHeaders.add(header.key, headerValue); + } + response.setHTTPHeaderFields(WTFMove(explicitHeaders)); + response.setHTTPHeaderField(HTTPHeaderName::ContentType, response.mimeType()); + loader->didReceiveResponse(response, [loader, data = data.releaseNonNull()]() mutable { + if (data->size()) + loader->didReceiveBuffer(WTFMove(data), data->size(), DataPayloadWholeResource); + loader->didFinishLoading(NetworkLoadMetrics()); + }); + pendingRequest->m_callback(true); + return; + } + auto pendingInterceptResponse = m_pendingInterceptResponses.take(requestId); if (!pendingInterceptResponse) { errorString = "Missing pending intercept response for given requestId"_s; @@ -1152,20 +1284,26 @@ void InspectorNetworkAgent::interceptWithResponse(ErrorString& errorString, cons } RefPtr overrideData; - if (base64Encoded) { + if (base64Encoded && *base64Encoded && content) { Vector buffer; - if (!base64Decode(content, buffer)) { + if (!base64Decode(*content, buffer)) { errorString = "Unable to decode given content"_s; pendingInterceptResponse->respondWithOriginalResponse(); return; } overrideData = SharedBuffer::create(WTFMove(buffer)); - } else - overrideData = SharedBuffer::create(content.utf8().data(), content.utf8().length()); + } else if (content) { + overrideData = SharedBuffer::create(content->utf8().data(), content->utf8().length()); + } pendingInterceptResponse->respond(overrideResponse, overrideData); } +void InspectorNetworkAgent::setEmulateOfflineState(ErrorString&, bool offline) +{ + platformStrategies()->loaderStrategy()->setEmulateOfflineState(offline); +} + bool InspectorNetworkAgent::shouldTreatAsText(const String& mimeType) { return startsWithLettersIgnoringASCIICase(mimeType, "text/") @@ -1295,6 +1433,11 @@ void InspectorNetworkAgent::searchInRequest(ErrorString& errorString, const Stri results = ContentSearchUtilities::searchInTextByLines(resourceData->content(), query, caseSensitive, isRegex); } +String InspectorNetworkAgent::createInitiatorIdentifierForInspectorNavigation(const String& referrer) +{ + return inspectorInitiatorPrefix() + referrer; +} + void InspectorNetworkAgent::mainFrameNavigated(DocumentLoader& loader) { m_resourcesData->clear(loaderIdentifier(&loader)); diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h index b038a1879c043aa17dae97425693f29be42e3258..d60716b837663004675ffd90bceede4c3a6e98c6 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h @@ -87,11 +87,13 @@ public: void loadResource(const String& frameId, const String& url, Ref&&) final; void getSerializedCertificate(ErrorString&, const String& requestId, String* serializedCertificate) final; void resolveWebSocket(ErrorString&, const String& requestId, const String* objectGroup, RefPtr&) final; - void setInterceptionEnabled(ErrorString&, bool enabled) final; + void setInterceptionEnabled(ErrorString&, bool enabled, const bool* interceptRequests) final; void addInterception(ErrorString&, const String& url, const bool* caseSensitive, const bool* isRegex, const String* networkStageString) final; void removeInterception(ErrorString&, const String& url, const bool* caseSensitive, const bool* isRegex, const String* networkStageString) final; - void interceptContinue(ErrorString&, const String& requestId) final; - void interceptWithResponse(ErrorString&, const String& requestId, const String& content, bool base64Encoded, const String* mimeType, const int* status, const String* statusText, const JSON::Object* headers) final; + void interceptContinue(ErrorString&, const String& requestId, const String* method, const JSON::Object* headers, const String* postData) final; + void interceptAsError(ErrorString&, const String& requestId, const String& reason) final; + void interceptWithResponse(ErrorString&, const String& requestId, const String* content, const bool* base64Encoded, const String* mimeType, const int* status, const String* statusText, const JSON::Object* headers) final; + void setEmulateOfflineState(ErrorString&, bool offline) final; // InspectorInstrumentation void willRecalculateStyle(); @@ -121,10 +123,13 @@ public: bool willInterceptRequest(const ResourceRequest&); bool shouldInterceptResponse(const ResourceResponse&); void interceptResponse(const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); + bool interceptRequest(ResourceLoader& loader, Function&&); void searchOtherRequests(const JSC::Yarr::RegularExpression&, RefPtr>&); void searchInRequest(ErrorString&, const String& requestId, const String& query, bool caseSensitive, bool isRegex, RefPtr>&); + static String createInitiatorIdentifierForInspectorNavigation(const String& referrer); + protected: InspectorNetworkAgent(WebAgentContext&); @@ -141,6 +146,7 @@ private: void willSendRequest(unsigned long identifier, DocumentLoader*, ResourceRequest&, const ResourceResponse& redirectResponse, InspectorPageAgent::ResourceType); bool shouldIntercept(URL); + void continuePendingRequests(); void continuePendingResponses(); WebSocket* webSocketForRequestId(const String& requestId); @@ -191,6 +197,15 @@ private: bool m_responded { false }; }; + class PendingInterceptRequest { + WTF_MAKE_NONCOPYABLE(PendingInterceptRequest); + WTF_MAKE_FAST_ALLOCATED; + public: + PendingInterceptRequest() = default; + RefPtr m_loader; + CompletionHandler m_callback; + }; + std::unique_ptr m_frontendDispatcher; RefPtr m_backendDispatcher; Inspector::InjectedScriptManager& m_injectedScriptManager; @@ -214,6 +229,7 @@ private: }; Vector m_intercepts; HashMap> m_pendingInterceptResponses; + HashMap> m_pendingInterceptRequests; // FIXME: InspectorNetworkAgent should not be aware of style recalculation. RefPtr m_styleRecalculationInitiator; @@ -222,6 +238,7 @@ private: bool m_enabled { false }; bool m_loadingXHRSynchronously { false }; bool m_interceptionEnabled { false }; + bool m_interceptRequests { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp index 44a7da37f588d38e3070e967cdc23a9fd9dad203..bf760c64150ea04e82c979df2fabf73a3fbd7733 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp @@ -32,6 +32,8 @@ #include "config.h" #include "InspectorPageAgent.h" +#include "AXObjectCache.h" +#include "BackForwardController.h" #include "CachedResource.h" #include "CachedResourceLoader.h" #include "Cookie.h" @@ -40,12 +42,15 @@ #include "DOMWrapperWorld.h" #include "Document.h" #include "DocumentLoader.h" +#include "FocusController.h" #include "Frame.h" #include "FrameLoadRequest.h" #include "FrameLoader.h" +#include "FrameLoaderClient.h" #include "FrameSnapshotting.h" #include "FrameView.h" #include "HTMLFrameOwnerElement.h" +#include "HTMLInputElement.h" #include "HTMLNames.h" #include "ImageBuffer.h" #include "InspectorClient.h" @@ -56,19 +61,29 @@ #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "Page.h" +#include "PageRuntimeAgent.h" #include "RenderObject.h" #include "RenderTheme.h" +#include "RuntimeEnabledFeatures.h" #include "ScriptController.h" #include "ScriptSourceCode.h" +#include "ScriptState.h" #include "SecurityOrigin.h" #include "Settings.h" #include "StyleScope.h" #include "TextEncoding.h" +#include "TypingCommand.h" #include "UserGestureIndicator.h" #include #include +#include #include +#include +#include #include +#include +#include +#include #include #include #include @@ -81,7 +96,6 @@ #include "LegacyWebArchive.h" #endif - namespace WebCore { using namespace Inspector; @@ -100,6 +114,11 @@ using namespace Inspector; macro(WebRTCEncryptionEnabled) \ macro(WebSecurityEnabled) +static HashMap>& createdUserWorlds() { + static NeverDestroyed>> nameToWorld; + return nameToWorld; +} + static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result) { if (buffer) { @@ -340,6 +359,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) { @@ -373,11 +393,20 @@ void InspectorPageAgent::enable(ErrorString& errorString) #if HAVE(OS_DARK_MODE_SUPPORT) defaultAppearanceDidChange(m_inspectedPage.defaultUseDarkAppearance()); #endif + + if (!createdUserWorlds().isEmpty()) { + Vector worlds; + for (const auto& world : createdUserWorlds().values()) + worlds.append(world.ptr()); + ensureUserWorldsExistInAllFrames(worlds); + } } void InspectorPageAgent::disable(ErrorString&) { m_instrumentingAgents.setInspectorPageAgent(nullptr); + m_interceptFileChooserDialog = false; + m_bypassCSP = false; ErrorString unused; setShowPaintRects(unused, false); @@ -415,14 +444,35 @@ void InspectorPageAgent::reload(ErrorString&, const bool* optionalReloadFromOrig m_inspectedPage.mainFrame().loader().reload(reloadOptions); } -void InspectorPageAgent::navigate(ErrorString&, const String& url) +void InspectorPageAgent::goBack(ErrorString& errorString) +{ + if (!m_inspectedPage.backForward().goBack()) + errorString = "Failed to go back"_s; +} + +void InspectorPageAgent::goForward(ErrorString& errorString) +{ + if (!m_inspectedPage.backForward().goForward()) + errorString = "Failed to go forward"_s; +} + +void InspectorPageAgent::navigate(ErrorString& errorString, const String& url, const String* frameId, const String* referrer) { UserGestureIndicator indicator { ProcessingUserGesture }; - Frame& frame = m_inspectedPage.mainFrame(); + Frame* frame = frameId ? assertFrame(errorString, *frameId) : &m_inspectedPage.mainFrame(); + if (!frame) + return; + + ResourceRequest resourceRequest { frame->document()->completeURL(url) }; + if (!resourceRequest.url().isValid()) { + errorString = "Cannot navigate to invalid URL"_s; + return; + } - ResourceRequest resourceRequest { frame.document()->completeURL(url) }; - FrameLoadRequest frameLoadRequest { *frame.document(), frame.document()->securityOrigin(), WTFMove(resourceRequest), "_self"_s, LockHistory::No, LockBackForwardList::No, ReferrerPolicy::EmptyString, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown }; - frame.loader().changeLocation(WTFMove(frameLoadRequest)); + if (referrer) + resourceRequest.setInitiatorIdentifier(InspectorNetworkAgent::createInitiatorIdentifierForInspectorNavigation(*referrer)); + FrameLoadRequest frameLoadRequest { *frame->document(), frame->document()->securityOrigin(), WTFMove(resourceRequest), "_self"_s, LockHistory::No, LockBackForwardList::No, ReferrerPolicy::EmptyString, AllowNavigationToInvalidURL::No, NewFrameOpenerPolicy::Allow, ShouldOpenExternalURLsPolicy::ShouldNotAllow, InitiatedByMainFrame::Unknown }; + frame->loader().changeLocation(WTFMove(frameLoadRequest)); } void InspectorPageAgent::overrideUserAgent(ErrorString&, const String* value) @@ -683,15 +733,16 @@ void InspectorPageAgent::setShowPaintRects(ErrorString&, bool show) m_overlay->setShowPaintRects(show); } -void InspectorPageAgent::domContentEventFired() +void InspectorPageAgent::domContentEventFired(Frame& 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(Frame& frame) { - m_frontendDispatcher->loadEventFired(timestamp()); + m_frontendDispatcher->loadEventFired(timestamp(), frameId(&frame)); } void InspectorPageAgent::frameNavigated(Frame& frame) @@ -699,13 +750,18 @@ void InspectorPageAgent::frameNavigated(Frame& frame) m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } +static String globalIDForFrame(Frame& frame) +{ + return makeString(Process::identifier().toUInt64(), ".", frame.loader().client().frameID()->toUInt64()); +} + void InspectorPageAgent::frameDetached(Frame& frame) { - auto identifier = m_frameToIdentifier.take(&frame); - if (identifier.isNull()) + String identifier = globalIDForFrame(frame); + if (!m_identifierToFrame.take(identifier)) return; + m_frontendDispatcher->frameDetached(identifier); - m_identifierToFrame.remove(identifier); } Frame* InspectorPageAgent::frameForId(const String& frameId) @@ -717,20 +773,18 @@ 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 = globalIDForFrame(*frame); + 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; + + return String::number(loader->loaderIDForInspector()); } Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId) @@ -741,11 +795,6 @@ Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& f return frame; } -void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader) -{ - m_loaderToIdentifier.remove(&loader); -} - void InspectorPageAgent::frameStartedLoading(Frame& frame) { m_frontendDispatcher->frameStartedLoading(frameId(&frame)); @@ -766,6 +815,12 @@ void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame) m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame)); } +void InspectorPageAgent::didNavigateWithinPage(Frame& frame) +{ + String url = frame.document()->url().string(); + m_frontendDispatcher->navigatedWithinDocument(frameId(&frame), url); +} + void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance) { m_frontendDispatcher->defaultAppearanceDidChange(useDarkAppearance ? Inspector::Protocol::Page::Appearance::Dark : Inspector::Protocol::Page::Appearance::Light); @@ -823,6 +878,38 @@ void InspectorPageAgent::didRecalculateStyle() m_overlay->update(); } +void InspectorPageAgent::runOpenPanel(HTMLInputElement* element, bool* intercept) +{ + if (m_interceptFileChooserDialog) { + *intercept = true; + } else { + return; + } + Document& document = element->document(); + auto* frame = document.frame(); + if (!frame) + return; + + auto& state = *mainWorldExecState(frame); + auto injectedScript = m_injectedScriptManager.injectedScriptFor(&state); + if (injectedScript.hasNoValue()) + return; + + m_frontendDispatcher->fileChooserOpened(frameId(frame), injectedScript.wrapObject(InspectorDOMAgent::nodeAsScriptValue(state, element), WTF::String())); +} + +void InspectorPageAgent::frameAttached(Frame& frame) +{ + Frame* parent = frame.tree().parent(); + String parentFrameId = frameId(parent); + m_frontendDispatcher->frameAttached(frameId(&frame), parent ? &parentFrameId : nullptr); +} + +bool InspectorPageAgent::shouldBypassCSP() +{ + return m_bypassCSP; +} + Ref InspectorPageAgent::buildObjectForFrame(Frame* frame) { ASSERT_ARG(frame, frame); @@ -966,6 +1053,29 @@ void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, in *outDataURL = snapshot->toDataURL("image/png"_s, WTF::nullopt, PreserveResolution::Yes); } +void InspectorPageAgent::setTimeZone(ErrorString& errorString, const String* timeZone) +{ + if (!timeZone) { + WTF::setTimeZoneForAutomation(String()); + return; + } + bool success = WTF::setTimeZoneForAutomation(*timeZone); + if (!success) + errorString = "Invalid time zone " + *timeZone; +} + +void InspectorPageAgent::setTouchEmulationEnabled(ErrorString& errorString, bool enabled) +{ +#if ENABLE(TOUCH_EVENTS) + RuntimeEnabledFeatures::sharedFeatures().setTouchEventsEnabled(enabled); + UNUSED_PARAM(errorString); +#else + UNUSED_PARAM(enabled); + errorString = "Not supported"_s; +#endif +} + + void InspectorPageAgent::archive(ErrorString& errorString, String* data) { #if ENABLE(WEB_ARCHIVE) && USE(CF) @@ -983,4 +1093,529 @@ void InspectorPageAgent::archive(ErrorString& errorString, String* data) #endif } +void InspectorPageAgent::insertText(ErrorString&, const String& text) +{ + UserGestureIndicator indicator { ProcessingUserGesture }; + Document* focusedDocument = m_inspectedPage.focusController().focusedOrMainFrame().document(); + TypingCommand::insertText(*focusedDocument, text, 0); +} + +static String roleFromObject(RefPtr axObject) +{ + String computedRoleString = axObject->computedRoleString(); + if (!computedRoleString.isEmpty()) + return computedRoleString; + AccessibilityRole role = axObject->roleValue(); + switch(role) { + case AccessibilityRole::Annotation: + return "Annotation"; + case AccessibilityRole::Application: + return "Application"; + case AccessibilityRole::ApplicationAlert: + return "ApplicationAlert"; + case AccessibilityRole::ApplicationAlertDialog: + return "ApplicationAlertDialog"; + case AccessibilityRole::ApplicationDialog: + return "ApplicationDialog"; + case AccessibilityRole::ApplicationGroup: + return "ApplicationGroup"; + case AccessibilityRole::ApplicationLog: + return "ApplicationLog"; + case AccessibilityRole::ApplicationMarquee: + return "ApplicationMarquee"; + case AccessibilityRole::ApplicationStatus: + return "ApplicationStatus"; + case AccessibilityRole::ApplicationTextGroup: + return "ApplicationTextGroup"; + case AccessibilityRole::ApplicationTimer: + return "ApplicationTimer"; + case AccessibilityRole::Audio: + return "Audio"; + case AccessibilityRole::Blockquote: + return "Blockquote"; + case AccessibilityRole::Browser: + return "Browser"; + case AccessibilityRole::BusyIndicator: + return "BusyIndicator"; + case AccessibilityRole::Button: + return "Button"; + case AccessibilityRole::Canvas: + return "Canvas"; + case AccessibilityRole::Caption: + return "Caption"; + case AccessibilityRole::Cell: + return "Cell"; + case AccessibilityRole::CheckBox: + return "CheckBox"; + case AccessibilityRole::ColorWell: + return "ColorWell"; + case AccessibilityRole::Column: + return "Column"; + case AccessibilityRole::ColumnHeader: + return "ColumnHeader"; + case AccessibilityRole::ComboBox: + return "ComboBox"; + case AccessibilityRole::Definition: + return "Definition"; + case AccessibilityRole::Deletion: + return "Deletion"; + case AccessibilityRole::DescriptionList: + return "DescriptionList"; + case AccessibilityRole::DescriptionListTerm: + return "DescriptionListTerm"; + case AccessibilityRole::DescriptionListDetail: + return "DescriptionListDetail"; + case AccessibilityRole::Details: + return "Details"; + case AccessibilityRole::Directory: + return "Directory"; + case AccessibilityRole::DisclosureTriangle: + return "DisclosureTriangle"; + case AccessibilityRole::Div: + return "Div"; + case AccessibilityRole::Document: + return "Document"; + case AccessibilityRole::DocumentArticle: + return "DocumentArticle"; + case AccessibilityRole::DocumentMath: + return "DocumentMath"; + case AccessibilityRole::DocumentNote: + return "DocumentNote"; + case AccessibilityRole::Drawer: + return "Drawer"; + case AccessibilityRole::EditableText: + return "EditableText"; + case AccessibilityRole::Feed: + return "Feed"; + case AccessibilityRole::Figure: + return "Figure"; + case AccessibilityRole::Footer: + return "Footer"; + case AccessibilityRole::Footnote: + return "Footnote"; + case AccessibilityRole::Form: + return "Form"; + case AccessibilityRole::GraphicsDocument: + return "GraphicsDocument"; + case AccessibilityRole::GraphicsObject: + return "GraphicsObject"; + case AccessibilityRole::GraphicsSymbol: + return "GraphicsSymbol"; + case AccessibilityRole::Grid: + return "Grid"; + case AccessibilityRole::GridCell: + return "GridCell"; + case AccessibilityRole::Group: + return "Group"; + case AccessibilityRole::GrowArea: + return "GrowArea"; + case AccessibilityRole::Heading: + return "Heading"; + case AccessibilityRole::HelpTag: + return "HelpTag"; + case AccessibilityRole::HorizontalRule: + return "HorizontalRule"; + case AccessibilityRole::Ignored: + return "Ignored"; + case AccessibilityRole::Inline: + return "Inline"; + case AccessibilityRole::Image: + return "Image"; + case AccessibilityRole::ImageMap: + return "ImageMap"; + case AccessibilityRole::ImageMapLink: + return "ImageMapLink"; + case AccessibilityRole::Incrementor: + return "Incrementor"; + case AccessibilityRole::Insertion: + return "Insertion"; + case AccessibilityRole::Label: + return "Label"; + case AccessibilityRole::LandmarkBanner: + return "LandmarkBanner"; + case AccessibilityRole::LandmarkComplementary: + return "LandmarkComplementary"; + case AccessibilityRole::LandmarkContentInfo: + return "LandmarkContentInfo"; + case AccessibilityRole::LandmarkDocRegion: + return "LandmarkDocRegion"; + case AccessibilityRole::LandmarkMain: + return "LandmarkMain"; + case AccessibilityRole::LandmarkNavigation: + return "LandmarkNavigation"; + case AccessibilityRole::LandmarkRegion: + return "LandmarkRegion"; + case AccessibilityRole::LandmarkSearch: + return "LandmarkSearch"; + case AccessibilityRole::Legend: + return "Legend"; + case AccessibilityRole::Link: + return "Link"; + case AccessibilityRole::List: + return "List"; + case AccessibilityRole::ListBox: + return "ListBox"; + case AccessibilityRole::ListBoxOption: + return "ListBoxOption"; + case AccessibilityRole::ListItem: + return "ListItem"; + case AccessibilityRole::ListMarker: + return "ListMarker"; + case AccessibilityRole::Mark: + return "Mark"; + case AccessibilityRole::MathElement: + return "MathElement"; + case AccessibilityRole::Matte: + return "Matte"; + case AccessibilityRole::Menu: + return "Menu"; + case AccessibilityRole::MenuBar: + return "MenuBar"; + case AccessibilityRole::MenuButton: + return "MenuButton"; + case AccessibilityRole::MenuItem: + return "MenuItem"; + case AccessibilityRole::MenuItemCheckbox: + return "MenuItemCheckbox"; + case AccessibilityRole::MenuItemRadio: + return "MenuItemRadio"; + case AccessibilityRole::MenuListPopup: + return "MenuListPopup"; + case AccessibilityRole::MenuListOption: + return "MenuListOption"; + case AccessibilityRole::Meter: + return "Meter"; + case AccessibilityRole::Outline: + return "Outline"; + case AccessibilityRole::Paragraph: + return "Paragraph"; + case AccessibilityRole::PopUpButton: + return "PopUpButton"; + case AccessibilityRole::Pre: + return "Pre"; + case AccessibilityRole::Presentational: + return "Presentational"; + case AccessibilityRole::ProgressIndicator: + return "ProgressIndicator"; + case AccessibilityRole::RadioButton: + return "RadioButton"; + case AccessibilityRole::RadioGroup: + return "RadioGroup"; + case AccessibilityRole::RowHeader: + return "RowHeader"; + case AccessibilityRole::Row: + return "Row"; + case AccessibilityRole::RowGroup: + return "RowGroup"; + case AccessibilityRole::RubyBase: + return "RubyBase"; + case AccessibilityRole::RubyBlock: + return "RubyBlock"; + case AccessibilityRole::RubyInline: + return "RubyInline"; + case AccessibilityRole::RubyRun: + return "RubyRun"; + case AccessibilityRole::RubyText: + return "RubyText"; + case AccessibilityRole::Ruler: + return "Ruler"; + case AccessibilityRole::RulerMarker: + return "RulerMarker"; + case AccessibilityRole::ScrollArea: + return "ScrollArea"; + case AccessibilityRole::ScrollBar: + return "ScrollBar"; + case AccessibilityRole::SearchField: + return "SearchField"; + case AccessibilityRole::Sheet: + return "Sheet"; + case AccessibilityRole::Slider: + return "Slider"; + case AccessibilityRole::SliderThumb: + return "SliderThumb"; + case AccessibilityRole::SpinButton: + return "SpinButton"; + case AccessibilityRole::SpinButtonPart: + return "SpinButtonPart"; + case AccessibilityRole::SplitGroup: + return "SplitGroup"; + case AccessibilityRole::Splitter: + return "Splitter"; + case AccessibilityRole::StaticText: + return "StaticText"; + case AccessibilityRole::Subscript: + return "Subscript"; + case AccessibilityRole::Summary: + return "Summary"; + case AccessibilityRole::Superscript: + return "Superscript"; + case AccessibilityRole::Switch: + return "Switch"; + case AccessibilityRole::SystemWide: + return "SystemWide"; + case AccessibilityRole::SVGRoot: + return "SVGRoot"; + case AccessibilityRole::SVGText: + return "SVGText"; + case AccessibilityRole::SVGTSpan: + return "SVGTSpan"; + case AccessibilityRole::SVGTextPath: + return "SVGTextPath"; + case AccessibilityRole::TabGroup: + return "TabGroup"; + case AccessibilityRole::TabList: + return "TabList"; + case AccessibilityRole::TabPanel: + return "TabPanel"; + case AccessibilityRole::Tab: + return "Tab"; + case AccessibilityRole::Table: + return "Table"; + case AccessibilityRole::TableHeaderContainer: + return "TableHeaderContainer"; + case AccessibilityRole::TextArea: + return "TextArea"; + case AccessibilityRole::TextGroup: + return "TextGroup"; + case AccessibilityRole::Term: + return "Term"; + case AccessibilityRole::Time: + return "Time"; + case AccessibilityRole::Tree: + return "Tree"; + case AccessibilityRole::TreeGrid: + return "TreeGrid"; + case AccessibilityRole::TreeItem: + return "TreeItem"; + case AccessibilityRole::TextField: + return "TextField"; + case AccessibilityRole::ToggleButton: + return "ToggleButton"; + case AccessibilityRole::Toolbar: + return "Toolbar"; + case AccessibilityRole::Unknown: + return "Unknown"; + case AccessibilityRole::UserInterfaceTooltip: + return "UserInterfaceTooltip"; + case AccessibilityRole::ValueIndicator: + return "ValueIndicator"; + case AccessibilityRole::Video: + return "Video"; + case AccessibilityRole::WebApplication: + return "WebApplication"; + case AccessibilityRole::WebArea: + return "WebArea"; + case AccessibilityRole::WebCoreLink: + return "WebCoreLink"; + case AccessibilityRole::Window: + return "Window"; + }; + return "Unknown"; +} + +static RefPtr snapshotForAXObject(RefPtr axObject, Node* nodeToFind) +{ + auto axNode = Inspector::Protocol::Page::AXNode::create() + .setRole(roleFromObject(axObject)) + .release(); + + if (!axObject->computedLabel().isEmpty()) + axNode->setName(axObject->computedLabel()); + if (!axObject->stringValue().isEmpty()) + axNode->setValue(JSON::Value::create(axObject->stringValue())); + if (!axObject->accessibilityDescription().isEmpty()) + axNode->setDescription(axObject->accessibilityDescription()); + if (!axObject->keyShortcutsValue().isEmpty()) + axNode->setKeyshortcuts(axObject->keyShortcutsValue()); + if (!axObject->valueDescription().isEmpty()) + axNode->setValuetext(axObject->valueDescription()); + if (!axObject->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()); + bool multiline = axObject->ariaIsMultiline() || axObject->roleValue() == AccessibilityRole::TextArea; + if (multiline) + axNode->setMultiline(multiline); + if (axObject->isMultiSelectable()) + axNode->setMultiselectable(axObject->isMultiSelectable()); + if (axObject->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; + } + } + if (axObject->supportsPressed()) { + AccessibilityButtonState checkedState = axObject->checkboxOrRadioValue(); + switch (checkedState) { + case AccessibilityButtonState::On: + axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::True); + break; + case AccessibilityButtonState::Off: + axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::False); + break; + case AccessibilityButtonState::Mixed: + axNode->setPressed(Inspector::Protocol::Page::AXNode::Pressed::Mixed); + break; + } + } + unsigned level = axObject->hierarchicalLevel() ? axObject->hierarchicalLevel() : axObject->headingLevel(); + if (level) + axNode->setLevel(level); + if (axObject->minValueForRange() != 0) + axNode->setValuemin(axObject->minValueForRange()); + if (axObject->maxValueForRange() != 0) + axNode->setValuemax(axObject->maxValueForRange()); + if (axObject->supportsAutoComplete()) + axNode->setAutocomplete(axObject->autoCompleteValue()); + if (axObject->hasPopup()) + axNode->setHaspopup(axObject->popupValue()); + + String invalidValue = axObject->invalidStatus(); + if (invalidValue != "false") { + if (invalidValue == "grammar") + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Grammar); + else if (invalidValue == "spelling") + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Spelling); + else // Future versions of ARIA may allow additional truthy values. Ex. format, order, or size. + axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::True); + } + switch (axObject->orientation()) { + case AccessibilityOrientation::Undefined: + break; + case AccessibilityOrientation::Vertical: + axNode->setOrientation("vertical"_s); + break; + case AccessibilityOrientation::Horizontal: + axNode->setOrientation("horizontal"_s); + break; + } + + if (axObject->isKeyboardFocusable()) + axNode->setFocusable(axObject->isKeyboardFocusable()); + + if (nodeToFind && axObject->node() == nodeToFind) + axNode->setFound(true); + + if (axObject->hasChildren()) { + RefPtr> children = JSON::ArrayOf::create(); + for (auto& childObject : axObject->children()) + children->addItem(snapshotForAXObject(childObject, nodeToFind)); + axNode->setChildren(children); + } + return axNode; +} + + +void InspectorPageAgent::accessibilitySnapshot(ErrorString& errorString, const String* objectId, RefPtr& out_axNode) +{ + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); + auto document = makeRefPtr(m_inspectedPage.mainFrame().document()); + if (!document) { + errorString = "No document for main frame"_s; + return; + } + AXObjectCache* axObjectCache = document->axObjectCache(); + if (!axObjectCache) { + errorString = "No AXObjectCache for main document"_s; + return; + } + AXCoreObject* axObject = axObjectCache->rootObject(); + if (!axObject) { + errorString = "No AXObject for main document"_s; + return; + } + + Node* node = nullptr; + if (objectId) { + InspectorDOMAgent* domAgent = m_instrumentingAgents.inspectorDOMAgent(); + ASSERT(domAgent); + node = domAgent->nodeForObjectId(*objectId); + if (!node) { + errorString = "No Node for objectId"_s; + return; + } + } + + out_axNode = snapshotForAXObject(makeRefPtr(axObject), node); +} + +void InspectorPageAgent::setInterceptFileChooserDialog(ErrorString&, bool enabled) +{ + m_interceptFileChooserDialog = enabled; +} + +void InspectorPageAgent::setDefaultBackgroundColorOverride(ErrorString& errorString, const JSON::Object* color) +{ + FrameView* view = m_inspectedPage.mainFrame().view(); + if (!view) { + errorString = "Internal error: No frame view to set color two"_s; + return; + } + if (!color) { + view->updateBackgroundRecursively(Optional()); + return; + } + view->updateBackgroundRecursively(InspectorDOMAgent::parseColor(color)); +} + +void InspectorPageAgent::createUserWorld(ErrorString& errorString, const String& name) +{ + if (createdUserWorlds().contains(name)) { + errorString = "World with the given name already exists"_s; + return; + } + + Ref world = ScriptController::createWorld(name, ScriptController::WorldType::User); + ensureUserWorldsExistInAllFrames({world.ptr()}); + createdUserWorlds().set(name, WTFMove(world)); +} + +void InspectorPageAgent::ensureUserWorldsExistInAllFrames(const Vector& worlds) +{ + for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) { + for (auto* world : worlds) + frame->windowProxy().jsWindowProxy(*world)->window(); + } +} + +void InspectorPageAgent::setBypassCSP(ErrorString&, bool enabled) +{ + m_bypassCSP = enabled; +} + +void InspectorPageAgent::crash(ErrorString&) +{ + CRASH(); +} + +void InspectorPageAgent::setScreenSizeOverride(ErrorString&, int width, int height) +{ + Optional size; + if (width && height) + size = FloatSize(width, height); + m_inspectedPage.setOverrideScreenSize(size); +} + + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h index 110173dbbfe819226b6c4caa0f65a5dee8c39f2b..f59486b7e1635ceaa67f3fe5968e8e0e42a023b9 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h @@ -40,11 +40,16 @@ #include #include +namespace Inspector { +class InjectedScriptManager; +} + namespace WebCore { class DOMWrapperWorld; class DocumentLoader; class Frame; +class HTMLInputElement; class InspectorClient; class InspectorOverlay; class Page; @@ -97,7 +102,9 @@ public: void enable(ErrorString&) override; void disable(ErrorString&) override; void reload(ErrorString&, const bool* optionalReloadFromOrigin, const bool* optionalRevalidateAllResources) override; - void navigate(ErrorString&, const String& url) override; + void goBack(ErrorString&) override; + void goForward(ErrorString&) override; + void navigate(ErrorString&, const String& url, const String* frameId, const String* referrer) override; void overrideUserAgent(ErrorString&, const String* value) override; void overrideSetting(ErrorString&, const String& setting, const bool* value) override; void getCookies(ErrorString&, RefPtr>& cookies) override; @@ -111,20 +118,30 @@ public: void setShowPaintRects(ErrorString&, bool show) override; void setEmulatedMedia(ErrorString&, const String&) override; void setForcedAppearance(ErrorString&, const String&) override; + void setTimeZone(ErrorString&, const String*) override; + void setTouchEmulationEnabled(ErrorString&, bool) override; void snapshotNode(ErrorString&, int nodeId, String* outDataURL) override; - void snapshotRect(ErrorString&, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL) override; + void snapshotRect(ErrorString&, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL) override; void archive(ErrorString&, String* data) override; + void insertText(ErrorString&, const String& text) override; + void accessibilitySnapshot(ErrorString&, const String* objectId, RefPtr& out_axNode) override; + void setInterceptFileChooserDialog(ErrorString&, bool enabled) override; + void setDefaultBackgroundColorOverride(ErrorString&, const JSON::Object*) override; + void createUserWorld(ErrorString&, const String&) override; + void setBypassCSP(ErrorString&, bool) override; + void crash(ErrorString&) override; + void setScreenSizeOverride(ErrorString&, int width, int height) override; // InspectorInstrumentation - void domContentEventFired(); - void loadEventFired(); + void domContentEventFired(Frame&); + void loadEventFired(Frame&); void frameNavigated(Frame&); void frameDetached(Frame&); - void loaderDetachedFromFrame(DocumentLoader&); void frameStartedLoading(Frame&); void frameStoppedLoading(Frame&); void frameScheduledNavigation(Frame&, Seconds delay); void frameClearedScheduledNavigation(Frame&); + void didNavigateWithinPage(Frame&); void defaultAppearanceDidChange(bool useDarkAppearance); void applyUserAgentOverride(String&); void applyEmulatedMedia(String&); @@ -133,6 +150,9 @@ public: void didLayout(); void didScroll(); void didRecalculateStyle(); + void runOpenPanel(HTMLInputElement* element, bool* intercept); + void frameAttached(Frame&); + bool shouldBypassCSP(); Frame* frameForId(const String& frameId); WEBCORE_EXPORT String frameId(Frame*); @@ -141,6 +161,7 @@ public: private: double timestamp(); + void ensureUserWorldsExistInAllFrames(const Vector&); static bool mainResourceContent(Frame*, bool withBase64Encode, String* result); static bool dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result); @@ -152,18 +173,19 @@ private: RefPtr m_backendDispatcher; Page& m_inspectedPage; + Inspector::InjectedScriptManager& m_injectedScriptManager; InspectorClient* m_client { nullptr }; InspectorOverlay* m_overlay { nullptr }; - HashMap m_frameToIdentifier; HashMap m_identifierToFrame; - HashMap m_loaderToIdentifier; String m_userAgentOverride; String m_emulatedMedia; String m_forcedAppearance; String m_bootstrapScript; bool m_isFirstLayoutAfterOnLoad { false }; bool m_showPaintRects { false }; + bool m_interceptFileChooserDialog { false }; + bool m_bypassCSP { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp b/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp index 5b7d17a424be41789f73e795736defb8fdf4ed1b..ee571acbf3a4c34cd7039ddd04febe36164a7346 100644 --- a/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp @@ -160,7 +160,11 @@ void InspectorWorkerAgent::connectToWorkerInspectorProxy(WorkerInspectorProxy* p m_connectedProxies.set(proxy->identifier(), proxy); - m_frontendDispatcher->workerCreated(proxy->identifier(), proxy->url()); + ASSERT(is(proxy->scriptExecutionContext())); + Document& document = downcast(*proxy->scriptExecutionContext()); + auto* pageAgent = m_instrumentingAgents.inspectorPageAgent(); + m_frontendDispatcher->workerCreated(proxy->identifier(), proxy->url(), + pageAgent ? pageAgent->frameId(document.frame()) : emptyString()); } void InspectorWorkerAgent::disconnectFromWorkerInspectorProxy(WorkerInspectorProxy* proxy) diff --git a/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp b/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp index cc0b0526f19f806ce621521d0771cc5f30d43840..6b54fa315ac22af78f2bf1befef204ca48308200 100644 --- a/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageDebuggerAgent.cpp @@ -38,6 +38,7 @@ #include "Frame.h" #include "InspectorPageAgent.h" #include "InstrumentingAgents.h" +#include "JSDOMWindowBase.h" #include "Page.h" #include "PageConsoleClient.h" #include "PageScriptDebugServer.h" @@ -70,8 +71,11 @@ bool PageDebuggerAgent::enabled() const void PageDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, const bool* emulateUserGesture, RefPtr& result, Optional& wasThrown, Optional& savedResultIndex) { + InjectedScript injectedScript = injectedScriptManager().injectedScriptForObjectId(callFrameId); + JSC::JSGlobalObject* globalObject = injectedScript.globalObject(); + Document* document = globalObject ? activeDOMWindow(*globalObject).document() : nullptr; auto shouldEmulateUserGesture = emulateUserGesture && *emulateUserGesture; - UserGestureEmulationScope userGestureScope(m_inspectedPage, shouldEmulateUserGesture); + UserGestureEmulationScope userGestureScope(m_inspectedPage, shouldEmulateUserGesture, document); WebDebuggerAgent::evaluateOnCallFrame(errorString, callFrameId, expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, saveResult, emulateUserGesture, result, wasThrown, savedResultIndex); } diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp index 63336051bb0050d6a55eb5543b0349eb964bbb7a..eecfb5a50196c6d9ca353e9b7aedbd4d6feb690c 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp @@ -35,12 +35,14 @@ #include "DOMWrapperWorld.h" #include "Document.h" #include "Frame.h" +#include "FrameLoader.h" #include "InspectorPageAgent.h" #include "InstrumentingAgents.h" #include "JSDOMWindowBase.h" #include "Page.h" #include "PageConsoleClient.h" #include "ScriptController.h" +#include "ScriptSourceCode.h" #include "ScriptState.h" #include "SecurityOrigin.h" #include "UserGestureEmulationScope.h" @@ -106,6 +108,15 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld notifyContextCreated(pageAgent->frameId(&frame), frame.script().globalObject(world), world); } +void PageRuntimeAgent::didReceiveMainResourceError(Frame& frame) +{ + if (frame.loader().stateMachine().isDisplayingInitialEmptyDocument()) { + // Ensure execution context is created for the empty docment to make + // it usable in case loading failed. + mainWorldExecState(&frame); + } +} + InjectedScript PageRuntimeAgent::injectedScriptForEval(ErrorString& errorString, const int* executionContextId) { if (!executionContextId) { @@ -194,13 +205,21 @@ void PageRuntimeAgent::notifyContextCreated(const String& frameId, JSC::JSGlobal void PageRuntimeAgent::evaluate(ErrorString& errorString, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const int* executionContextId, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, const bool* emulateUserGesture, RefPtr& result, Optional& wasThrown, Optional& savedResultIndex) { - UserGestureEmulationScope userGestureScope(m_inspectedPage, asBool(emulateUserGesture)); + InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId); + if (!errorString.isEmpty()) + return; + JSC::JSGlobalObject* globalObject = injectedScript.globalObject(); + Document* document = globalObject ? activeDOMWindow(*globalObject).document() : nullptr; + UserGestureEmulationScope userGestureScope(m_inspectedPage, asBool(emulateUserGesture), document); InspectorRuntimeAgent::evaluate(errorString, expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, executionContextId, returnByValue, generatePreview, saveResult, emulateUserGesture, result, wasThrown, savedResultIndex); } void PageRuntimeAgent::callFunctionOn(ErrorString& errorString, const String& objectId, const String& expression, const JSON::Array* optionalArguments, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* emulateUserGesture, RefPtr& result, Optional& wasThrown) { - UserGestureEmulationScope userGestureScope(m_inspectedPage, asBool(emulateUserGesture)); + InjectedScript injectedScript = injectedScriptManager().injectedScriptForObjectId(objectId); + JSC::JSGlobalObject* globalObject = injectedScript.globalObject(); + Document* document = globalObject ? activeDOMWindow(*globalObject).document() : nullptr; + UserGestureEmulationScope userGestureScope(m_inspectedPage, asBool(emulateUserGesture), document); InspectorRuntimeAgent::callFunctionOn(errorString, objectId, expression, optionalArguments, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, emulateUserGesture, result, wasThrown); } diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h index 2af3739b7fe7c16faa7d8d2797ce6d010215398d..80bfde6120874e16fb173f707fd0bd8a3e5067a0 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h @@ -63,6 +63,7 @@ public: // InspectorInstrumentation void frameNavigated(Frame&); void didClearWindowObjectInWorld(Frame&, DOMWrapperWorld&); + void didReceiveMainResourceError(Frame&); private: Inspector::InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) override; @@ -73,7 +74,6 @@ private: std::unique_ptr m_frontendDispatcher; RefPtr m_backendDispatcher; - InstrumentingAgents& m_instrumentingAgents; Page& m_inspectedPage; diff --git a/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.cpp b/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.cpp index 633bce6e8f3c0785632eb7f26d172f6016b3efd9..14f531504bb2b96646d1a48092a0b132b0510f55 100644 --- a/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.cpp +++ b/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.cpp @@ -39,9 +39,9 @@ namespace WebCore { -UserGestureEmulationScope::UserGestureEmulationScope(Page& inspectedPage, bool emulateUserGesture) +UserGestureEmulationScope::UserGestureEmulationScope(Page& inspectedPage, bool emulateUserGesture, Document* document) : m_pageChromeClient(inspectedPage.chrome().client()) - , m_gestureIndicator(emulateUserGesture ? Optional(ProcessingUserGesture) : WTF::nullopt) + , m_gestureIndicator(emulateUserGesture ? Optional(ProcessingUserGesture) : WTF::nullopt, document) , m_emulateUserGesture(emulateUserGesture) , m_userWasInteracting(false) { diff --git a/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.h b/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.h index b94ed78ad3dbea19543c1fd54653f0481e52fb7c..6341c7ff7ef53577f33c19ecad1b8bfbd674d051 100644 --- a/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.h +++ b/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.h @@ -38,11 +38,12 @@ namespace WebCore { class ChromeClient; class Page; +class Document; class UserGestureEmulationScope { WTF_MAKE_NONCOPYABLE(UserGestureEmulationScope); public: - UserGestureEmulationScope(Page& inspectedPage, bool emulateUserGesture); + UserGestureEmulationScope(Page& inspectedPage, bool emulateUserGesture, Document* document); ~UserGestureEmulationScope(); private: diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp index 1511f5a7d4b038e7a8d2ddc4ae3e5060486fd794..80c08e8065c27724e8130fb7b2b164dbbc018937 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp @@ -1289,8 +1289,6 @@ void DocumentLoader::detachFromFrame() if (!m_frame) return; - InspectorInstrumentation::loaderDetachedFromFrame(*m_frame, *this); - observeFrame(nullptr); } diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h index d6a3d0acd246de70cb485880a04b38941c832f65..61c8d5478f5eefccf88532bebf69b94d97e8a88c 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h @@ -163,9 +163,13 @@ public: WEBCORE_EXPORT virtual void detachFromFrame(); + virtual void replacedByFragmentNavigation(Frame&) { } + WEBCORE_EXPORT FrameLoader* frameLoader() const; WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const; WEBCORE_EXPORT RefPtr mainResourceData() const; + + virtual uint64_t loaderIDForInspector() { return 0; } DocumentWriter& writer() const { return m_writer; } diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp index 0f4a5283f5a3ef22d7e4203e660acf41f2545f19..9b3b2cf7df8310012bcc341abd40266d317e0cd4 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -1183,6 +1183,7 @@ void FrameLoader::loadInSameDocument(const URL& url, SerializedScriptValue* stat } m_client.dispatchDidNavigateWithinPage(); + InspectorInstrumentation::didNavigateWithinPage(m_frame); m_frame.document()->statePopped(stateObject ? Ref { *stateObject } : SerializedScriptValue::nullValue()); m_client.dispatchDidPopStateWithinPage(); @@ -1369,6 +1370,8 @@ void FrameLoader::loadURL(FrameLoadRequest&& frameLoadRequest, const String& ref ASSERT(newLoadType != FrameLoadType::Same); + request.setInitiatorIdentifier(frameLoadRequest.resourceRequest().initiatorIdentifier()); + // The search for a target frame is done earlier in the case of form submission. Frame* targetFrame = isFormSubmission ? nullptr : findFrameForNavigation(effectiveFrameName); if (targetFrame && targetFrame != &m_frame) { @@ -1501,6 +1504,7 @@ void FrameLoader::load(FrameLoadRequest&& request) void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, NavigationAction&& action, LockHistory lockHistory, FrameLoadType type, RefPtr&& formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL, const String& downloadAttribute, CompletionHandler&& completionHandler) { + InspectorInstrumentation::frameScheduledNavigation(m_frame, Seconds(0)); FRAMELOADER_RELEASE_LOG_IF_ALLOWED(ResourceLoading, "loadWithNavigationAction: frame load started"); Ref loader = m_client.createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); @@ -1603,6 +1607,8 @@ 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 { *m_frame.document(), loader->request(), InitiatedByMainFrame::Unknown, policyChecker().loadType(), isFormSubmission }; @@ -3196,6 +3202,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error) checkCompleted(); if (m_frame.page()) checkLoadComplete(); + + InspectorInstrumentation::didReceiveMainResourceError(m_frame, error); } void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue) @@ -3958,9 +3966,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { - if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) - return; - Vector> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) @@ -3969,13 +3974,13 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { - if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript) || !m_frame.windowProxy().existingJSWindowProxy(world)) - return; + if (m_frame.windowProxy().existingJSWindowProxy(world)) { + if (m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) + m_client.dispatchDidClearWindowObjectInWorld(world); - m_client.dispatchDidClearWindowObjectInWorld(world); - - if (Page* page = m_frame.page()) - page->inspectorController().didClearWindowObjectInWorld(m_frame, world); + if (Page* page = m_frame.page()) + page->inspectorController().didClearWindowObjectInWorld(m_frame, world); + } InspectorInstrumentation::didClearWindowObjectInWorld(m_frame, world); } diff --git a/Source/WebCore/loader/LoaderStrategy.h b/Source/WebCore/loader/LoaderStrategy.h index 579d9038f317d45d27c84a27e3f21cff0ae8fddf..9dc41a6ff78b85e229927409b309e01adce2f27a 100644 --- a/Source/WebCore/loader/LoaderStrategy.h +++ b/Source/WebCore/loader/LoaderStrategy.h @@ -80,6 +80,7 @@ public: virtual bool isOnLine() const = 0; virtual void addOnlineStateChangeListener(WTF::Function&&) = 0; + virtual void setEmulateOfflineState(bool) {}; virtual bool shouldPerformSecurityChecks() const { return false; } virtual bool havePerformedSecurityChecks(const ResourceResponse&) const { return false; } diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp index e24fded2225f1c1918f454017566717e20484eab..30e4b7a986418c4b4f6c799b858b608206e22bb5 100644 --- a/Source/WebCore/loader/ProgressTracker.cpp +++ b/Source/WebCore/loader/ProgressTracker.cpp @@ -154,6 +154,8 @@ void ProgressTracker::progressCompleted(Frame& frame) if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame) finalProgressComplete(); + InspectorInstrumentation::frameStoppedLoading(frame); + m_client->didChangeEstimatedProgress(); } @@ -179,8 +181,6 @@ void ProgressTracker::finalProgressComplete() frame->loader().client().setMainFrameDocumentReady(true); m_client->progressFinished(*frame); frame->loader().loadProgressingStatusChanged(); - - InspectorInstrumentation::frameStoppedLoading(*frame); } void ProgressTracker::incrementProgress(unsigned long identifier, const ResourceResponse& response) diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp index fb61b6fd24b34a91e71b0064615b6a22675a5515..30d793a10b9689e55495db9e5e986735e2c025f8 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -809,9 +809,7 @@ bool EventHandler::handleMousePressEvent(const MouseEventWithHitTestResults& eve m_mousePressNode = event.targetNode(); m_frame.document()->setFocusNavigationStartingNode(event.targetNode()); -#if ENABLE(DRAG_SUPPORT) m_dragStartPosition = event.event().position(); -#endif m_mousePressed = true; m_selectionInitiationState = HaveNotStartedSelection; @@ -850,8 +848,6 @@ VisiblePosition EventHandler::selectionExtentRespectingEditingBoundary(const Vis return targetNode->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr); } -#if ENABLE(DRAG_SUPPORT) - #if !PLATFORM(IOS_FAMILY) bool EventHandler::supportsSelectionUpdatesOnMouseDrag() const @@ -873,8 +869,10 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e Ref protectedFrame(m_frame); +#if ENABLE(DRAG_SUPPORT) if (handleDrag(event, checkDragHysteresis)) return true; +#endif Node* targetNode = event.targetNode(); if (event.event().button() != LeftButton || !targetNode) @@ -895,7 +893,9 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e ASSERT(m_mouseDownMayStartSelect || m_mouseDownMayStartAutoscroll); #endif +#if ENABLE(DRAG_SUPPORT) m_mouseDownMayStartDrag = false; +#endif if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { m_autoscrollController->startAutoscrollForSelection(renderer); @@ -912,6 +912,8 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e return true; } +#if ENABLE(DRAG_SUPPORT) + bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const { // This is a pre-flight check of whether the event might lead to a drag being started. Be careful @@ -943,6 +945,8 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const return targetElement && page->dragController().draggableElement(&m_frame, targetElement, result.roundedPointInInnerNodeFrame(), state); } +#endif // ENABLE(DRAG_SUPPORT) + void EventHandler::updateSelectionForMouseDrag() { if (!supportsSelectionUpdatesOnMouseDrag()) @@ -1034,7 +1038,6 @@ void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResul m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(), FrameSelection::AdjustEndpointsAtBidiBoundary); } -#endif // ENABLE(DRAG_SUPPORT) void EventHandler::lostMouseCapture() { @@ -1082,9 +1085,7 @@ bool EventHandler::handleMouseReleaseEvent(const MouseEventWithHitTestResults& e // on the selection, the selection goes away. However, if we are // editing, place the caret. if (m_mouseDownWasSingleClickInSelection && m_selectionInitiationState != ExtendedSelection -#if ENABLE(DRAG_SUPPORT) && m_dragStartPosition == event.event().position() -#endif && m_frame.selection().isRange() && event.event().button() != RightButton) { VisibleSelection newSelection; @@ -2039,10 +2040,8 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseE return true; swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), false, 0, platformMouseEvent, true); -#if ENABLE(DRAG_SUPPORT) if (!swallowEvent) swallowEvent = handleMouseDraggedEvent(mouseEvent); -#endif return swallowEvent; } diff --git a/Source/WebCore/page/EventHandler.h b/Source/WebCore/page/EventHandler.h index b19f13f229355dc5957d32c2d0ebf9a3990759d7..786a37d815f0972649064a14f05f73ce113da877 100644 --- a/Source/WebCore/page/EventHandler.h +++ b/Source/WebCore/page/EventHandler.h @@ -132,9 +132,7 @@ public: WEBCORE_EXPORT VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection&, const LayoutPoint&, Node*); -#if ENABLE(DRAG_SUPPORT) void updateSelectionForMouseDrag(); -#endif #if ENABLE(PAN_SCROLLING) void didPanScrollStart(); @@ -364,10 +362,8 @@ private: bool handleMousePressEventDoubleClick(const MouseEventWithHitTestResults&); bool handleMousePressEventTripleClick(const MouseEventWithHitTestResults&); -#if ENABLE(DRAG_SUPPORT) bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&, CheckDragHysteresis = ShouldCheckDragHysteresis); bool shouldAllowMouseDownToStartDrag() const; -#endif WEBCORE_EXPORT bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&); @@ -454,10 +450,8 @@ private: void defaultTabEventHandler(KeyboardEvent&); void defaultArrowEventHandler(FocusDirection, KeyboardEvent&); -#if ENABLE(DRAG_SUPPORT) DragSourceAction updateDragSourceActionsAllowed() const; bool supportsSelectionUpdatesOnMouseDrag() const; -#endif // The following are called at the beginning of handleMouseUp and handleDrag. // If they return true it indicates that they have consumed the event. @@ -465,9 +459,10 @@ private: #if ENABLE(DRAG_SUPPORT) bool eventLoopHandleMouseDragged(const MouseEventWithHitTestResults&); - void updateSelectionForMouseDrag(const HitTestResult&); #endif + void updateSelectionForMouseDrag(const HitTestResult&); + enum class SetOrClearLastScrollbar { Clear, Set }; void updateLastScrollbarUnderMouse(Scrollbar*, SetOrClearLastScrollbar); @@ -517,10 +512,7 @@ private: enum SelectionInitiationState { HaveNotStartedSelection, PlacedCaret, ExtendedSelection }; SelectionInitiationState m_selectionInitiationState { HaveNotStartedSelection }; -#if ENABLE(DRAG_SUPPORT) LayoutPoint m_dragStartPosition; -#endif - Timer m_hoverTimer; Timer m_cursorUpdateTimer; diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp index bc741bc1e585095b2e31636fe4a6502c1a2518e7..87608f42473dd009d691ad4eefa0960c7b24c11d 100644 --- a/Source/WebCore/page/Frame.cpp +++ b/Source/WebCore/page/Frame.cpp @@ -180,6 +180,7 @@ Frame::Frame(Page& page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient& void Frame::init() { m_loader->init(); + InspectorInstrumentation::frameAttached(this); } Ref Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, FrameLoaderClient* client) diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp index 73587787f88a6ad4e4baffb0beb0b87e7782916f..7e7a984207d6005bdb116784f981b487c8c16846 100644 --- a/Source/WebCore/page/FrameSnapshotting.cpp +++ b/Source/WebCore/page/FrameSnapshotting.cpp @@ -115,6 +115,8 @@ std::unique_ptr snapshotFrameRectWithClip(Frame& frame, const IntRe if (!buffer) return nullptr; buffer->context().translate(-imageRect.x(), -imageRect.y()); + if (coordinateSpace != FrameView::ViewCoordinates) + buffer->context().scale(1 / frame.page()->pageScaleFactor()); if (!clipRects.isEmpty()) { Path clipPath; @@ -123,7 +125,10 @@ std::unique_ptr snapshotFrameRectWithClip(Frame& frame, const IntRe buffer->context().clipPath(clipPath); } - frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace); + FloatRect fr = imageRect; + if (coordinateSpace != FrameView::ViewCoordinates) + fr.scale(frame.page()->pageScaleFactor()); + frame.view()->paintContentsForSnapshot(buffer->context(), enclosingIntRect(fr), shouldIncludeSelection, coordinateSpace); return buffer; } diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index 5c0dab84e00b3786e05474c989c5839da15aa1eb..87378c01a02a6d6d02bfc71eb707490ebd68d3a4 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -2991,7 +2991,7 @@ void FrameView::setBaseBackgroundColor(const Color& backgroundColor) void FrameView::updateBackgroundRecursively(const Optional& backgroundColor) { -#if HAVE(OS_DARK_MODE_SUPPORT) +#if HAVE(OS_DARK_MODE_SUPPORT) && (defined(WTF_PLATFORM_MAC) && WTF_PLATFORM_MAC) || (defined(WTF_PLATFORM_IOS_FAMILY) && WTF_PLATFORM_IOS_FAMILY) Color baseBackgroundColor = backgroundColor.valueOr(RenderTheme::singleton().systemColor(CSSValueAppleSystemControlBackground, styleColorOptions())); #else Color baseBackgroundColor = backgroundColor.valueOr(Color::white); diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index 9c58b06f4c471130ce4815f11d14cb78f81b49a0..3d624733c36f09518b12095d91e67a2ae67879e2 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -259,6 +259,7 @@ ExceptionOr History::stateObjectAdded(RefPtr&& data if (!urlString.isEmpty()) frame->document()->updateURLForPushOrReplaceState(fullURL); + InspectorInstrumentation::didNavigateWithinPage(*frame); if (stateObjectType == StateObjectType::Push) { frame->loader().history().pushState(WTFMove(data), title, fullURL.string()); diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp index a383a1cb022e80bf69fce5446c5a934b2c3c649d..316b895e8690d3286a4416f3d9d5a7a318ff5921 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -86,6 +86,7 @@ #include "PerformanceLoggingClient.h" #include "PerformanceMonitor.h" #include "PlatformMediaSessionManager.h" +#include "PlatformScreen.h" #include "PlatformStrategies.h" #include "PlugInClient.h" #include "PluginData.h" @@ -419,6 +420,21 @@ void Page::setOverrideViewportArguments(const Optional& viewp document->updateViewportArguments(); } +FloatSize Page::screenSize() +{ + return m_overrideScreenSize.valueOr(screenRect(mainFrame().view()).size()); +} + +void Page::setOverrideScreenSize(Optional size) +{ + if (size == m_overrideScreenSize) + return; + + m_overrideScreenSize = size; + if (auto* document = mainFrame().document()) + document->updateViewportArguments(); +} + ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h index 81ee655c282bd96656e15eb1f390382a8a368f15..79763e7895c4fa774f8498a599a2ef876ccbe228 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h @@ -186,6 +186,9 @@ public: const Optional& overrideViewportArguments() const { return m_overrideViewportArguments; } WEBCORE_EXPORT void setOverrideViewportArguments(const Optional&); + WEBCORE_EXPORT FloatSize screenSize(); + WEBCORE_EXPORT void setOverrideScreenSize(Optional size); + static void refreshPlugins(bool reload); WEBCORE_EXPORT PluginData& pluginData(); void clearPluginData(); @@ -994,6 +997,7 @@ private: #endif Optional m_overrideViewportArguments; + Optional m_overrideScreenSize; #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) RefPtr m_deviceOrientationUpdateProvider; diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp index a9d228ca404918860c40651994db78a1e76db5ca..1fc3c345308dfed8384d1c02334f2030e879383d 100644 --- a/Source/WebCore/page/Screen.cpp +++ b/Source/WebCore/page/Screen.cpp @@ -32,6 +32,7 @@ #include "FloatRect.h" #include "Frame.h" #include "FrameView.h" +#include "Page.h" #include "PlatformScreen.h" #include "ResourceLoadObserver.h" #include "RuntimeEnabledFeatures.h" @@ -53,7 +54,7 @@ unsigned Screen::height() const return 0; if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::Height); - long height = static_cast(screenRect(frame->view()).height()); + long height = static_cast(frame->page()->screenSize().height()); return static_cast(height); } @@ -64,7 +65,7 @@ unsigned Screen::width() const return 0; if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::Width); - long width = static_cast(screenRect(frame->view()).width()); + long width = static_cast(frame->page()->screenSize().width()); return static_cast(width); } diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp index ad6f5209c52e0842d93be267f8f5e99551dfe07c..0fcf4fe9877ba8a89a8dfb321e120f7954c6f69b 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp @@ -298,6 +298,8 @@ bool ContentSecurityPolicy::protocolMatchesSelf(const URL& url) const template typename std::enable_if::value, bool>::type ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, Predicate&& predicate, Args&&... args) const { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext)) + return true; bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; for (auto& policy : m_policies) { if (policy->isReportOnly() != isReportOnly) @@ -311,6 +313,8 @@ typename std::enable_if bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext)) + return true; bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly; bool isAllowed = true; for (auto& policy : m_policies) { @@ -327,6 +331,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit template bool ContentSecurityPolicy::allPoliciesAllow(ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const { + if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext)) + 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/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h index f423a4a1d5399326fc48fe4d4a8a8fb9d4df861e..b4b60162d8b0d34113df052b04a1695d481d266e 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -138,6 +138,7 @@ namespace WebCore { static String keyCodeForHardwareKeyCode(unsigned); static String keyIdentifierForGdkKeyCode(unsigned); static int windowsKeyCodeForGdkKeyCode(unsigned); + static unsigned gdkKeyCodeForWindowsKeyCode(int); static String singleCharacterString(unsigned); static bool modifiersContainCapsLock(unsigned); #endif @@ -147,6 +148,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/ScrollableArea.h b/Source/WebCore/platform/ScrollableArea.h index fdddf2f9beb7e0b28f072cb121d1ee117bf00969..6c6acba2e5795319b60bd3031f37d8872d5a2011 100644 --- a/Source/WebCore/platform/ScrollableArea.h +++ b/Source/WebCore/platform/ScrollableArea.h @@ -103,7 +103,7 @@ public: void updateScrollSnapState(); #if ENABLE(TOUCH_EVENTS) - virtual bool handleTouchEvent(const PlatformTouchEvent&); + WEBCORE_EXPORT virtual bool handleTouchEvent(const PlatformTouchEvent&); #endif #if PLATFORM(IOS_FAMILY) diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp index 3cc3dc9012e8ff409141dd43808b71264c8cd337..e44eca80b5a7f0ac8360d39d78ec7097d5296dc3 100644 --- a/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp +++ b/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp @@ -27,7 +27,7 @@ #include "config.h" #include "GraphicsContextGLOpenGL.h" -#if ENABLE(GRAPHICS_CONTEXT_GL) && (USE(OPENGL) || (PLATFORM(COCOA) && USE(OPENGL_ES))) +#if !PLATFORM(WIN) && ENABLE(GRAPHICS_CONTEXT_GL) && (USE(OPENGL) || (PLATFORM(COCOA) && USE(OPENGL_ES))) #if PLATFORM(IOS_FAMILY) #include "GraphicsContextGLOpenGLESIOS.h" diff --git a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp index 269008b9053c8d8b6787cf22f13b44b46dace333..d3ba16947bc8964a7cfe746cabbf99d32a673cef 100644 --- a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp @@ -36,8 +36,10 @@ #include "WindowsKeyboardCodes.h" #include #include +#include #include #include +#include namespace WebCore { @@ -1293,6 +1295,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(unsigned keycode) } +static const HashMap& gdkToWindowsKeyCodeMap() +{ + static HashMap* result; + static std::once_flag once; + std::call_once( + once, + [] { + const unsigned gdkKeyCodes[] = { + GDK_KEY_Cancel, + // FIXME: non-keypad keys should take precedence, so we skip GDK_KEY_KP_* + // GDK_KEY_KP_0, + // GDK_KEY_KP_1, + // GDK_KEY_KP_2, + // GDK_KEY_KP_3, + // GDK_KEY_KP_4, + // GDK_KEY_KP_5, + // GDK_KEY_KP_6, + // GDK_KEY_KP_7, + // GDK_KEY_KP_8, + // GDK_KEY_KP_9, + // GDK_KEY_KP_Multiply, + // GDK_KEY_KP_Add, + // GDK_KEY_KP_Subtract, + // GDK_KEY_KP_Decimal, + // GDK_KEY_KP_Divide, + // GDK_KEY_KP_Page_Up, + // GDK_KEY_KP_Page_Down, + // GDK_KEY_KP_End, + // GDK_KEY_KP_Home, + // GDK_KEY_KP_Left, + // GDK_KEY_KP_Up, + // GDK_KEY_KP_Right, + // GDK_KEY_KP_Down, + GDK_KEY_BackSpace, + // GDK_KEY_ISO_Left_Tab, + // GDK_KEY_3270_BackTab, + GDK_KEY_Tab, + GDK_KEY_Clear, + // GDK_KEY_ISO_Enter, + // GDK_KEY_KP_Enter, + GDK_KEY_Return, + GDK_KEY_Menu, + GDK_KEY_Pause, + GDK_KEY_AudioPause, + GDK_KEY_Caps_Lock, + GDK_KEY_Kana_Lock, + GDK_KEY_Kana_Shift, + GDK_KEY_Hangul, + GDK_KEY_Hangul_Hanja, + GDK_KEY_Kanji, + GDK_KEY_Escape, + GDK_KEY_space, + GDK_KEY_Page_Up, + GDK_KEY_Page_Down, + GDK_KEY_End, + GDK_KEY_Home, + GDK_KEY_Left, + GDK_KEY_Up, + GDK_KEY_Right, + GDK_KEY_Down, + GDK_KEY_Select, + GDK_KEY_Print, + GDK_KEY_Execute, + GDK_KEY_Insert, + GDK_KEY_KP_Insert, + GDK_KEY_Delete, + GDK_KEY_KP_Delete, + GDK_KEY_Help, + GDK_KEY_0, + GDK_KEY_parenright, + GDK_KEY_1, + GDK_KEY_exclam, + GDK_KEY_2, + GDK_KEY_at, + GDK_KEY_3, + GDK_KEY_numbersign, + GDK_KEY_4, + GDK_KEY_dollar, + GDK_KEY_5, + GDK_KEY_percent, + GDK_KEY_6, + GDK_KEY_asciicircum, + GDK_KEY_7, + GDK_KEY_ampersand, + GDK_KEY_8, + GDK_KEY_asterisk, + GDK_KEY_9, + GDK_KEY_parenleft, + GDK_KEY_a, + GDK_KEY_A, + GDK_KEY_b, + GDK_KEY_B, + GDK_KEY_c, + GDK_KEY_C, + GDK_KEY_d, + GDK_KEY_D, + GDK_KEY_e, + GDK_KEY_E, + GDK_KEY_f, + GDK_KEY_F, + GDK_KEY_g, + GDK_KEY_G, + GDK_KEY_h, + GDK_KEY_H, + GDK_KEY_i, + GDK_KEY_I, + GDK_KEY_j, + GDK_KEY_J, + GDK_KEY_k, + GDK_KEY_K, + GDK_KEY_l, + GDK_KEY_L, + GDK_KEY_m, + GDK_KEY_M, + GDK_KEY_n, + GDK_KEY_N, + GDK_KEY_o, + GDK_KEY_O, + GDK_KEY_p, + GDK_KEY_P, + GDK_KEY_q, + GDK_KEY_Q, + GDK_KEY_r, + GDK_KEY_R, + GDK_KEY_s, + GDK_KEY_S, + GDK_KEY_t, + GDK_KEY_T, + GDK_KEY_u, + GDK_KEY_U, + GDK_KEY_v, + GDK_KEY_V, + GDK_KEY_w, + GDK_KEY_W, + GDK_KEY_x, + GDK_KEY_X, + GDK_KEY_y, + GDK_KEY_Y, + GDK_KEY_z, + GDK_KEY_Z, + GDK_KEY_Meta_L, + GDK_KEY_Meta_R, + GDK_KEY_Sleep, + GDK_KEY_Num_Lock, + GDK_KEY_Scroll_Lock, + GDK_KEY_Shift_L, + GDK_KEY_Shift_R, + GDK_KEY_Control_L, + GDK_KEY_Control_R, + GDK_KEY_Alt_L, + GDK_KEY_Alt_R, + GDK_KEY_Back, + GDK_KEY_Forward, + GDK_KEY_Refresh, + GDK_KEY_Stop, + GDK_KEY_Search, + GDK_KEY_Favorites, + GDK_KEY_HomePage, + GDK_KEY_AudioMute, + GDK_KEY_AudioLowerVolume, + GDK_KEY_AudioRaiseVolume, + GDK_KEY_AudioNext, + GDK_KEY_AudioPrev, + GDK_KEY_AudioStop, + GDK_KEY_AudioMedia, + GDK_KEY_semicolon, + GDK_KEY_colon, + GDK_KEY_plus, + GDK_KEY_equal, + GDK_KEY_comma, + GDK_KEY_less, + GDK_KEY_minus, + GDK_KEY_underscore, + GDK_KEY_period, + GDK_KEY_greater, + GDK_KEY_slash, + GDK_KEY_question, + GDK_KEY_asciitilde, + GDK_KEY_quoteleft, + GDK_KEY_bracketleft, + GDK_KEY_braceleft, + GDK_KEY_backslash, + GDK_KEY_bar, + GDK_KEY_bracketright, + GDK_KEY_braceright, + GDK_KEY_quoteright, + GDK_KEY_quotedbl, + GDK_KEY_AudioRewind, + GDK_KEY_AudioForward, + GDK_KEY_AudioPlay, + GDK_KEY_F1, + GDK_KEY_F2, + GDK_KEY_F3, + GDK_KEY_F4, + GDK_KEY_F5, + GDK_KEY_F6, + GDK_KEY_F7, + GDK_KEY_F8, + GDK_KEY_F9, + GDK_KEY_F10, + GDK_KEY_F11, + GDK_KEY_F12, + GDK_KEY_F13, + GDK_KEY_F14, + GDK_KEY_F15, + GDK_KEY_F16, + GDK_KEY_F17, + GDK_KEY_F18, + GDK_KEY_F19, + GDK_KEY_F20, + GDK_KEY_F21, + GDK_KEY_F22, + GDK_KEY_F23, + GDK_KEY_F24, + GDK_KEY_VoidSymbol, + GDK_KEY_Red, + GDK_KEY_Green, + GDK_KEY_Yellow, + GDK_KEY_Blue, + GDK_KEY_PowerOff, + GDK_KEY_AudioRecord, + GDK_KEY_Display, + GDK_KEY_Subtitle, + GDK_KEY_Video + }; + result = new HashMap(); + for (unsigned gdkKeyCode : gdkKeyCodes) { + int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(gdkKeyCode); + // If several gdk key codes map to the same win key code first one is used. + result->add(winKeyCode, gdkKeyCode); + } + }); + return *result; +} + +unsigned PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(int keycode) +{ + return gdkToWindowsKeyCodeMap().get(keycode); +} + String PlatformKeyboardEvent::singleCharacterString(unsigned val) { switch (val) { diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp index a34dc220bbb9a92b40dfb463e8724e81ac745b2c..8ecedd5dae88469366a619b96960598c1232a32d 100644 --- a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp @@ -30,8 +30,10 @@ #include "WindowsKeyboardCodes.h" #include +#include #include #include +#include namespace WebCore { @@ -1291,6 +1293,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(unsigned keycode) return 0; } +static const HashMap& WPEToWindowsKeyCodeMap() +{ + static HashMap* result; + static std::once_flag once; + std::call_once( + once, + [] { + const unsigned WPEKeyCodes[] = { + WPE_KEY_Cancel, + // FIXME: non-keypad keys should take precedence, so we skip WPE_KEY_KP_* + // WPE_KEY_KP_0, + // WPE_KEY_KP_1, + // WPE_KEY_KP_2, + // WPE_KEY_KP_3, + // WPE_KEY_KP_4, + // WPE_KEY_KP_5, + // WPE_KEY_KP_6, + // WPE_KEY_KP_7, + // WPE_KEY_KP_8, + // WPE_KEY_KP_9, + // WPE_KEY_KP_Multiply, + // WPE_KEY_KP_Add, + // WPE_KEY_KP_Subtract, + // WPE_KEY_KP_Decimal, + // WPE_KEY_KP_Divide, + // WPE_KEY_KP_Page_Up, + // WPE_KEY_KP_Page_Down, + // WPE_KEY_KP_End, + // WPE_KEY_KP_Home, + // WPE_KEY_KP_Left, + // WPE_KEY_KP_Up, + // WPE_KEY_KP_Right, + // WPE_KEY_KP_Down, + WPE_KEY_BackSpace, + // WPE_KEY_ISO_Left_Tab, + // WPE_KEY_3270_BackTab, + WPE_KEY_Tab, + WPE_KEY_Clear, + // WPE_KEY_ISO_Enter, + // WPE_KEY_KP_Enter, + WPE_KEY_Return, + WPE_KEY_Menu, + WPE_KEY_Pause, + WPE_KEY_AudioPause, + WPE_KEY_Caps_Lock, + WPE_KEY_Kana_Lock, + WPE_KEY_Kana_Shift, + WPE_KEY_Hangul, + WPE_KEY_Hangul_Hanja, + WPE_KEY_Kanji, + WPE_KEY_Escape, + WPE_KEY_space, + WPE_KEY_Page_Up, + WPE_KEY_Page_Down, + WPE_KEY_End, + WPE_KEY_Home, + WPE_KEY_Left, + WPE_KEY_Up, + WPE_KEY_Right, + WPE_KEY_Down, + WPE_KEY_Select, + WPE_KEY_Print, + WPE_KEY_Execute, + WPE_KEY_Insert, + WPE_KEY_KP_Insert, + WPE_KEY_Delete, + WPE_KEY_KP_Delete, + WPE_KEY_Help, + WPE_KEY_0, + WPE_KEY_parenright, + WPE_KEY_1, + WPE_KEY_exclam, + WPE_KEY_2, + WPE_KEY_at, + WPE_KEY_3, + WPE_KEY_numbersign, + WPE_KEY_4, + WPE_KEY_dollar, + WPE_KEY_5, + WPE_KEY_percent, + WPE_KEY_6, + WPE_KEY_asciicircum, + WPE_KEY_7, + WPE_KEY_ampersand, + WPE_KEY_8, + WPE_KEY_asterisk, + WPE_KEY_9, + WPE_KEY_parenleft, + WPE_KEY_a, + WPE_KEY_A, + WPE_KEY_b, + WPE_KEY_B, + WPE_KEY_c, + WPE_KEY_C, + WPE_KEY_d, + WPE_KEY_D, + WPE_KEY_e, + WPE_KEY_E, + WPE_KEY_f, + WPE_KEY_F, + WPE_KEY_g, + WPE_KEY_G, + WPE_KEY_h, + WPE_KEY_H, + WPE_KEY_i, + WPE_KEY_I, + WPE_KEY_j, + WPE_KEY_J, + WPE_KEY_k, + WPE_KEY_K, + WPE_KEY_l, + WPE_KEY_L, + WPE_KEY_m, + WPE_KEY_M, + WPE_KEY_n, + WPE_KEY_N, + WPE_KEY_o, + WPE_KEY_O, + WPE_KEY_p, + WPE_KEY_P, + WPE_KEY_q, + WPE_KEY_Q, + WPE_KEY_r, + WPE_KEY_R, + WPE_KEY_s, + WPE_KEY_S, + WPE_KEY_t, + WPE_KEY_T, + WPE_KEY_u, + WPE_KEY_U, + WPE_KEY_v, + WPE_KEY_V, + WPE_KEY_w, + WPE_KEY_W, + WPE_KEY_x, + WPE_KEY_X, + WPE_KEY_y, + WPE_KEY_Y, + WPE_KEY_z, + WPE_KEY_Z, + WPE_KEY_Meta_L, + WPE_KEY_Meta_R, + WPE_KEY_Sleep, + WPE_KEY_Num_Lock, + WPE_KEY_Scroll_Lock, + WPE_KEY_Shift_L, + WPE_KEY_Shift_R, + WPE_KEY_Control_L, + WPE_KEY_Control_R, + WPE_KEY_Alt_L, + WPE_KEY_Alt_R, + WPE_KEY_Back, + WPE_KEY_Forward, + WPE_KEY_Refresh, + WPE_KEY_Stop, + WPE_KEY_Search, + WPE_KEY_Favorites, + WPE_KEY_HomePage, + WPE_KEY_AudioMute, + WPE_KEY_AudioLowerVolume, + WPE_KEY_AudioRaiseVolume, + WPE_KEY_AudioNext, + WPE_KEY_AudioPrev, + WPE_KEY_AudioStop, + WPE_KEY_AudioMedia, + WPE_KEY_semicolon, + WPE_KEY_colon, + WPE_KEY_plus, + WPE_KEY_equal, + WPE_KEY_comma, + WPE_KEY_less, + WPE_KEY_minus, + WPE_KEY_underscore, + WPE_KEY_period, + WPE_KEY_greater, + WPE_KEY_slash, + WPE_KEY_question, + WPE_KEY_asciitilde, + WPE_KEY_quoteleft, + WPE_KEY_bracketleft, + WPE_KEY_braceleft, + WPE_KEY_backslash, + WPE_KEY_bar, + WPE_KEY_bracketright, + WPE_KEY_braceright, + WPE_KEY_quoteright, + WPE_KEY_quotedbl, + WPE_KEY_AudioRewind, + WPE_KEY_AudioForward, + WPE_KEY_AudioPlay, + WPE_KEY_F1, + WPE_KEY_F2, + WPE_KEY_F3, + WPE_KEY_F4, + WPE_KEY_F5, + WPE_KEY_F6, + WPE_KEY_F7, + WPE_KEY_F8, + WPE_KEY_F9, + WPE_KEY_F10, + WPE_KEY_F11, + WPE_KEY_F12, + WPE_KEY_F13, + WPE_KEY_F14, + WPE_KEY_F15, + WPE_KEY_F16, + WPE_KEY_F17, + WPE_KEY_F18, + WPE_KEY_F19, + WPE_KEY_F20, + WPE_KEY_F21, + WPE_KEY_F22, + WPE_KEY_F23, + WPE_KEY_F24, + WPE_KEY_VoidSymbol, + WPE_KEY_Red, + WPE_KEY_Green, + WPE_KEY_Yellow, + WPE_KEY_Blue, + WPE_KEY_PowerOff, + WPE_KEY_AudioRecord, + WPE_KEY_Display, + WPE_KEY_Subtitle, + WPE_KEY_Video + }; + result = new HashMap(); + for (unsigned WPEKeyCode : WPEKeyCodes) { + int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(WPEKeyCode); + // If several gdk key codes map to the same win key code first one is used. + result->add(winKeyCode, WPEKeyCode); + } + }); + return *result; +} + +unsigned PlatformKeyboardEvent::WPEKeyCodeForWindowsKeyCode(int keycode) +{ + return WPEToWindowsKeyCodeMap().get(keycode); +} + String PlatformKeyboardEvent::singleCharacterString(unsigned val) { switch (val) { diff --git a/Source/WebCore/platform/network/NetworkStateNotifier.h b/Source/WebCore/platform/network/NetworkStateNotifier.h index 87930048f4fd18d6098af7de4da25be532df5931..2bb2afcf9473b0d5d97efbe18dd7b8145bc5f932 100644 --- a/Source/WebCore/platform/network/NetworkStateNotifier.h +++ b/Source/WebCore/platform/network/NetworkStateNotifier.h @@ -72,6 +72,7 @@ private: #endif Optional m_isOnLine; + Optional m_emulatedIsOnLine; Vector> m_listeners; Timer m_updateStateTimer; diff --git a/Source/WebCore/platform/win/KeyEventWin.cpp b/Source/WebCore/platform/win/KeyEventWin.cpp index 44737686187a06a92c408ea60b63a48ac8481334..c754a763688b52e7ddd47493296ef9b0c6adc527 100644 --- a/Source/WebCore/platform/win/KeyEventWin.cpp +++ b/Source/WebCore/platform/win/KeyEventWin.cpp @@ -239,10 +239,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::RawKeyDown) { + m_text = String(); + m_unmodifiedText = String(); + } else { + m_keyIdentifier = String(); + m_windowsVirtualKeyCode = 0; + } } bool PlatformKeyboardEvent::currentCapsLockState() diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp index 09bc42cb53114d089c3794ae7b00503655a4499d..1bdb584c7f5f1867088c775cb6518d620ab295a0 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp @@ -26,7 +26,6 @@ #include "config.h" #include "NetworkProcess.h" - #include "ArgumentCoders.h" #include "Attachment.h" #include "AuthenticationManager.h" @@ -594,6 +593,35 @@ void NetworkProcess::destroySession(PAL::SessionID sessionID) m_storageManagerSet->remove(sessionID); } +void NetworkProcess::getAllCookies(PAL::SessionID sessionID, CompletionHandler&&)>&& completionHandler) +{ + if (auto* networkStorageSession = storageSession(sessionID)) { + completionHandler(networkStorageSession->getAllCookies()); + return; + } + completionHandler({ }); +} + +void NetworkProcess::setCookies(PAL::SessionID sessionID, Vector cookies, CompletionHandler&& completionHandler) { + if (auto* networkStorageSession = storageSession(sessionID)) { + for (auto cookie : cookies) + networkStorageSession->setCookie(cookie); + completionHandler(true); + return; + } + completionHandler(false); +} + +void NetworkProcess::deleteAllCookies(PAL::SessionID sessionID, CompletionHandler&& completionHandler) +{ + if (auto* networkStorageSession = storageSession(sessionID)) { + networkStorageSession->deleteAllCookies(); + completionHandler(true); + return; + } + completionHandler(false); +} + #if ENABLE(RESOURCE_LOAD_STATISTICS) void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler&& completionHandler) { diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h index 769595855829302a1bed9596412813f333572f18..1a11997c2723666ae7c193ac4e79af9a3632cdb1 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h @@ -74,6 +74,7 @@ class SessionID; namespace WebCore { class CertificateInfo; +struct Cookie; class CurlProxySettings; class DownloadID; class ProtectionSpace; @@ -202,6 +203,10 @@ public: void addWebsiteDataStore(WebsiteDataStoreParameters&&); + void getAllCookies(PAL::SessionID, CompletionHandler&&)>&&); + void setCookies(PAL::SessionID, Vector, CompletionHandler&&); + void deleteAllCookies(PAL::SessionID, CompletionHandler&&); + #if ENABLE(RESOURCE_LOAD_STATISTICS) void clearPrevalentResource(PAL::SessionID, const RegistrableDomain&, CompletionHandler&&); void clearUserInteraction(PAL::SessionID, const RegistrableDomain&, CompletionHandler&&); @@ -309,6 +314,7 @@ public: #if PLATFORM(COCOA) NetworkHTTPSUpgradeChecker& networkHTTPSUpgradeChecker(); + bool ignoreTLSErrors() const { return m_ignoreTLSErrors; } #endif const String& uiProcessBundleIdentifier() const { return m_uiProcessBundleIdentifier; } @@ -422,8 +428,10 @@ private: void syncAllCookies(); void didSyncAllCookies(); -#if USE(SOUP) +#if PLATFORM(COCOA) || USE(CURL) || USE(SOUP) void setIgnoreTLSErrors(bool); +#endif +#if USE(SOUP) void userPreferredLanguagesChanged(const Vector&); void setNetworkProxySettings(const WebCore::SoupNetworkProxySettings&); #endif @@ -570,6 +578,7 @@ private: #if PLATFORM(COCOA) std::unique_ptr m_networkHTTPSUpgradeChecker; + bool m_ignoreTLSErrors { false }; #endif #if ENABLE(RESOURCE_LOAD_STATISTICS) diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in index ebebaddfbd2e036dd02f4efbf99645613eb28206..81057e5bbfaa5b61e3e93ce781476a7953444aff 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in @@ -27,8 +27,10 @@ messages -> NetworkProcess LegacyReceiver { # Creates a connection for communication with a WebProcess CreateNetworkConnectionToWebProcess(WebCore::ProcessIdentifier processIdentifier, PAL::SessionID sessionID) -> (Optional connectionIdentifier, enum:uint8_t WebCore::HTTPCookieAcceptPolicy cookieAcceptPolicy) Async -#if USE(SOUP) +#if USE(SOUP) || PLATFORM(COCOA) || USE(CURL) SetIgnoreTLSErrors(bool ignoreTLSErrors) +#endif +#if USE(SOUP) UserPreferredLanguagesChanged(Vector languages) SetNetworkProxySettings(struct WebCore::SoupNetworkProxySettings settings) PrefetchDNS(String hostname) @@ -82,6 +84,10 @@ messages -> NetworkProcess LegacyReceiver { PreconnectTo(PAL::SessionID sessionID, URL url, String userAgent, enum:uint8_t WebCore::StoredCredentialsPolicy storedCredentialsPolicy); + GetAllCookies(PAL::SessionID sessionID) -> (Vector cookies) Async + SetCookies(PAL::SessionID sessionID, Vector cookies) -> (bool success) Async + DeleteAllCookies(PAL::SessionID sessionID) -> (bool success) Async + #if ENABLE(RESOURCE_LOAD_STATISTICS) ClearPrevalentResource(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () Async ClearUserInteraction(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> () Async diff --git a/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h b/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h index bdc2cae74892db1b0a26d22afbe2a4bb7a6c0ab0..7c45a71befbcd531e724a816d606f81fe6061a2f 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h +++ b/Source/WebKit/NetworkProcess/NetworkProcessCreationParameters.h @@ -74,9 +74,9 @@ struct NetworkProcessCreationParameters { WebsiteDataStoreParameters defaultDataStoreParameters; + bool ignoreTLSErrors { false }; #if USE(SOUP) WebCore::HTTPCookieAcceptPolicy cookieAcceptPolicy { WebCore::HTTPCookieAcceptPolicy::AlwaysAccept }; - bool ignoreTLSErrors { false }; Vector languages; WebCore::SoupNetworkProxySettings proxySettings; #endif diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm index 6416bcfe97bf44a231f0691c5ce97fba791df526..58aa3dd33f2f96c045a2b725e74c3da2a4a6ce80 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkProcessCocoa.mm @@ -89,6 +89,8 @@ void NetworkProcess::platformInitializeNetworkProcessCocoa(const NetworkProcessC #endif #endif + setIgnoreTLSErrors(parameters.ignoreTLSErrors); + _CFNetworkSetATSContext(parameters.networkATSContext.get()); m_uiProcessBundleIdentifier = parameters.uiProcessBundleIdentifier; @@ -209,6 +211,7 @@ void NetworkProcess::syncAllCookies() }); } + #if HAVE(FOUNDATION_WITH_SAVE_COOKIES_WITH_COMPLETION_HANDLER) static void saveCookies(NSHTTPCookieStorage *cookieStorage, CompletionHandler&& completionHandler) { @@ -239,6 +242,11 @@ void NetworkProcess::platformSyncAllCookies(CompletionHandler&& completi ALLOW_DEPRECATED_DECLARATIONS_END } +void NetworkProcess::setIgnoreTLSErrors(bool ignoreTLSErrors) +{ + m_ignoreTLSErrors = ignoreTLSErrors; +} + void NetworkProcess::platformPrepareToSuspend(CompletionHandler&& completionHandler) { completionHandler(); diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h index 198aaacb4847c934191a5df8e6b69c1f3e565647..16cebf540b396a73527da35c51b2f247c7ef0aba 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.h @@ -77,7 +77,7 @@ public: const String& dataConnectionServiceType() const; #endif - static bool allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge&); + bool allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge&); void continueDidReceiveChallenge(SessionWrapper&, const WebCore::AuthenticationChallenge&, NegotiatedLegacyTLS, NetworkDataTaskCocoa::TaskIdentifier, NetworkDataTaskCocoa*, CompletionHandler&&); diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm index 4e5c72ff0ac5bc3b419bb5e57e0dbb71ee01f9bd..84f38cc73841ac7760e75af66376e2390471f80d 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm @@ -653,7 +653,7 @@ static inline void processServerTrustEvaluation(NetworkSessionCocoa& session, Se NegotiatedLegacyTLS negotiatedLegacyTLS = NegotiatedLegacyTLS::No; if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - if (NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(challenge)) + if (sessionCocoa->allowsSpecificHTTPSCertificateForHost(challenge)) return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); #if HAVE(TLS_PROTOCOL_VERSION_T) @@ -1379,6 +1379,9 @@ static bool certificatesMatch(SecTrustRef trust1, SecTrustRef trust2) bool NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(const WebCore::AuthenticationChallenge& challenge) { + if (networkProcess().ignoreTLSErrors()) + return true; + const String& host = challenge.protectionSpace().host(); NSArray *certificates = [NSURLRequest allowsSpecificHTTPSCertificateForHost:host]; if (!certificates) diff --git a/Source/WebKit/NetworkProcess/curl/NetworkProcessCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkProcessCurl.cpp index 5be170266f45b8bf72ef56b10087cb59bb56dba9..24f8885a0054c1a64cb7deebb00bb4421c56a858 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkProcessCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkProcessCurl.cpp @@ -94,4 +94,9 @@ void NetworkProcess::setNetworkProxySettings(PAL::SessionID sessionID, WebCore:: ASSERT_NOT_REACHED(); } +void NetworkProcess::setIgnoreTLSErrors(bool ignoreTLSErrors) +{ + CurlContext::singleton().sslHandle().setIgnoreSSLErrors(ignoreTLSErrors); +} + } // namespace WebKit diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index 963518a05c4ad1a4690048341104022504e04651..e6800b106c40fec6cd80415498a6bddfee1c17ac 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -249,6 +249,7 @@ list(APPEND WebKit_INCLUDE_DIRECTORIES "${WEBKIT_DIR}/UIProcess/API/wpe" "${WEBKIT_DIR}/UIProcess/CoordinatedGraphics" "${WEBKIT_DIR}/UIProcess/geoclue" + "${WEBKIT_DIR}/UIProcess/glib" "${WEBKIT_DIR}/UIProcess/gstreamer" "${WEBKIT_DIR}/UIProcess/linux" "${WEBKIT_DIR}/UIProcess/soup" diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake index 75a9c8d7678dad39dc4b5254427da518ef5928f1..e1de3540157681c4cc0404736b9604e7dd74e9bc 100644 --- a/Source/WebKit/PlatformWin.cmake +++ b/Source/WebKit/PlatformWin.cmake @@ -56,8 +56,12 @@ list(APPEND WebKit_SOURCES UIProcess/WebsiteData/win/WebsiteDataStoreWin.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 diff --git a/Source/WebKit/Shared/API/c/wpe/WebKit.h b/Source/WebKit/Shared/API/c/wpe/WebKit.h index 898e30b370db8176e886fbbde0cd960e38a64818..74945e06fac0eb14936578de6a599a123364a63a 100644 --- a/Source/WebKit/Shared/API/c/wpe/WebKit.h +++ b/Source/WebKit/Shared/API/c/wpe/WebKit.h @@ -78,6 +78,7 @@ // From Source/WebKit/UIProcess/API/C #include #include +#include #include #include #include diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h index f08c19fb95ec8c8cca8f4ca2aa4049885637febf..c09e35e1b4fbf95b31f8d890bf09231055e4373a 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h +++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -34,6 +34,7 @@ #if USE(APPKIT) #include OBJC_CLASS NSView; +OBJC_CLASS NSEvent; namespace WebCore { struct CompositionUnderline; @@ -67,18 +68,34 @@ 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(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands)) + { + } #elif PLATFORM(GTK) NativeWebKeyboardEvent(const NativeWebKeyboardEvent&); enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(GdkEvent*, const String&, HandledByInputMethod, Optional>&&, Optional&&, Vector&& commands); + NativeWebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp, Vector&& commands) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands)) + { + } #elif PLATFORM(IOS_FAMILY) enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(::WebEvent *, HandledByInputMethod); #elif USE(LIBWPE) enum class HandledByInputMethod : bool { No, Yes }; NativeWebKeyboardEvent(struct wpe_input_keyboard_event*, const String&, HandledByInputMethod, Optional>&&, Optional&&); + NativeWebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) + : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp) + { + } #elif PLATFORM(WIN) NativeWebKeyboardEvent(HWND, UINT message, WPARAM, LPARAM, Vector&& pendingCharEvents); + NativeWebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) + : 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 0fa557e9faa34ba81a7a4f7da5e32f30cbfad5d2..4f06afeb895fb1231d87e4304a4b588cd326944c 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h @@ -70,6 +70,11 @@ public: NativeWebMouseEvent(HWND, UINT message, WPARAM, LPARAM, bool); #endif +#if PLATFORM(GTK) || USE(LIBWPE) || PLATFORM(WIN) + NativeWebMouseEvent(Type type, Button button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet modifiers, WallTime timestamp) + : WebMouseEvent(type, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount, modifiers, timestamp) { } +#endif + #if USE(APPKIT) NSEvent* nativeEvent() const { return m_nativeEvent.get(); } #elif PLATFORM(GTK) diff --git a/Source/WebKit/Shared/WebEvent.h b/Source/WebKit/Shared/WebEvent.h index 224ef51567fdf5eb7321a3411faccd283b5b2813..7c102952d5821486f0c6a0af0b8d3286ace96b93 100644 --- a/Source/WebKit/Shared/WebEvent.h +++ b/Source/WebKit/Shared/WebEvent.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -252,14 +253,18 @@ public: #if USE(APPKIT) WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector&, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); + WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp, Vector&& commands); #elif PLATFORM(GTK) WebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, Optional>&&, Optional&&, Vector&& commands, bool isKeypad, OptionSet, WallTime timestamp); + WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp, Vector&& commands); #elif PLATFORM(IOS_FAMILY) WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); #elif USE(LIBWPE) WebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, Optional>&&, Optional&&, bool isKeypad, OptionSet, WallTime timestamp); + WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); #else WebKeyboardEvent(Type, 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, OptionSet, WallTime timestamp); + WebKeyboardEvent(Type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet, WallTime timestamp); #endif const String& text() const { return m_text; } @@ -301,7 +306,7 @@ private: int32_t m_nativeVirtualKeyCode; int32_t m_macCharCode; #if USE(APPKIT) || USE(UIKIT_KEYBOARD_ADDITIONS) || PLATFORM(GTK) || USE(LIBWPE) - bool m_handledByInputMethod; + bool m_handledByInputMethod = false; #endif #if PLATFORM(GTK) || USE(LIBWPE) Optional> m_preeditUnderlines; diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp index cccb560418f32fad40587ac083b95f398eb1399d..f6b0aee44e5f12055dd14ad0636d780d2d4ece5d 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.cpp +++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp @@ -35,6 +35,7 @@ WebKeyboardEvent::WebKeyboardEvent() { } + #if USE(APPKIT) WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector& commands, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) @@ -56,6 +57,24 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& ASSERT(isKeyboardEventType(type)); } +WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) + , 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(Type type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, Optional>&& preeditUnderlines, Optional&& preeditSelectionRange, Vector&& commands, bool isKeypad, OptionSet modifiers, WallTime timestamp) @@ -79,6 +98,24 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& ASSERT(isKeyboardEventType(type)); } +WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp, Vector&& commands) + : WebEvent(type, modifiers, timestamp) + , m_text(text) + , m_unmodifiedText(text) + , 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(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) @@ -144,6 +181,27 @@ WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& #endif +#if PLATFORM(WIN) || USE(LIBWPE) + +WebKeyboardEvent::WebKeyboardEvent(Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, WallTime timestamp) + : 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/WebPageCreationParameters.cpp b/Source/WebKit/Shared/WebPageCreationParameters.cpp index 724c16e50433debb240d9be13be9a5f0579baa43..ae6824657c76c0627bec3bfd037cf2cf48871e82 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.cpp +++ b/Source/WebKit/Shared/WebPageCreationParameters.cpp @@ -149,6 +149,8 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const encoder << shouldRenderCanvasInGPUProcess; encoder << needsInAppBrowserPrivacyQuirks; + encoder << shouldPauseInInspectorWhenShown; + #if PLATFORM(GTK) encoder << themeName; #endif @@ -478,6 +480,9 @@ Optional WebPageCreationParameters::decode(IPC::Decod if (!decoder.decode(parameters.needsInAppBrowserPrivacyQuirks)) return WTF::nullopt; + if (!decoder.decode(parameters.shouldPauseInInspectorWhenShown)) + return WTF::nullopt; + #if PLATFORM(GTK) if (!decoder.decode(parameters.themeName)) return WTF::nullopt; diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h index e8b9fa886cc37d688d1c88584635b212945b0e91..5cb8d7bbc7b24ef5bc2160b2b0d780827bb66b29 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h @@ -220,6 +220,8 @@ struct WebPageCreationParameters { bool shouldRenderCanvasInGPUProcess { false }; bool needsInAppBrowserPrivacyQuirks { false }; + bool shouldPauseInInspectorWhenShown { false }; + #if PLATFORM(GTK) String themeName; #endif diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp index 2357f3d58415fae78e48b0f8a25bddad85c786bf..f3941a74922f5a0a3bf59a11cd4c42fbfd33d0af 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -40,7 +40,7 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(GdkEvent* event, const String& te } NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event) - : WebKeyboardEvent(WebEventFactory::createWebKeyboardEvent(event.nativeEvent(), event.text(), event.handledByInputMethod(), Optional>(event.preeditUnderlines()), Optional(event.preeditSelectionRange()), Vector(event.commands()))) + : WebKeyboardEvent(event) , m_nativeEvent(gdk_event_copy(event.nativeEvent())) { } diff --git a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp index 58e37fe3827cdb08d36ef0c85b8d4a968dee001a..429d245ea99fdee1b598a5caf51de8ce4b47fb02 100644 --- a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp @@ -38,8 +38,8 @@ NativeWebMouseEvent::NativeWebMouseEvent(GdkEvent* event, int eventClickCount, O } NativeWebMouseEvent::NativeWebMouseEvent(const NativeWebMouseEvent& event) - : WebMouseEvent(WebEventFactory::createWebMouseEvent(event.nativeEvent(), event.clickCount(), WebCore::IntPoint(event.deltaX(), event.deltaY()))) - , m_nativeEvent(gdk_event_copy(event.nativeEvent())) + : WebMouseEvent(event) + , m_nativeEvent(event.nativeEvent() ? gdk_event_copy(event.nativeEvent()) : nullptr) { } diff --git a/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp b/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp index 7b5eb372880d8662544334cd4697276d543de45b..ba06ecbb2cf5088a4c8c0824b50cb7797605dc57 100644 --- a/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp +++ b/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "WebEvent.h" -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) #include "WebCoreArgumentCoders.h" @@ -79,4 +79,4 @@ Optional WebPlatformTouchPoint::decode(IPC::Decoder& deco } // namespace WebKit -#endif // ENABLE(TOUCH_EVENTS) +#endif // ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) diff --git a/Source/WebKit/Shared/ios/WebTouchEventIOS.cpp b/Source/WebKit/Shared/ios/WebTouchEventIOS.cpp index 45a56eb3b0fda13c3b78d57594a0092e4e1866f6..5e29e15813be6abe82790e6a98d3947e7a6fae44 100644 --- a/Source/WebKit/Shared/ios/WebTouchEventIOS.cpp +++ b/Source/WebKit/Shared/ios/WebTouchEventIOS.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "WebEvent.h" -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) #include "ArgumentCoders.h" #include "WebCoreArgumentCoders.h" @@ -71,4 +71,4 @@ bool WebTouchEvent::decode(IPC::Decoder& decoder, WebTouchEvent& result) } // namespace WebKit -#endif // ENABLE(TOUCH_EVENTS) +#endif // ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) diff --git a/Source/WebKit/Shared/win/WebEventFactory.cpp b/Source/WebKit/Shared/win/WebEventFactory.cpp index 88d53d236cd6d62735f03678a04ca9c198dddacb..b8f8efc57ab00dc5725660c5a8ad56a3e6384de5 100644 --- a/Source/WebKit/Shared/win/WebEventFactory.cpp +++ b/Source/WebKit/Shared/win/WebEventFactory.cpp @@ -473,7 +473,7 @@ WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message } #if ENABLE(TOUCH_EVENTS) -WebTouchEvent WebEventFactory::createWebTouchEvent(const GdkEvent* event, Vector&& touchPoints) +WebTouchEvent WebEventFactory::createWebTouchEvent() { return WebTouchEvent(); } diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt index c3e3874d1480228a09b53ad3edda66fb33edc2f2..18d7a8e5459eefb94e8862d94129204389fb8623 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt @@ -276,16 +276,21 @@ Shared/WebsiteData/WebsiteData.cpp UIProcess/AuxiliaryProcessProxy.cpp UIProcess/BackgroundProcessResponsivenessTimer.cpp +UIProcess/BrowserInspectorController.cpp +UIProcess/BrowserInspectorPipe.cpp UIProcess/DeviceIdHashSaltStorage.cpp UIProcess/DrawingAreaProxy.cpp UIProcess/FrameLoadState.cpp UIProcess/GeolocationPermissionRequestManagerProxy.cpp UIProcess/GeolocationPermissionRequestProxy.cpp +UIProcess/InspectorDialogAgent.cpp +UIProcess/InspectorPlaywrightAgent.cpp UIProcess/LegacyGlobalSettings.cpp UIProcess/PageLoadState.cpp UIProcess/ProcessAssertion.cpp UIProcess/ProcessThrottler.cpp UIProcess/ProvisionalPageProxy.cpp +UIProcess/RemoteInspectorPipe.cpp UIProcess/ResponsivenessTimer.cpp UIProcess/StatisticsRequest.cpp UIProcess/SuspendedPageProxy.cpp @@ -323,6 +328,8 @@ UIProcess/WebOpenPanelResultListenerProxy.cpp UIProcess/WebPageDiagnosticLoggingClient.cpp UIProcess/WebPageGroup.cpp UIProcess/WebPageInjectedBundleClient.cpp +UIProcess/WebPageInspectorEmulationAgent.cpp +UIProcess/WebPageInspectorInputAgent.cpp UIProcess/WebPageProxy.cpp UIProcess/WebPasteboardProxy.cpp UIProcess/WebPreferences.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt index a124cdca7849248a5039fb74da4541c18857f97e..f9d49d81f3383685daaf5a9d748925217cd3115e 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt @@ -249,6 +249,7 @@ UIProcess/API/Cocoa/_WKApplicationManifest.mm UIProcess/API/Cocoa/_WKAttachment.mm UIProcess/API/Cocoa/_WKAutomationSession.mm UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm +UIProcess/API/Cocoa/_WKBrowserInspector.mm UIProcess/API/Cocoa/_WKContentRuleListAction.mm UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @no-unify diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt index eba34614fe0fdcee53c1edc4e940c41bbd24027c..17b592801937088d73ecd8842c48d55f57f0d8d2 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -130,6 +130,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 @@ -237,6 +238,7 @@ UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp UIProcess/cairo/BackingStoreCairo.cpp @no-unify +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp UIProcess/glib/WebsiteDataStoreGLib.cpp @no-unify @@ -250,6 +252,7 @@ UIProcess/gtk/AcceleratedBackingStoreX11.cpp @no-unify UIProcess/gtk/DragAndDropHandler.cpp UIProcess/gtk/GestureController.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 @@ -261,6 +264,8 @@ UIProcess/gtk/WaylandCompositor.cpp @no-unify 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 69a52e17a4a8932b5dfc5edfa72b922c18d43082..bc332745c8905414f1c8079c036dadf73902fde4 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -118,6 +118,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 @@ -193,7 +194,7 @@ UIProcess/Automation/wpe/WebAutomationSessionWPE.cpp UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp UIProcess/geoclue/GeoclueGeolocationProvider.cpp - +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp UIProcess/glib/WebsiteDataStoreGLib.cpp @no-unify @@ -220,6 +221,10 @@ UIProcess/soup/WebProcessPoolSoup.cpp UIProcess/wpe/WebPageProxyWPE.cpp +UIProcess/wpe/InspectorTargetProxyWPE.cpp +UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp +UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp + WebProcess/InjectedBundle/API/glib/DOM/DOMObjectCache.cpp @no-unify WebProcess/InjectedBundle/API/glib/DOM/WebKitDOMDocument.cpp @no-unify WebProcess/InjectedBundle/API/glib/DOM/WebKitDOMElement.cpp @no-unify diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp index 72ccef564d1854290de793921e1f092804a6bec6..2ae46d68a1c7454e02800e87ba7eade58713b9e1 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp @@ -53,6 +53,9 @@ Ref ProcessPoolConfiguration::copy() copy->m_ignoreSynchronousMessagingTimeoutsForTesting = this->m_ignoreSynchronousMessagingTimeoutsForTesting; copy->m_attrStyleEnabled = this->m_attrStyleEnabled; copy->m_overrideLanguages = this->m_overrideLanguages; +#if PLATFORM(MAC) + copy->m_forceOverlayScrollbars = this->m_forceOverlayScrollbars; +#endif 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 2a7e318e14f5cd4d136756ce31eb3a16f14055df..2657b4524eb49b76dc2c136837f2d2f5b2806434 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h @@ -98,6 +98,11 @@ public: const Vector& overrideLanguages() const { return m_overrideLanguages; } void setOverrideLanguages(Vector&& languages) { m_overrideLanguages = WTFMove(languages); } +#if PLATFORM(MAC) + bool forceOverlayScrollbars() const { return m_forceOverlayScrollbars; } + void setForceOverlayScrollbars(bool forceOverlayScrollbars) { m_forceOverlayScrollbars = forceOverlayScrollbars; } +#endif + bool alwaysRunsAtBackgroundPriority() const { return m_alwaysRunsAtBackgroundPriority; } void setAlwaysRunsAtBackgroundPriority(bool alwaysRunsAtBackgroundPriority) { m_alwaysRunsAtBackgroundPriority = alwaysRunsAtBackgroundPriority; } @@ -141,6 +146,9 @@ private: bool m_ignoreSynchronousMessagingTimeoutsForTesting { false }; bool m_attrStyleEnabled { false }; Vector m_overrideLanguages; +#if PLATFORM(MAC) + bool m_forceOverlayScrollbars { false }; +#endif 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 9066b62ac2e964220fbd6cdd68be8e973b99ddd6..06193f0b01207b30dd3c7c97db32bfeeda41f247 100644 --- a/Source/WebKit/UIProcess/API/APIUIClient.h +++ b/Source/WebKit/UIProcess/API/APIUIClient.h @@ -97,6 +97,7 @@ public: virtual void runJavaScriptAlert(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, 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/WKContext.cpp b/Source/WebKit/UIProcess/API/C/WKContext.cpp index 743cb854e28f51a0399d6fd1589e767fa3494f25..a6667051636cef88fb9dacc928cde16ba5215266 100644 --- a/Source/WebKit/UIProcess/API/C/WKContext.cpp +++ b/Source/WebKit/UIProcess/API/C/WKContext.cpp @@ -436,6 +436,11 @@ WKWebsiteDataStoreRef WKContextGetWebsiteDataStore(WKContextRef) return WKWebsiteDataStoreGetDefaultDataStore(); } +void WKContextSetPrimaryDataStore(WKContextRef contextRef, WKWebsiteDataStoreRef dataStoreRef) +{ + WebKit::toImpl(contextRef)->setPrimaryDataStore(*WebKit::toImpl(dataStoreRef)); +} + WKApplicationCacheManagerRef WKContextGetApplicationCacheManager(WKContextRef context) { return reinterpret_cast(WKWebsiteDataStoreGetDefaultDataStore()); diff --git a/Source/WebKit/UIProcess/API/C/WKContext.h b/Source/WebKit/UIProcess/API/C/WKContext.h index 08f54ff5057f8d04e26adfe2c0e3a472647935e7..8f3ae0f0346514cec926ea7babff40c22fd4097a 100644 --- a/Source/WebKit/UIProcess/API/C/WKContext.h +++ b/Source/WebKit/UIProcess/API/C/WKContext.h @@ -168,6 +168,7 @@ WK_EXPORT void WKContextStartMemorySampler(WKContextRef context, WKDoubleRef int WK_EXPORT void WKContextStopMemorySampler(WKContextRef context); WK_EXPORT WKWebsiteDataStoreRef WKContextGetWebsiteDataStore(WKContextRef context) WK_C_API_DEPRECATED_WITH_REPLACEMENT(WKWebsiteDataStoreGetDefaultDataStore); +WK_EXPORT void WKContextSetPrimaryDataStore(WKContextRef context, WKWebsiteDataStoreRef dataStore); WK_EXPORT WKApplicationCacheManagerRef WKContextGetApplicationCacheManager(WKContextRef context) WK_C_API_DEPRECATED_WITH_REPLACEMENT(WKWebsiteDataStoreGetDefaultDataStore); WK_EXPORT WKCookieManagerRef WKContextGetCookieManager(WKContextRef context) WK_C_API_DEPRECATED; diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.cpp b/Source/WebKit/UIProcess/API/C/WKInspector.cpp index 39327c5c9230591e4f52e4574c416e36687788f0..269dc87a6ab35481d2b45bea86fff893a9bddfb2 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 "WebInspectorProxy.h" #include "WebPageProxy.h" @@ -130,4 +135,11 @@ void WKInspectorToggleElementSelection(WKInspectorRef inspectorRef) toImpl(inspectorRef)->toggleElementSelection(); } +void WKInspectorInitializeRemoteInspectorPipe(CreatePageCallback createPage, QuitCallback quit) +{ +#if PLATFORM(WIN) + initializeBrowserInspectorPipe(makeUnique(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..1f707641766b51e3bddcdde0c49ee8cfcd83db0b 100644 --- a/Source/WebKit/UIProcess/API/C/WKInspector.h +++ b/Source/WebKit/UIProcess/API/C/WKInspector.h @@ -66,6 +66,9 @@ WK_EXPORT void WKInspectorTogglePageProfiling(WKInspectorRef inspector); WK_EXPORT bool WKInspectorIsElementSelectionActive(WKInspectorRef inspector); WK_EXPORT void WKInspectorToggleElementSelection(WKInspectorRef inspector); +typedef WKPageRef (*CreatePageCallback)(WKPageConfigurationRef configuration); +typedef void (*QuitCallback)(); +WK_EXPORT void WKInspectorInitializeRemoteInspectorPipe(CreatePageCallback, QuitCallback); #ifdef __cplusplus } #endif diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp index 8432ce01af2c43154416f65f035352006c103527..19e9fb021793cc5aebe855d50c9be29c582e915c 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp @@ -1678,6 +1678,13 @@ void WKPageSetPageUIClient(WKPageRef pageRef, const WKPageUIClientBase* wkClient completionHandler(String()); } + 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) @@ -1738,6 +1745,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 1d2febfba8833912f72216aa53c8c20090ee2d8b..1b2c3d84b15b12f1a187c0b7622db43cbbcd5996 100644 --- a/Source/WebKit/UIProcess/API/C/WKPageUIClient.h +++ b/Source/WebKit/UIProcess/API/C/WKPageUIClient.h @@ -90,6 +90,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); @@ -1352,6 +1353,7 @@ typedef struct WKPageUIClientV14 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; } WKPageUIClientV14; #ifdef __cplusplus diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm b/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm index 032584571cb63dbe6b49a7953f6e8d6d7e83e375..766b1e0456a490eb60eeef01c8edd8577ab3fe1a 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKProcessPool.mm @@ -47,6 +47,7 @@ #import "_WKDownloadDelegate.h" #import "_WKDownloadInternal.h" #import "_WKProcessPoolConfigurationInternal.h" +#import "_WKWebsiteDataStoreInternal.h" #import #import #import @@ -84,6 +85,18 @@ static WKProcessPool *sharedProcessPool; return self; } +- (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration AndDataStore:(WKWebsiteDataStore*)dataStore +{ + if (!(self = [super init])) + return nil; + + API::Object::constructInWrapper(self, *configuration->_processPoolConfiguration); + _processPool->setPrimaryDataStore(*dataStore->_websiteDataStore); + + return self; +} + + - (instancetype)init { return [self _initWithConfiguration:adoptNS([[_WKProcessPoolConfiguration alloc] init]).get()]; diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h index cc0f99cf9b1fb80dfd023c2200c66d87d494d6c4..96713376932923a342d0c973216c96925d18dbf0 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKProcessPoolPrivate.h @@ -37,6 +37,7 @@ @interface WKProcessPool () - (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration __attribute__((objc_method_family(init))) NS_DESIGNATED_INITIALIZER; +- (instancetype)_initWithConfiguration:(_WKProcessPoolConfiguration *)configuration AndDataStore:(WKWebsiteDataStore *)dataStore __attribute__((objc_method_family(init))) NS_DESIGNATED_INITIALIZER; @end @interface WKProcessPool (WKPrivate) diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h index cad87f3ef2ab93d93a74cec0c34b47c695de6bc6..66145a384638b97ee08516e56e1e86a83713c634 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h @@ -123,6 +123,13 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler; +/*! @abstract Handle a JavaScript dialog. + @param webView The web view invoking the delegate method. + @param accept Whether to accept the dialog. + @param value Value to use for prompt dialog. + */ +- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(nullable NSString *)value; + #if TARGET_OS_IPHONE /*! @abstract Allows your app to determine whether or not the given element should show a preview. diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h index 726c4972aa0b32e0dc602e0ab2d71f6ae8ef93ae..c67f408797724cb6d68ed441c0ef1cccd33ca1e0 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h @@ -24,7 +24,6 @@ */ #import - #import NS_ASSUME_NONNULL_BEGIN @@ -78,6 +77,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0)) /*! @abstract Returns the cookie store representing HTTP cookies in this website data store. */ @property (nonatomic, readonly) WKHTTPCookieStore *httpCookieStore WK_API_AVAILABLE(macos(10.13), ios(11.0)); +- (uint64_t)sessionID; + @end NS_ASSUME_NONNULL_END diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm index ed2e5ef682164ae5d52c4a3bfc3d2c8d5d58763a..d00941dda15e35c4b812583a0f3b00dc3123f0d9 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm @@ -44,6 +44,7 @@ #import "_WKWebsiteDataStoreDelegate.h" #import #import +#import #import #import #import @@ -184,6 +185,11 @@ static WallTime toSystemClockTime(NSDate *date) }); } +- (uint64_t) sessionID +{ + return _websiteDataStore->sessionID().toUInt64(); +} + static Vector toWebsiteDataRecords(NSArray *dataRecords) { Vector result; diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..b64d1a6d54ec15a99164294706543cee626d1050 --- /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; +- (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..e7143513ea2be8e1cdab5c86a28643fffea626dd --- /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)); +#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 04922b10809ed4754279184a42169defa5f01ec8..a40edf790cded9f05943aa226db1e1e7e7211cb6 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h @@ -62,6 +62,7 @@ WK_CLASS_AVAILABLE(macos(10.10), ios(8.0)) #endif @property (nonatomic) pid_t presentingApplicationPID WK_API_AVAILABLE(macos(10.13), ios(11.0)); @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 processSwapsOnWindowOpenWithOpener WK_API_AVAILABLE(macos(10.14), ios(12.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 18dae1c505a2d068740d559cf0ad31ea172c7c07..cb58f6df7a99867b149be670fcd76ba76a90be59 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm @@ -261,6 +261,16 @@ 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/_WKRemoteWebInspectorViewController.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm index 2bdb8b9e7256f22096ebaa5d51959aa52389ca0a..2141d9d17497861a6c711f99306de10992a93ce8 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm @@ -25,6 +25,7 @@ #import "config.h" #import "_WKRemoteWebInspectorViewController.h" +#import "WKWebViewPrivate.h" #if PLATFORM(MAC) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1884526cd6ce7d436af6596ab3a45b103031dba1 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp @@ -0,0 +1,136 @@ +/* + * 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, + + LAST_SIGNAL +}; + +struct _WebKitBrowserInspectorPrivate { + int unused { 0 }; +}; + +WEBKIT_DEFINE_TYPE(WebKitBrowserInspector, webkit_browser_inspector, G_TYPE_OBJECT) + +static guint signals[LAST_SIGNAL] = { 0, }; + +static void webkit_browser_inspector_class_init(WebKitBrowserInspectorClass* findClass) +{ + GObjectClass* gObjectClass = G_OBJECT_CLASS(findClass); + + /** + * WebKitBrowserInspector::create-new-page: + * @inspector: the #WebKitBrowserInspector on which the signal is emitted + * + * Emitted when the inspector is requested to create a new page in the provided + * #WebKitWebContext. + * + * This signal is emitted when inspector receives 'Browser.createPage' command + * from its remote client. If the signla is not handled the command will fail. + * + * Returns: %WebKitWebView that contains created page. + */ + signals[CREATE_NEW_PAGE] = g_signal_new( + "create-new-page", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitBrowserInspectorClass, create_new_page), + nullptr, nullptr, + g_cclosure_marshal_generic, +#if PLATFORM(GTK) + GTK_TYPE_WIDGET, +#else + WEBKIT_TYPE_WEB_VIEW, +#endif + 1, + WEBKIT_TYPE_WEB_CONTEXT); +} + +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext* context) +{ + WebKitWebView* newWebView; + g_signal_emit(webkit_browser_inspector_get_default(), signals[CREATE_NEW_PAGE], 0, context, &newWebView); + if (!newWebView) + return nullptr; + return &webkitWebViewGetPage(newWebView); +} + +static gpointer createWebKitBrowserInspector(gpointer) +{ + static GRefPtr browserInspector = adoptGRef(WEBKIT_BROWSER_INSPECTOR(g_object_new(WEBKIT_TYPE_BROWSER_INSPECTOR, nullptr))); + return browserInspector.get(); +} + +/** + * webkit_browser_inspector_get_default: + * + * Gets the default instance of the browser inspector. + * + * Returns: (transfer none): a #WebKitBrowserInspector + */ +WebKitBrowserInspector* webkit_browser_inspector_get_default(void) +{ + static GOnce onceInit = G_ONCE_INIT; + return WEBKIT_BROWSER_INSPECTOR(g_once(&onceInit, createWebKitBrowserInspector, 0)); +} + +/** + * webkit_browser_inspector_initialize_pipe: + * + * Creates browser inspector and configures pipe handler to communicate with + * the parent process. + */ +void webkit_browser_inspector_initialize_pipe(GMainLoop* mainLoop) +{ +#if ENABLE(REMOTE_INSPECTOR) + WebKit::initializeBrowserInspectorPipe(makeUnique(mainLoop)); +#endif +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h new file mode 100644 index 0000000000000000000000000000000000000000..1bff4e694f19264d1be418198b7921780e4f8309 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h @@ -0,0 +1,31 @@ +/* + * 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*); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp index ec20db91bf75ad3968fac93893f2f4bd3cd0ffae..8e82a209cd515a6290564bb9fdf3aa7049c44981 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp @@ -64,7 +64,8 @@ private: void createNewPage(WebPageProxy& page, WebCore::WindowFeatures&& windowFeatures, Ref&& apiNavigationAction, CompletionHandler&&)>&& completionHandler) final { WebKitNavigationAction navigationAction(WTFMove(apiNavigationAction)); - completionHandler(webkitWebViewCreateNewPage(m_webView, windowFeatures, &navigationAction)); + WebPageProxy* newPage = webkitWebViewCreateNewPage(m_webView, windowFeatures, &navigationAction); + completionHandler(adoptRef(newPage)); } void showPage(WebPageProxy*) final @@ -91,6 +92,10 @@ private: { webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTFMove(completionHandler)); } + void handleJavaScriptDialog(WebPageProxy&, bool accept, const String& value) final + { + webkitWebViewHandleJavaScriptDialog(m_webView, accept, value); + } bool canRunBeforeUnloadConfirmPanel() const final { return true; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 33a9b7d5ad060f275dcf7156a8cff3f37644e736..128a5c75807848de10aed628618fc7d149a42792 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -119,9 +119,7 @@ enum { PROP_LOCAL_STORAGE_DIRECTORY, #endif PROP_WEBSITE_DATA_MANAGER, -#if PLATFORM(GTK) PROP_PSON_ENABLED -#endif }; enum { @@ -202,9 +200,7 @@ struct _WebKitWebContextPrivate { RefPtr processPool; bool clientsDetached; -#if PLATFORM(GTK) bool psonEnabled; -#endif GRefPtr faviconDatabase; GRefPtr securityManager; @@ -329,11 +325,9 @@ static void webkitWebContextGetProperty(GObject* object, guint propID, GValue* v case PROP_WEBSITE_DATA_MANAGER: g_value_set_object(value, webkit_web_context_get_website_data_manager(context)); break; -#if PLATFORM(GTK) case PROP_PSON_ENABLED: g_value_set_boolean(value, context->priv->psonEnabled); break; -#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec); } @@ -354,11 +348,9 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa context->priv->websiteDataManager = manager ? WEBKIT_WEBSITE_DATA_MANAGER(manager) : nullptr; break; } -#if PLATFORM(GTK) case PROP_PSON_ENABLED: context->priv->psonEnabled = g_value_get_boolean(value); break; -#endif default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec); } @@ -375,9 +367,7 @@ static void webkitWebContextConstructed(GObject* object) API::ProcessPoolConfiguration configuration; configuration.setInjectedBundlePath(FileSystem::stringFromFileSystemRepresentation(bundleFilename.get())); -#if PLATFORM(GTK) configuration.setProcessSwapsOnNavigation(priv->psonEnabled); -#endif if (!priv->websiteDataManager) priv->websiteDataManager = adoptGRef(webkit_website_data_manager_new("local-storage-directory", priv->localStorageDirectory.data(), nullptr)); @@ -385,6 +375,11 @@ static void webkitWebContextConstructed(GObject* object) if (!webkit_website_data_manager_is_ephemeral(priv->websiteDataManager.get())) WebKit::LegacyGlobalSettings::singleton().setHSTSStorageDirectory(FileSystem::stringFromFileSystemRepresentation(webkit_website_data_manager_get_hsts_cache_directory(priv->websiteDataManager.get()))); + const gchar *singleprocess = g_getenv("MINIBROWSER_SINGLEPROCESS"); + if (singleprocess && *singleprocess) { + // processModel is not set at this point, force single process. + configuration.setUsesSingleWebProcess(true); + } priv->processPool = WebProcessPool::create(configuration); priv->processPool->setPrimaryDataStore(webkitWebsiteDataManagerGetDataStore(priv->websiteDataManager.get())); priv->processPool->setUserMessageHandler([webContext](UserMessage&& message, CompletionHandler&& completionHandler) { @@ -496,7 +491,6 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass WEBKIT_TYPE_WEBSITE_DATA_MANAGER, static_cast(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); -#if PLATFORM(GTK) /** * WebKitWebContext:process-swap-on-cross-site-navigation-enabled: * @@ -519,7 +513,6 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass _("Whether swap Web processes on cross-site navigations is enabled"), FALSE, static_cast(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY))); -#endif /** * WebKitWebContext::download-started: diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index a4aa7c9d75345dc8053c010b01ecd7ff7330eea9..db2f436ad2fb9a90e5e6c0a96e76e726af71ac63 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -131,6 +131,7 @@ enum { CLOSE, SCRIPT_DIALOG, + SCRIPT_DIALOG_HANDLED, DECIDE_POLICY, PERMISSION_REQUEST, @@ -1536,6 +1537,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 @@ -2417,6 +2427,20 @@ 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; + 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 5ab7574c9378f52db87ce75157627c04e9b2e962..5322d725238f5989c04b045615a2de8163329fdf 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h @@ -60,6 +60,7 @@ void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message, Fun void webkitWebViewRunJavaScriptConfirm(WebKitWebView*, const CString& message, Function&& completionHandler); void webkitWebViewRunJavaScriptPrompt(WebKitWebView*, const CString& message, const CString& defaultText, Function&& completionHandler); void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView*, const CString& message, Function&& completionHandler); +void webkitWebViewHandleJavaScriptDialog(WebKitWebView*, bool accept, const String& value); bool webkitWebViewIsShowingScriptDialog(WebKitWebView*); bool webkitWebViewIsScriptDialogRunning(WebKitWebView*, WebKitScriptDialog*); String webkitWebViewGetCurrentScriptDialogMessage(WebKitWebView*); diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp index a68a30983f609d925b45ee16fbe34110b6cabe95..533f45fe6810509b8a0e1823087011a86510770a 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp @@ -230,6 +230,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool { if (wasEventHandled) return; + if (!event.nativeEvent()) + return; WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(m_viewWidget); webkitWebViewBaseForwardNextKeyEvent(webkitWebViewBase); diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..a51cfebc270ca5a91cd94645eeeb005ba9a67caf --- /dev/null +++ b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h @@ -0,0 +1,79 @@ +/* + * 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(WEBKIT2_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef WebKitBrowserInspector_h +#define WebKitBrowserInspector_h + +#include +#include +#include + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_BROWSER_INSPECTOR (webkit_browser_inspector_get_type()) +#define WEBKIT_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspector)) +#define WEBKIT_IS_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) +#define WEBKIT_IS_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) + +typedef struct _WebKitBrowserInspector WebKitBrowserInspector; +typedef struct _WebKitBrowserInspectorClass WebKitBrowserInspectorClass; +typedef struct _WebKitBrowserInspectorPrivate WebKitBrowserInspectorPrivate; + +struct _WebKitBrowserInspector { + GObject parent; + + WebKitBrowserInspectorPrivate *priv; +}; + +struct _WebKitBrowserInspectorClass { + GObjectClass parent_class; + + WebKitWebView *(* create_new_page) (WebKitBrowserInspector *browser_inspector, + WebKitWebContext *context); + + void (*_webkit_reserved0) (void); + void (*_webkit_reserved1) (void); + void (*_webkit_reserved2) (void); + void (*_webkit_reserved3) (void); +}; + +WEBKIT_API GType +webkit_browser_inspector_get_type (void); + +WEBKIT_API WebKitBrowserInspector * +webkit_browser_inspector_get_default (void); + +WEBKIT_API void +webkit_browser_inspector_initialize_pipe (GMainLoop*); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/gtk/webkit2.h b/Source/WebKit/UIProcess/API/gtk/webkit2.h index 930b17b6629e04d0dfa2222bbc3217877c6e1812..395462e5f01c195231e9296d1204167cded99ad3 100644 --- a/Source/WebKit/UIProcess/API/gtk/webkit2.h +++ b/Source/WebKit/UIProcess/API/gtk/webkit2.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..6dffa4fa10a9a64f778a0a77c760c2e76b2f9968 --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h @@ -0,0 +1,79 @@ +/* + * 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(WEBKIT2_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef WebKitBrowserInspector_h +#define WebKitBrowserInspector_h + +#include +#include +#include + +G_BEGIN_DECLS + +#define WEBKIT_TYPE_BROWSER_INSPECTOR (webkit_browser_inspector_get_type()) +#define WEBKIT_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspector)) +#define WEBKIT_IS_BROWSER_INSPECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) +#define WEBKIT_IS_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_BROWSER_INSPECTOR)) +#define WEBKIT_BROWSER_INSPECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass)) + +typedef struct _WebKitBrowserInspector WebKitBrowserInspector; +typedef struct _WebKitBrowserInspectorClass WebKitBrowserInspectorClass; +typedef struct _WebKitBrowserInspectorPrivate WebKitBrowserInspectorPrivate; + +struct _WebKitBrowserInspector { + GObject parent; + + WebKitBrowserInspectorPrivate *priv; +}; + +struct _WebKitBrowserInspectorClass { + GObjectClass parent_class; + + WebKitWebView *(* create_new_page) (WebKitBrowserInspector *browser_inspector, + WebKitWebContext *context); + + void (*_webkit_reserved0) (void); + void (*_webkit_reserved1) (void); + void (*_webkit_reserved2) (void); + void (*_webkit_reserved3) (void); +}; + +WEBKIT_API GType +webkit_browser_inspector_get_type (void); + +WEBKIT_API WebKitBrowserInspector * +webkit_browser_inspector_get_default (void); + +WEBKIT_API void +webkit_browser_inspector_initialize_pipe (GMainLoop*); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitScriptDialogWPE.cpp b/Source/WebKit/UIProcess/API/wpe/WebKitScriptDialogWPE.cpp index 3ad6e613657557045ec07ce4bcdb3eea0d1e7dae..a53a4aa01bd692ba34bacb9f663c335cfd3821a7 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitScriptDialogWPE.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WebKitScriptDialogWPE.cpp @@ -22,14 +22,26 @@ #include "WebKitScriptDialogPrivate.h" -void webkitScriptDialogAccept(WebKitScriptDialog*) +void webkitScriptDialogAccept(WebKitScriptDialog* dialog) { + if (!dialog->completionHandler) + return; + auto completionHandler = std::exchange(dialog->completionHandler, nullptr); + completionHandler(true, String()); } -void webkitScriptDialogDismiss(WebKitScriptDialog*) +void webkitScriptDialogDismiss(WebKitScriptDialog* dialog) { + if (!dialog->completionHandler) + return; + auto completionHandler = std::exchange(dialog->completionHandler, nullptr); + completionHandler(false, String()); } -void webkitScriptDialogSetUserInput(WebKitScriptDialog*, const String&) +void webkitScriptDialogSetUserInput(WebKitScriptDialog* dialog, const String& value) { + if (!dialog->completionHandler) + return; + auto completionHandler = std::exchange(dialog->completionHandler, nullptr); + completionHandler(true, value); } diff --git a/Source/WebKit/UIProcess/API/wpe/webkit.h b/Source/WebKit/UIProcess/API/wpe/webkit.h index 02e258253e47fbf6594c20f743d0faeac8a4eefe..e051fdf396dc65717def6b36168b5538e3cb2f4d 100644 --- a/Source/WebKit/UIProcess/API/wpe/webkit.h +++ b/Source/WebKit/UIProcess/API/wpe/webkit.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/Source/WebKit/UIProcess/BrowserInspectorController.cpp b/Source/WebKit/UIProcess/BrowserInspectorController.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74b702953a54425bb80090f60b0a321b402e68eb --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorController.cpp @@ -0,0 +1,238 @@ +/* + * 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 "BrowserInspectorController.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include "InspectorPlaywrightAgentClient.h" +#include "WebPageInspectorController.h" +#include "WebPageProxy.h" +#include "WebProcessPool.h" +#include "WebProcessProxy.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace Inspector; + +namespace WebKit { + +static Vector allPages() +{ + ASSERT(isMainThread()); + Vector result; + for (WebProcessPool* pool : WebProcessPool::allProcessPools()) { + for (auto& process : pool->processes()) { + result.appendRange(process->pages().begin(), process->pages().end()); + } + } + return result; +} + +class BrowserInspectorController::PageProxyChannel : public FrontendChannel { + WTF_MAKE_FAST_ALLOCATED; +public: + PageProxyChannel(FrontendChannel& frontendChannel, String pageProxyID, WebPageProxy& page) + : 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; + if (!JSON::Value::parseJSON(message, parsedMessage)) + return message; + + RefPtr messageObject; + if (!parsedMessage->asObject(messageObject)) + return message; + + messageObject->setString("pageProxyId"_s, m_pageProxyID); + return messageObject->toJSONString(); + } + + String m_pageProxyID; + FrontendChannel& m_frontendChannel; + WebPageProxy& m_page; +}; + +BrowserInspectorController::BrowserInspectorController(std::unique_ptr client) + : m_frontendChannel(nullptr) + , m_frontendRouter(FrontendRouter::create()) + , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) + , m_browserAgentClient(std::move(client)) +{ + PageProxyIDMap* map = this; + auto browserAgent = makeUnique(m_frontendRouter, m_backendDispatcher, m_browserAgentClient.get(), *map); + m_browserAgent = browserAgent.get(); + m_agents.append(WTFMove(browserAgent)); +} + +BrowserInspectorController::~BrowserInspectorController() +{ + if (m_frontendChannel) + disconnectFrontend(); +} + +void BrowserInspectorController::connectFrontend(FrontendChannel& frontendChannel) +{ + ASSERT(!m_frontendChannel); + m_frontendChannel = &frontendChannel; + WebPageInspectorController::setObserver(this); + + bool connectingFirstFrontend = !m_frontendRouter->hasFrontends(); + m_frontendRouter->connectFrontend(frontendChannel); + if (connectingFirstFrontend) + m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get()); + + connectToAllPages(); +} + +void BrowserInspectorController::disconnectFrontend() +{ + ASSERT(m_frontendChannel); + disconnectFromAllPages(); + + m_frontendRouter->disconnectFrontend(*m_frontendChannel); + if (!m_frontendRouter->hasFrontends()) + m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed); + + WebPageInspectorController::setObserver(nullptr); + m_frontendChannel = nullptr; +} + +void BrowserInspectorController::dispatchMessageFromFrontend(const String& message) +{ + m_backendDispatcher->dispatch(message, BackendDispatcher::Mode::FailIfDomainIsMissing, [&](const RefPtr& messageObject) { + RefPtr pageProxyIDValue; + if (!messageObject->getValue("pageProxyId"_s, pageProxyIDValue)) + return BackendDispatcher::DispatchResult::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::DispatchResult::Finished; + } + + + if (auto pageProxyChannel = m_pageProxyChannels.get(pageProxyID)) { + pageProxyChannel->dispatchMessageFromFrontend(message); + return BackendDispatcher::DispatchResult::Finished; + } + + m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidRequest, "Cannot find page proxy with provided 'pageProxyId'"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::DispatchResult::Finished; + }); +} + +void BrowserInspectorController::connectToAllPages() +{ + for (auto* page : allPages()) + connectToPage(*page); +} + +void BrowserInspectorController::disconnectFromAllPages() +{ + for (auto it = m_pageProxyChannels.begin(); it != m_pageProxyChannels.end(); ++it) + it->value->disconnect(); + m_pageProxyChannels.clear(); +} + +void BrowserInspectorController::connectToPage(WebPageProxy& page) +{ + String pageProxyID = InspectorPlaywrightAgent::toPageProxyIDProtocolString(page); + auto pageProxyChannel = makeUnique(*m_frontendChannel, pageProxyID, page); + page.inspectorController().connectFrontend(*pageProxyChannel); + // Always pause new targets if controlled remotely. + page.inspectorController().setPauseOnStart(true); + m_pageProxyChannels.set(pageProxyID, WTFMove(pageProxyChannel)); +} + +void BrowserInspectorController::didCreateInspectorController(WebPageProxy& page) +{ + ASSERT(m_frontendChannel); + // Auto-connect to all new pages. + connectToPage(page); + m_browserAgent->didCreateWebPageProxy(page); +} + +void BrowserInspectorController::willDestroyInspectorController(WebPageProxy& page) +{ + m_browserAgent->willDestroyWebPageProxy(page); + + String pageProxyID = InspectorPlaywrightAgent::toPageProxyIDProtocolString(page); + auto it = m_pageProxyChannels.find(pageProxyID); + ASSERT(it != m_pageProxyChannels.end()); + it->value->disconnect(); + m_pageProxyChannels.remove(it); +} + +void BrowserInspectorController::didFailProvisionalLoad(WebPageProxy& page, uint64_t navigationID, const String& error) +{ + m_browserAgent->didFailProvisionalLoad(page, navigationID, error); +} + +WebPageProxy* BrowserInspectorController::findPageProxy(const String& pageProxyID) +{ + if (auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID)) + return &pageProxyChannel->page(); + + return nullptr; +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorController.h b/Source/WebKit/UIProcess/BrowserInspectorController.h new file mode 100644 index 0000000000000000000000000000000000000000..4516c31d02caabbb731f662e96436569daf3eaeb --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorController.h @@ -0,0 +1,85 @@ +/* + * 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 "InspectorPlaywrightAgent.h" +#include "WebPageInspectorController.h" +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class InspectorPlaywrightAgent; +class InspectorPlaywrightAgentClient; + +class BrowserInspectorController : private WebPageInspectorControllerObserver, private PageProxyIDMap { + WTF_MAKE_NONCOPYABLE(BrowserInspectorController); + WTF_MAKE_FAST_ALLOCATED; +public: + BrowserInspectorController(std::unique_ptr client); + ~BrowserInspectorController(); + + void connectFrontend(Inspector::FrontendChannel&); + void disconnectFrontend(); + void dispatchMessageFromFrontend(const String& message); + +private: + class TargetHandler; + class PageProxyChannel; + + // WebPageInspectorControllerObserver + void didCreateInspectorController(WebPageProxy&) override; + void willDestroyInspectorController(WebPageProxy&) override; + void didFailProvisionalLoad(WebPageProxy&, uint64_t navigationID, const String& error) override; + + // PageProxyIDMap + WebPageProxy* findPageProxy(const String& pageProxyID) override; + + void connectToAllPages(); + void disconnectFromAllPages(); + void connectToPage(WebPageProxy&); + + Inspector::FrontendChannel* m_frontendChannel { nullptr }; + Ref m_frontendRouter; + Ref m_backendDispatcher; + std::unique_ptr m_browserAgentClient; + Inspector::AgentRegistry m_agents; + InspectorPlaywrightAgent* m_browserAgent { nullptr }; + HashMap> m_pageProxyChannels; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e07123453ecab2611ff4918cec37ee6e744a23a6 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp @@ -0,0 +1,57 @@ +/* + * 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 "BrowserInspectorController.h" +#include "RemoteInspectorPipe.h" +#include +#include "InspectorPlaywrightAgentClient.h" + +namespace WebKit { + +void initializeBrowserInspectorPipe(std::unique_ptr client) +{ + class BrowserInspectorPipe { + public: + BrowserInspectorPipe(std::unique_ptr client) + : m_browserInspectorController(std::move(client)) + , m_remoteInspectorPipe(m_browserInspectorController) + { + } + + BrowserInspectorController m_browserInspectorController; + RemoteInspectorPipe m_remoteInspectorPipe; + }; + + static NeverDestroyed pipe(std::move(client)); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.h b/Source/WebKit/UIProcess/BrowserInspectorPipe.h new file mode 100644 index 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/PageClientImplCocoa.mm b/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm index 40949c2f409cd42dca616c29649852ff222f2af5..b56ff05f55263e00bdccfda75249a767e965fe82 100644 --- a/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/PageClientImplCocoa.mm @@ -40,7 +40,7 @@ namespace WebKit { PageClientImplCocoa::PageClientImplCocoa(WKWebView *webView) : m_webView { webView } #if USE(DICTATION_ALTERNATIVES) - , m_alternativeTextUIController { makeUnique() } + , m_alternativeTextUIController { makeUnique() } #endif { } diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h index 454c61ffdefecc476d1560c7c43f5b5d345f281d..6de7509037b7683ddd403ee247bdf2845ce4e87a 100644 --- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h +++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.h @@ -27,6 +27,8 @@ #if HAVE(APP_SSO) +#include +#include #include "SOAuthorizationSession.h" #include @@ -39,6 +41,8 @@ class NavigationAction; namespace WebKit { +class WebPageProxy; + // FSM: Idle => Active => Completed class PopUpSOAuthorizationSession final : public SOAuthorizationSession { public: diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm index 0f18038de989e69a8432c85b71b6c04e931302b3..82a966779403346aed174dcfcd01a79691956d7b 100644 --- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm +++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/PopUpSOAuthorizationSession.mm @@ -29,6 +29,7 @@ #if HAVE(APP_SSO) #import "APINavigationAction.h" +#import "WebPageProxy.h" #import "WKNavigationDelegatePrivate.h" #import "WKUIDelegate.h" #import "WKWebViewConfigurationPrivate.h" diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h index ecf6a5c2dce317eb58f77f33f57010fdabdf87ed..c6a1125dc1b8c06fe752ec5ca86239dfeac3c3d6 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h @@ -91,6 +91,7 @@ private: void runJavaScriptAlert(WebPageProxy&, const WTF::String&, WebFrameProxy*, 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, CompletionHandler&&) final; void decidePolicyForGeolocationPermissionRequest(WebPageProxy&, WebFrameProxy&, const FrameInfoData&, Function&) final; @@ -170,6 +171,7 @@ private: bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1; + bool webViewHandleJavaScriptDialogValue : 1; bool webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler : 1; bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1; bool webViewRequestGeolocationPermissionForFrameDecisionHandler : 1; diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm index c562fac4fb66635b63e51f6a43a4879c357f4f73..931be3735d0f46c19afd1024ab6ee0400055c09d 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm @@ -102,6 +102,7 @@ void UIDelegate::setDelegate(id delegate) m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)]; + m_delegateMethods.webViewHandleJavaScriptDialogValue = [delegate respondsToSelector:@selector(webView:handleJavaScriptDialog:value:)]; m_delegateMethods.webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:)]; m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)]; m_delegateMethods.webViewRequestGeolocationPermissionForFrameDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestGeolocationPermissionForFrame:decisionHandler:)]; @@ -338,6 +339,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 handleJavaScriptDialog:accept value:value]; +} + void UIDelegate::UIClient::requestStorageAccessConfirm(WebPageProxy&, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, CompletionHandler&& completionHandler) { auto delegate = m_uiDelegate.m_delegate.get(); diff --git a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm index e8baa21f6b46266fc7a39b150037f377a3107e9d..cbb9f97e9c774a51f66436459dd4dfe5d558fffb 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm @@ -138,6 +138,13 @@ static void registerUserDefaultsIfNeeded() [[NSUserDefaults standardUserDefaults] registerDefaults:registrationDictionary]; } +void WebProcessPool::setIgnoreTLSErrors(bool ignoreTLSErrors) +{ + m_ignoreTLSErrors = ignoreTLSErrors; + if (m_networkProcess) + m_networkProcess->send(Messages::NetworkProcess::SetIgnoreTLSErrors(m_ignoreTLSErrors), 0); +} + void WebProcessPool::updateProcessSuppressionState() { if (m_networkProcess) @@ -365,7 +372,7 @@ void WebProcessPool::platformInitializeWebProcess(const WebProcessProxy& process #if PLATFORM(MAC) auto screenProperties = WebCore::collectScreenProperties(); parameters.screenProperties = WTFMove(screenProperties); - parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); + parameters.useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); #endif #if PLATFORM(IOS) @@ -482,6 +489,8 @@ void WebProcessPool::platformInitializeNetworkProcess(NetworkProcessCreationPara } } + parameters.ignoreTLSErrors = m_ignoreTLSErrors; + parameters.networkATSContext = adoptCF(_CFNetworkCopyATSContext()); parameters.shouldSuppressMemoryPressureHandler = [defaults boolForKey:WebKitSuppressMemoryPressureHandlerDefaultsKey]; @@ -642,8 +651,8 @@ void WebProcessPool::registerNotificationObservers() #if ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING) 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)); }]; #endif diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp index 6bbd1cabd27ae2847648a8c2edcf9acfcd556ff5..38d101b9a96986e40f6e9f0261fa429a3d516e2e 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp @@ -37,6 +37,7 @@ #include "WebProcessProxy.h" #include #include +#include #if PLATFORM(GTK) #include @@ -119,6 +120,10 @@ void DrawingAreaProxyCoordinatedGraphics::paint(BackingStore::PlatformGraphicsCo void DrawingAreaProxyCoordinatedGraphics::sizeDidChange() { + for (auto& value : m_callbacks) + value(); + m_callbacks.clear(); + #if USE(DIRECT2D) m_backingStore = nullptr; #endif @@ -133,6 +138,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange() backingStoreStateDidChange(RespondImmediately); } +void DrawingAreaProxyCoordinatedGraphics::waitForSizeUpdate(Function&& callback) +{ + m_callbacks.append(WTFMove(callback)); +} + void DrawingAreaProxyCoordinatedGraphics::waitForBackingStoreUpdateOnNextPaint() { m_hasReceivedFirstUpdate = true; diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h index d7695088e7cfc4f638f157338754f9f157489749..ba114d47ac079661702e44f19853398f5c1d6b55 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h @@ -30,6 +30,7 @@ #include "BackingStore.h" #include "DrawingAreaProxy.h" #include "LayerTreeContext.h" +#include #include namespace WebCore { @@ -49,6 +50,7 @@ public: bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); } const LayerTreeContext& layerTreeContext() const { return m_layerTreeContext; } + void waitForSizeUpdate(Function&&); private: // DrawingAreaProxy @@ -126,6 +128,8 @@ private: // For a new Drawing Area don't draw anything until the WebProcess has sent over the first content. bool m_hasReceivedFirstUpdate { false }; + Vector> m_callbacks; + #if !PLATFORM(WPE) bool m_isBackingStoreDiscardable { true }; std::unique_ptr m_backingStore; diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.h b/Source/WebKit/UIProcess/DrawingAreaProxy.h index 4896c404bc8b25d69360de7d1c509383282b2317..14bdebf732e929ea367c961f9d0bec85202bbae3 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.h +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h @@ -70,6 +70,7 @@ public: const WebCore::IntSize& size() const { return m_size; } bool setSize(const WebCore::IntSize&, const WebCore::IntSize& scrollOffset = { }); + void waitForSizeUpdate(Function&&); // The timeout we use when waiting for a DidUpdateGeometry message. static constexpr Seconds didUpdateBackingStoreStateTimeout() { return Seconds::fromMilliseconds(500); } diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp index 6928ca2fbfb6939062e3cd14bb7ba6f2fdc87f5f..c4645302296540a408aa88dabb64fd5e9a04f3f7 100644 --- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp +++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp @@ -27,11 +27,10 @@ #include "InspectorTargetProxy.h" #include "ProvisionalPageProxy.h" -#include "WebFrameProxy.h" +#include "WebPageInspectorController.h" #include "WebPageInspectorTarget.h" #include "WebPageMessages.h" #include "WebPageProxy.h" -#include "WebProcessProxy.h" namespace WebKit { @@ -39,18 +38,17 @@ using namespace Inspector; std::unique_ptr InspectorTargetProxy::create(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) { - return makeUnique(page, targetId, type); + return makeUnique(page, nullptr, targetId, type); } -std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId, Inspector::InspectorTargetType type) +std::unique_ptr InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId) { - auto target = InspectorTargetProxy::create(provisionalPage.page(), targetId, type); - target->m_provisionalPage = makeWeakPtr(provisionalPage); - return target; + return makeUnique(provisionalPage.page(), &provisionalPage, targetId, Inspector::InspectorTargetType::Page); } -InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, const String& targetId, Inspector::InspectorTargetType type) +InspectorTargetProxy::InspectorTargetProxy(WebPageProxy& page, ProvisionalPageProxy* provisionalPage, const String& targetId, Inspector::InspectorTargetType type) : m_page(page) + , m_provisionalPage(makeWeakPtr(provisionalPage)) , m_identifier(targetId) , m_type(type) { @@ -83,6 +81,9 @@ void InspectorTargetProxy::disconnect() void InspectorTargetProxy::sendMessageToTargetBackend(const String& message) { + if (m_page.inspectorController().dispatchMessageToTargetBackend(message)) + return; + if (m_provisionalPage) { m_provisionalPage->send(Messages::WebPage::SendMessageToTargetBackend(identifier(), message)); return; @@ -97,6 +98,31 @@ void InspectorTargetProxy::didCommitProvisionalTarget() m_provisionalPage = nullptr; } +void InspectorTargetProxy::willResume() +{ + if (m_page.hasRunningProcess()) + m_page.send(Messages::WebPage::ResumeInspectorIfPausedInNewWindow()); +} + +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 a2239cec8e18850f35f7f88a9c4ebadc62bf4023..79f3ff84327dc075ec96983e04db4b10343b7fae 100644 --- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h +++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h @@ -37,13 +37,13 @@ class WebPageProxy; // NOTE: This UIProcess side InspectorTarget doesn't care about the frontend channel, since // any target -> frontend messages will be routed to the WebPageProxy with a targetId. -class InspectorTargetProxy final : public Inspector::InspectorTarget { +class InspectorTargetProxy : public Inspector::InspectorTarget { WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(InspectorTargetProxy); public: static std::unique_ptr create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); - static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType); - InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType); + static std::unique_ptr create(ProvisionalPageProxy&, const String& targetId); + InspectorTargetProxy(WebPageProxy&, ProvisionalPageProxy*, const String& targetId, Inspector::InspectorTargetType); ~InspectorTargetProxy() = default; Inspector::InspectorTargetType type() const final { return m_type; } @@ -55,12 +55,17 @@ 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; + WebPageProxy& m_page; + WeakPtr m_provisionalPage; String m_identifier; Inspector::InspectorTargetType m_type; - WeakPtr m_provisionalPage; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp index 1861cff806131196ea49b4f8aca6665beebbf6e8..7c44efa7cdb60642608fbbbbd4811f834f6f7545 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp @@ -26,12 +26,18 @@ #include "config.h" #include "WebPageInspectorController.h" +#include "APINavigation.h" #include "InspectorBrowserAgent.h" +#include "InspectorDialogAgent.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 @@ -48,27 +54,96 @@ static String getTargetID(const ProvisionalPageProxy& provisionalPage) return WebPageInspectorTarget::toTargetID(provisionalPage.webPageID()); } +WebPageInspectorControllerObserver* WebPageInspectorController::s_observer = nullptr; + +void WebPageInspectorController::setObserver(WebPageInspectorControllerObserver* observer) +{ + s_observer = observer; +} + WebPageInspectorController::WebPageInspectorController(WebPageProxy& page) : m_frontendRouter(FrontendRouter::create()) , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) , m_page(page) { - auto targetAgent = makeUnique(m_frontendRouter.get(), m_backendDispatcher.get()); - m_targetAgent = targetAgent.get(); - m_agents.append(WTFMove(targetAgent)); } void WebPageInspectorController::init() { + 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_page); + m_emulationAgent = emulationAgent.get(); + m_agents.append(WTFMove(emulationAgent)); + auto inputAgent = makeUnique(m_backendDispatcher.get(), m_page); + m_inputAgent = inputAgent.get(); + m_agents.append(WTFMove(inputAgent)); + m_agents.append(makeUnique(m_backendDispatcher.get(), m_frontendRouter.get(), m_page)); + + if (s_observer) + s_observer->didCreateInspectorController(m_page); + + // window.open will create page with already running process. + if (!m_page.hasRunningProcess()) + return; String pageTargetId = WebPageInspectorTarget::toTargetID(m_page.webPageID()); createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page); } +void WebPageInspectorController::didFinishAttachingToWebProcess() +{ + String pageTargetID = WebPageInspectorTarget::toTargetID(m_page.webPageID()); + // Create target only after attaching to a Web Process first time. Before that + // we cannot event establish frontend connection. + if (m_targets.contains(pageTargetID)) + return; + createInspectorTarget(pageTargetID, Inspector::InspectorTargetType::Page); +} + void WebPageInspectorController::pageClosed() { + String pageTargetId = WebPageInspectorTarget::toTargetID(m_page.webPageID()); + destroyInspectorTarget(pageTargetId); + disconnectAllFrontends(); m_agents.discardValues(); + + if (s_observer) + s_observer->willDestroyInspectorController(m_page); +} + +bool WebPageInspectorController::pageCrashed(ProcessTerminationReason reason) +{ + if (reason != ProcessTerminationReason::Crash) + return false; + String targetId = WebPageInspectorTarget::toTargetID(m_page.webPageID()); + 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::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(); } bool WebPageInspectorController::hasLocalFrontend() const @@ -82,6 +157,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) @@ -100,8 +186,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(); + } m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); @@ -124,6 +212,8 @@ void WebPageInspectorController::disconnectAllFrontends() // Disconnect any remaining remote frontends. m_frontendRouter->disconnectAllFrontends(); + m_pendingNavigations.clear(); + m_page.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); #if ENABLE(REMOTE_INSPECTOR) @@ -136,6 +226,11 @@ void WebPageInspectorController::dispatchMessageFromFrontend(const String& messa m_backendDispatcher->dispatch(message); } +bool WebPageInspectorController::dispatchMessageToTargetBackend(const String& message) +{ + return m_backendDispatcher->dispatch(message, BackendDispatcher::Mode::ContinueIfDomainIsMissing) == BackendDispatcher::DispatchResult::Finished; +} + #if ENABLE(REMOTE_INSPECTOR) void WebPageInspectorController::setIndicating(bool indicating) { @@ -150,6 +245,55 @@ void WebPageInspectorController::setIndicating(bool indicating) } #endif +void WebPageInspectorController::navigate(WebCore::ResourceRequest&& request, WebFrameProxy* frame, NavigationHandler&& completionHandler) +{ + auto navigation = m_page.loadRequestForInspector(WTFMove(request), frame); + if (!navigation) { + completionHandler("Failed to navigate"_s, 0); + return; + } + + m_pendingNavigations.set(navigation->navigationID(), WTFMove(completionHandler)); +} + +void WebPageInspectorController::didReceivePolicyDecision(WebCore::PolicyAction action, uint64_t 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, 0); + else + completionHandler(String(), navigationID); +} + +void WebPageInspectorController::didDestroyNavigation(uint64_t 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(), 0); +} + +void WebPageInspectorController::didFailProvisionalLoadForFrame(uint64_t navigationID, const WebCore::ResourceError& error) +{ + if (s_observer) + s_observer->didFailProvisionalLoad(m_page, navigationID, error.localizedDescription()); +} + void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { addTarget(InspectorTargetProxy::create(m_page, targetId, type)); @@ -169,6 +313,33 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta m_targetAgent->sendMessageFromTargetToFrontend(targetId, message); } +void WebPageInspectorController::setPauseOnStart(bool shouldPause) +{ + ASSERT(m_frontendRouter->hasFrontends()); + String errorString; + m_targetAgent->setPauseOnStart(errorString, shouldPause); +} + +bool WebPageInspectorController::shouldPauseLoading() const +{ + if (!m_frontendRouter->hasFrontends()) + return false; + + if (!m_page.isPageOpenedByDOMShowingInitialEmptyDocument()) + return false; + + auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_page.webPageID())); + ASSERT(target); + return target->isPaused(); +} + +void WebPageInspectorController::setContinueLoadingCallback(WTF::Function&& callback) +{ + auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_page.webPageID())); + ASSERT(target); + target->setResumeCallback(WTFMove(callback)); +} + bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const { if (!m_frontendRouter->hasFrontends()) @@ -188,7 +359,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) @@ -241,4 +412,20 @@ void WebPageInspectorController::addTarget(std::unique_ptr m_targets.set(target->identifier(), WTFMove(target)); } +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_page.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_page.preferences().setUsesBackForwardCache(false); + + // Enable popup debugging. + // TODO: allow to set preferences over the inspector protocol or find a better place for this. + m_page.preferences().setJavaScriptCanOpenWindowsAutomatically(true); +} + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h index 9ce5ef36b652fd56a843c1d12a4c3c3cf639282c..5b6d5f4d28ccbde11df85782561ba1d9e6908490 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h @@ -26,6 +26,7 @@ #pragma once #include "InspectorTargetProxy.h" +#include "ProcessTerminationReason.h" #include #include #include @@ -37,6 +38,13 @@ namespace Inspector { class BackendDispatcher; class FrontendChannel; class FrontendRouter; +class InspectorTarget; +} + +namespace WebCore { +class ResourceError; +class ResourceRequest; +enum class PolicyAction : uint8_t; } namespace WebKit { @@ -44,6 +52,20 @@ namespace WebKit { class InspectorBrowserAgent; struct WebPageAgentContext; +class WebFrameProxy; +class WebPageInspectorEmulationAgent; +class WebPageInspectorInputAgent; + +class WebPageInspectorControllerObserver { +public: + virtual void didCreateInspectorController(WebPageProxy&) = 0; + virtual void willDestroyInspectorController(WebPageProxy&) = 0; + virtual void didFailProvisionalLoad(WebPageProxy&, uint64_t navigationID, const String& error) = 0; + +protected: + virtual ~WebPageInspectorControllerObserver() = default; +}; + class WebPageInspectorController { WTF_MAKE_NONCOPYABLE(WebPageInspectorController); WTF_MAKE_FAST_ALLOCATED; @@ -51,7 +73,17 @@ public: WebPageInspectorController(WebPageProxy&); void init(); + void didFinishAttachingToWebProcess(); + + static void setObserver(WebPageInspectorControllerObserver*); + void pageClosed(); + bool pageCrashed(ProcessTerminationReason); + + void didShowPage(); + + void didProcessAllPendingKeyboardEvents(); + void didProcessAllPendingMouseEvents(); bool hasLocalFrontend() const; @@ -60,15 +92,28 @@ public: void disconnectAllFrontends(); void dispatchMessageFromFrontend(const String& message); + bool dispatchMessageToTargetBackend(const String&); #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); #endif + using NavigationHandler = Function; + void navigate(WebCore::ResourceRequest&&, WebFrameProxy*, NavigationHandler&&); + void didReceivePolicyDecision(WebCore::PolicyAction action, uint64_t navigationID); + void didDestroyNavigation(uint64_t navigationID); + + void didFailProvisionalLoadForFrame(uint64_t 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 shouldPauseLoading() const; + void setContinueLoadingCallback(WTF::Function&&); + bool shouldPauseLoading(const ProvisionalPageProxy&) const; void setContinueLoadingCallback(const ProvisionalPageProxy&, WTF::Function&&); @@ -84,6 +129,7 @@ private: void createLazyAgents(); void addTarget(std::unique_ptr&&); + void adjustPageSettings(); Ref m_frontendRouter; Ref m_backendDispatcher; @@ -92,11 +138,16 @@ private: WebPageProxy& m_page; Inspector::InspectorTargetAgent* m_targetAgent; + WebPageInspectorEmulationAgent* m_emulationAgent { nullptr }; + WebPageInspectorInputAgent* m_inputAgent { nullptr }; HashMap> m_targets; InspectorBrowserAgent* m_enabledInspectorBrowserAgent; bool m_didCreateLazyAgents { false }; + HashMap m_pendingNavigations; + + static WebPageInspectorControllerObserver* s_observer; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca5965f9d682c0821a40f0d1d43e5cbeda1353a5 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorDialogAgent.h" + +#include "APINavigation.h" +#include "APIUIClient.h" +#include "WebPageProxy.h" +#include + + +namespace WebKit { + +using namespace Inspector; + +InspectorDialogAgent::InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page) + : InspectorAgentBase("Dialog"_s) + , m_frontendDispatcher(makeUnique(frontendRouter)) + , m_backendDispatcher(DialogBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +InspectorDialogAgent::~InspectorDialogAgent() +{ + Inspector::ErrorString err; + disable(err); +} + +void InspectorDialogAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ +} + +void InspectorDialogAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ +} + +void InspectorDialogAgent::enable(Inspector::ErrorString& errorString) +{ + if (m_page.inspectorDialogAgent()) { + errorString = "Dialog domain is already enabled."_s; + return; + } + m_page.setInspectorDialogAgent(this); +} + +void InspectorDialogAgent::disable(Inspector::ErrorString&) +{ + if (m_page.inspectorDialogAgent() != this) + return; + m_page.setInspectorDialogAgent(nullptr); +} + +void InspectorDialogAgent::handleJavaScriptDialog(Inspector::ErrorString& errorString, bool accept, const String* value) +{ + m_page.uiClient().handleJavaScriptDialog(m_page, accept, value ? *value : String()); +} + +void InspectorDialogAgent::javascriptDialogOpening(const String& type, const String& message, const String* defaultValue) { + m_frontendDispatcher->javascriptDialogOpening(type, message, defaultValue); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.h b/Source/WebKit/UIProcess/InspectorDialogAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..f356c613945fd263889bc74166bef2b279ab4ca1 --- /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; + + void enable(Inspector::ErrorString&) override; + void disable(Inspector::ErrorString&) override; + void handleJavaScriptDialog(Inspector::ErrorString& errorString, bool accept, const String* promptText) override; + + void javascriptDialogOpening(const String& type, const String& message, const String* defaultValue = nullptr); + +private: + void platformHandleJavaScriptDialog(bool accept, const String* promptText); + std::unique_ptr m_frontendDispatcher; + Ref m_backendDispatcher; + WebPageProxy& m_page; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aebf8bc2080aa7464a374b322489413bb2d91821 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp @@ -0,0 +1,590 @@ +/* + * 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 "APIPageConfiguration.h" +#include "InspectorPlaywrightAgentClient.h" +#include "InspectorTargetProxy.h" +#include "NetworkProcessMessages.h" +#include "NetworkProcessProxy.h" +#include "WebGeolocationManagerProxy.h" +#include "WebGeolocationPosition.h" +#include "WebPageInspectorController.h" +#include "WebPageInspectorTarget.h" +#include "WebPageProxy.h" +#include "WebProcessPool.h" +#include "WebProcessProxy.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace Inspector; + +namespace WebKit { + +namespace { + +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.valueOr(-1)) + .setHttpOnly(cookie.httpOnly) + .setSecure(cookie.secure) + .setSession(cookie.session) + .setSameSite(cookieSameSitePolicy(cookie.sameSite)) + .release(); +} + +Ref buildPageProxyInfo(const WebPageProxy& page) { + auto result = Inspector::Protocol::Playwright::PageProxyInfo::create() + .setPageProxyId(InspectorPlaywrightAgent::toPageProxyIDProtocolString(page)) + .setBrowserContextId(InspectorPlaywrightAgent::toBrowserContextIDProtocolString(page.sessionID())) + .release(); + auto* opener = page.configuration().relatedPage(); + if (opener) + result->setOpenerId(InspectorPlaywrightAgent::toPageProxyIDProtocolString(*opener)); + return result; +} + +} // namespace + +Vector BrowserContext::pages() const { + Vector pages; + for (auto& process : processPool->processes()) { + for (auto* page : process->pages()) + pages.append(page); + } + return pages; +} + +class InspectorPlaywrightAgent::BrowserContextDeletion { + WTF_MAKE_NONCOPYABLE(BrowserContextDeletion); + WTF_MAKE_FAST_ALLOCATED; +public: + BrowserContextDeletion(const BrowserContext& context, size_t numberOfPages, Ref&& callback) + : m_browserContext(context) + , m_numberOfPages(numberOfPages) + , m_callback(WTFMove(callback)) { } + + void willDestroyPage(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) { + Vector 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; } + +private: + BrowserContext m_browserContext; + size_t m_numberOfPages; + Ref m_callback; +}; + + +InspectorPlaywrightAgent::InspectorPlaywrightAgent(Inspector::FrontendRouter& frontendRouter, Inspector::BackendDispatcher& backendDispatcher, InspectorPlaywrightAgentClient* client, PageProxyIDMap& pageProxyIDMap) + : InspectorAgentBase("Playwright"_s) + , m_frontendDispatcher(makeUnique(frontendRouter)) + , m_backendDispatcher(PlaywrightBackendDispatcher::create(backendDispatcher, this)) + , m_client(client) + , m_pageProxyIDMap(pageProxyIDMap) +{ +} + +InspectorPlaywrightAgent::~InspectorPlaywrightAgent() = default; + +void InspectorPlaywrightAgent::didCreateWebPageProxy(const WebPageProxy& page) +{ + if (m_isConnected) + m_frontendDispatcher->pageProxyCreated(buildPageProxyInfo(page)); +} + +void InspectorPlaywrightAgent::willDestroyWebPageProxy(const WebPageProxy& page) +{ + if (!m_isConnected) + return; + + m_frontendDispatcher->pageProxyDestroyed(toPageProxyIDProtocolString(page)); + + auto it = m_browserContextDeletions.find(page.sessionID()); + if (it == m_browserContextDeletions.end()) + return; + + it->value->willDestroyPage(page); + if (it->value->isFinished()) + m_browserContextDeletions.remove(it); +} + +void InspectorPlaywrightAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ + m_isConnected = true; +} + +void InspectorPlaywrightAgent::didFailProvisionalLoad(WebPageProxy& page, uint64_t navigationID, const String& error) +{ + if (!m_isConnected) + return; + + m_frontendDispatcher->provisionalLoadFailed(toPageProxyIDProtocolString(page), String::number(navigationID), error); +} + +void InspectorPlaywrightAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ + m_isConnected = false; + m_browserContextDeletions.clear(); +} + +void InspectorPlaywrightAgent::close(Ref&& callback) +{ + Vector pages; + for (auto& pool : WebProcessPool::allProcessPools()) { + for (auto& process : pool->processes()) { + for (auto* page : process->pages()) + pages.append(page); + } + } + for (auto* page : pages) + page->closePage(); + + if (!WebProcessPool::allProcessPools().size()) { + m_client->closeBrowser(); + callback->sendSuccess(); + return; + } + + WebProcessPool::allProcessPools().first()->syncLocalStorage([this, callback = WTFMove(callback)] () { + if (!callback->isActive()) + return; + + m_browserContexts.clear(); + if (m_client == nullptr) { + callback->sendFailure("no platform delegate to close browser"); + } else { + m_client->closeBrowser(); + callback->sendSuccess(); + } + }); + +} + +void InspectorPlaywrightAgent::createContext(ErrorString& errorString, String* browserContextID) +{ + BrowserContext browserContext = m_client->createBrowserContext(errorString); + if (!errorString.isEmpty()) + return; + browserContext.processPool->setPrimaryDataStore(*browserContext.dataStore); + browserContext.processPool->ensureNetworkProcess(browserContext.dataStore.get()); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + *browserContextID = toBrowserContextIDProtocolString(sessionID); + m_browserContexts.set(*browserContextID, browserContext); +} + +void InspectorPlaywrightAgent::deleteContext(const String& browserContextID, Ref&& callback) +{ + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, &browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + Vector pages = browserContext.pages(); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + m_browserContexts.remove(browserContextID); + if (pages.isEmpty()) { + callback->sendSuccess(); + } else { + m_browserContextDeletions.set(sessionID, makeUnique(browserContext, pages.size(), WTFMove(callback))); + for (auto* page : pages) + page->closePage(); + } + m_client->deleteBrowserContext(errorString, sessionID); +} + +void InspectorPlaywrightAgent::createPage(ErrorString& errorString, const String* browserContextID, String* pageProxyID) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + RefPtr page = m_client->createPage(errorString, browserContext); + if (!page) + return; + page->setPermissionsForAutomation(m_permissions.get(browserContextID ? *browserContextID : "")); + *pageProxyID = toPageProxyIDProtocolString(*page); +} + +WebFrameProxy* InspectorPlaywrightAgent::frameForID(const String& frameID, String& error) +{ + size_t dotPos = frameID.find("."); + if (dotPos == notFound) { + error = "Invalid frame id"_s; + return nullptr; + } + + if (!frameID.isAllASCII()) { + error = "Invalid frame id"_s; + return nullptr; + } + + String processIDString = frameID.left(dotPos); + uint64_t pid = strtoull(processIDString.ascii().data(), 0, 10); + auto processID = makeObjectIdentifier(pid); + WebProcessProxy* process = WebProcessProxy::processForIdentifier(processID); + if (!process) { + error = "Cannot find web process for the frame id"_s; + return nullptr; + } + + String frameIDString = frameID.substring(dotPos + 1); + uint64_t frameIDNumber = strtoull(frameIDString.ascii().data(), 0, 10); + auto frameIdentifier = makeObjectIdentifier(frameIDNumber); + WebFrameProxy* frame = process->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) +{ + WebPageProxy* page = m_pageProxyIDMap.findPageProxy(pageProxyID); + if (!page) { + 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() != page) { + callback->sendFailure("Frame with specified is not from the specified page"_s); + return; + } + } + + page->inspectorController().navigate(WTFMove(resourceRequest), frame, [callback = WTFMove(callback)](const String& error, uint64_t navigationID) { + if (!error.isEmpty()) { + callback->sendFailure(error); + return; + } + + Optional navigationIDString; + if (navigationID) + navigationIDString = String::number(navigationID); + callback->sendSuccess(navigationIDString); + }); +} + +void InspectorPlaywrightAgent::setIgnoreCertificateErrors(Inspector::ErrorString& errorString, const String* browserContextID, bool ignore) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + browserContext.processPool->setIgnoreTLSErrors(ignore); +} + +void InspectorPlaywrightAgent::getAllCookies(const String* browserContextID, Ref&& callback) { + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + NetworkProcessProxy* networkProcess = browserContext.processPool->networkProcess(); + networkProcess->sendWithAsyncReply(Messages::NetworkProcess::GetAllCookies(sessionID), + [callback = WTFMove(callback)](Vector allCookies) { + if (!callback->isActive()) + return; + auto cookies = JSON::ArrayOf::create(); + for (const auto& cookie : allCookies) + cookies->addItem(buildObjectForCookie(cookie)); + callback->sendSuccess(WTFMove(cookies)); + }, 0); +} + +void InspectorPlaywrightAgent::setCookies(const String* browserContextID, const JSON::Array& in_cookies, Ref&& callback) { + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + NetworkProcessProxy* networkProcess = browserContext.processPool->networkProcess(); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + + Vector cookies; + for (unsigned i = 0; i < in_cookies.length(); ++i) { + RefPtr item = in_cookies.get(i); + RefPtr obj; + if (!item->asObject(obj)) { + errorString = "Invalid cookie payload format"_s; + return; + } + + WebCore::Cookie cookie; + if (!obj->getString("name", cookie.name) || + !obj->getString("value", cookie.value) || + !obj->getString("domain", cookie.domain) || + !obj->getString("path", cookie.path)) { + errorString = "Invalid file payload format"_s; + return; + } + + double expires; + if (obj->getDouble("expires", expires) && expires != -1) + cookie.expires = expires; + obj->getBoolean("httpOnly", cookie.httpOnly); + obj->getBoolean("secure", cookie.secure); + obj->getBoolean("session", cookie.session); + String sameSite; + if (obj->getString("sameSite", sameSite)) { + if (sameSite == "None") + cookie.sameSite = WebCore::Cookie::SameSitePolicy::None; + if (sameSite == "Lax") + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Lax; + if (sameSite == "Strict") + cookie.sameSite = WebCore::Cookie::SameSitePolicy::Strict; + } + cookies.append(WTFMove(cookie)); + } + + networkProcess->sendWithAsyncReply(Messages::NetworkProcess::SetCookies(sessionID, WTFMove(cookies)), + [callback = WTFMove(callback)](bool success) { + if (!callback->isActive()) + return; + + if (success) + callback->sendSuccess(); + else + callback->sendFailure("Internal error: no network storage"_s); + callback->sendSuccess(); + }, 0); +} + +void InspectorPlaywrightAgent::deleteAllCookies(const String* browserContextID, Ref&& callback) { + String errorString; + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + NetworkProcessProxy* networkProcess = browserContext.processPool->networkProcess(); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + networkProcess->sendWithAsyncReply(Messages::NetworkProcess::DeleteAllCookies(sessionID), + [callback = WTFMove(callback)](bool success) { + if (!callback->isActive()) + return; + if (success) + callback->sendSuccess(); + else + callback->sendFailure("Internal error: no network storage"_s); + }, 0); +} + +void InspectorPlaywrightAgent::grantPermissions(Inspector::ErrorString& errorString, const String* browserContextID, const String& origin, const JSON::Array& values) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + HashSet set; + for (const auto& value : values) { + String name; + if (!value->asString(name)) { + errorString = "Permission must be a string"_s; + return; + } + set.add(name); + } + String key = browserContextID ? *browserContextID : ""; + auto it = m_permissions.add(key, Permissions()).iterator; + it->value.set(origin, WTFMove(set)); + Vector pages; + for (auto& process : browserContext.processPool->processes()) { + for (auto* page : process->pages()) + page->setPermissionsForAutomation(it->value); + } +} + +void InspectorPlaywrightAgent::resetPermissions(Inspector::ErrorString& errorString, const String* browserContextID) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + m_permissions.clear(); + for (auto& process : browserContext.processPool->processes()) { + for (auto* page : process->pages()) + page->setPermissionsForAutomation(HashMap>()); + } +} + +void InspectorPlaywrightAgent::setLanguages(Inspector::ErrorString& errorString, const JSON::Array& languages, const String* browserContextID) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + + Vector items; + for (const auto& value : languages) { + String language; + if (!value->asString(language)) { + errorString = "Language must be a string"_s; + return; + } + items.append(language); + } + + browserContext.processPool->setLanguagesForAutomation(WTFMove(items)); +} + +void InspectorPlaywrightAgent::setGeolocationOverride(Inspector::ErrorString& errorString, const String* browserContextID, const JSON::Object* geolocation) +{ + BrowserContext browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return; + auto* geoManager = browserContext.processPool->supplement(); + if (!geoManager) { + errorString = "Internal error: geolocation manager is not available."; + return; + } + if (geolocation) { + double timestamp = 0; + double latitude = 0; + double longitude = 0; + double accuracy = 0; + if (!geolocation->getDouble("timestamp", timestamp) || + !geolocation->getDouble("latitude", latitude) || + !geolocation->getDouble("longitude", longitude) || + !geolocation->getDouble("accuracy", accuracy)) { + errorString = "Invalid geolocation format"_s; + return; + } + auto position = WebGeolocationPosition::create(WebCore::GeolocationPositionData(timestamp, latitude, longitude, accuracy)); + geoManager->providerDidChangePosition(&position.get()); + } else { + geoManager->providerDidFailToDeterminePosition("Position unavailable"_s); + } +} + +String InspectorPlaywrightAgent::toBrowserContextIDProtocolString(const PAL::SessionID& sessionID) +{ + StringBuilder builder; + builder.append(hex(sessionID.toUInt64(), 16)); + return builder.toString(); +} + +String InspectorPlaywrightAgent::toPageProxyIDProtocolString(const WebPageProxy& page) +{ + return makeString(page.identifier().toUInt64()); +} + +BrowserContext InspectorPlaywrightAgent::lookupBrowserContext(ErrorString& errorString, const String* browserContextID) +{ + if (!browserContextID) { + BrowserContext context; + if (!WebProcessPool::allProcessPools().size()) { + errorString = "Browser started with no default context"_s; + return context; + } + auto* pool = WebProcessPool::allProcessPools().first(); + context.processPool = pool; + context.dataStore = pool->websiteDataStore(); + return context; + } + + BrowserContext browserContext = m_browserContexts.get(*browserContextID); + if (!browserContext.processPool) + errorString = "Could not find browser context for given id"_s; + return browserContext; +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..b908ea9dd75d875e2e26807adef6e4370404e32f --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h @@ -0,0 +1,116 @@ +/* + * 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 +#include +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +class PlaywrightFrontendDispatcher; +} + +namespace PAL { +class SessionID; +} + +namespace WebKit { + +class NetworkProcess; +class WebFrameProxy; +class WebProcessPool; + +class PageProxyIDMap { +public: + virtual WebPageProxy* findPageProxy(const String& pageProxyID) = 0; + +protected: + virtual ~PageProxyIDMap() = default; +}; + +class InspectorPlaywrightAgent final : public Inspector::InspectorAgentBase, public Inspector::PlaywrightBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(InspectorPlaywrightAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorPlaywrightAgent(Inspector::FrontendRouter&, Inspector::BackendDispatcher&, InspectorPlaywrightAgentClient*, PageProxyIDMap&); + ~InspectorPlaywrightAgent() override; + + void didCreateWebPageProxy(const WebPageProxy&); + void willDestroyWebPageProxy(const WebPageProxy&); + void didFailProvisionalLoad(WebPageProxy&, uint64_t navigationID, const String& error); + + // InspectorAgentBase + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + // PlaywrightDispatcherHandler + void close(Ref&&) override; + void createContext(Inspector::ErrorString&, String* browserContextID) override; + void deleteContext(const String& browserContextID, Ref&& callback) override; + void createPage(Inspector::ErrorString&, const String* browserContextID, String* pageProxyID) override; + void navigate(const String& url, const String& pageProxyID, const String* frameId, const String* referrer, Ref&&) override; + void setIgnoreCertificateErrors(Inspector::ErrorString&, const String* browserContextID, bool ignore) override; + + void getAllCookies(const String* browserContextID, Ref&&) override; + void setCookies(const String* browserContextID, const JSON::Array& in_cookies, Ref&&) override; + void deleteAllCookies(const String* browserContextID, Ref&&) override; + + void grantPermissions(Inspector::ErrorString&, const String* browserContextID, const String& origin, const JSON::Array& permissions) override; + void resetPermissions(Inspector::ErrorString&, const String* browserContextID) override; + void setGeolocationOverride(Inspector::ErrorString&, const String* browserContextID, const JSON::Object* geolocation) override; + void setLanguages(Inspector::ErrorString&, const JSON::Array& languages, const String* browserContextID) override; + + static String toBrowserContextIDProtocolString(const PAL::SessionID&); + static String toPageProxyIDProtocolString(const WebPageProxy&); + +private: + class BrowserContextDeletion; + BrowserContext lookupBrowserContext(Inspector::ErrorString&, const String* browserContextID); + WebFrameProxy* frameForID(const String& frameID, String& error); + + std::unique_ptr m_frontendDispatcher; + Ref m_backendDispatcher; + InspectorPlaywrightAgentClient* m_client; + PageProxyIDMap& m_pageProxyIDMap; + using Permissions = HashMap>; + HashMap m_permissions; + HashMap m_browserContexts; + HashMap> m_browserContextDeletions; + bool m_isConnected { 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..d2f02082007b41b9e20dc6bb4751743835d60fce --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h @@ -0,0 +1,56 @@ +/* + * 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 + +namespace WebKit { + +class WebsiteDataStore; +class WebPageProxy; +class WebProcessPool; + +struct BrowserContext { + Vector pages() const; + RefPtr dataStore; + RefPtr processPool; +}; + +class InspectorPlaywrightAgentClient { +public: + virtual ~InspectorPlaywrightAgentClient() = default; + virtual RefPtr createPage(WTF::String& error, const BrowserContext& context) = 0; + virtual void closeBrowser() = 0; + virtual BrowserContext createBrowserContext(WTF::String& error) = 0; + virtual void deleteBrowserContext(WTF::String& error, PAL::SessionID) = 0; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp index 8a871bf2916d5eab86becf5fde0faed79283d88c..a19a429c4d53edf81c3028c7053265e6c22c171a 100644 --- a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp +++ b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp @@ -92,8 +92,11 @@ void ProcessLauncher::launchProcess() 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/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45d8dc48601548951dc5c5ecd68958dbd47c89db --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp @@ -0,0 +1,220 @@ +/* + * 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 "BrowserInspectorController.h" +#include +#include +#include +#include +#include +#include + +#if OS(UNIX) +#include +#include +#endif + +#if PLATFORM(WIN) +#include +#endif + +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")) + { + } + + ~RemoteFrontendChannel() override = default; + + ConnectionType connectionType() const override + { + return ConnectionType::Remote; + } + + void sendMessageToFrontend(const String& message) override + { + m_senderQueue->dispatch([message = message.isolatedCopy()]() { + WriteBytes(message.ascii().data(), message.length()); + WriteBytes("\0", 1); + }); + } + +private: + Ref m_senderQueue; +}; + +RemoteInspectorPipe::RemoteInspectorPipe(BrowserInspectorController& browserInspectorController) + : m_remoteFrontendChannel(makeUnique()) + , m_browserInspectorController(browserInspectorController) +{ + start(); +} + +RemoteInspectorPipe::~RemoteInspectorPipe() +{ + stop(); +} + +bool RemoteInspectorPipe::start() +{ + WTF::RunLoop::initializeMainRunLoop(); + if (m_receiverThread) + return true; + +#if PLATFORM(WIN) + readHandle = reinterpret_cast(_get_osfhandle(readFD)); + writeHandle = reinterpret_cast(_get_osfhandle(writeFD)); +#endif + + m_browserInspectorController.connectFrontend(*m_remoteFrontendChannel); + m_terminated = false; + m_receiverThread = Thread::create("Inspector pipe reader", [this] { + workerRun(); + }); + return true; +} + +void RemoteInspectorPipe::stop() +{ + if (!m_receiverThread) + return; + + m_browserInspectorController.disconnectFrontend(); + + m_terminated = true; + m_receiverThread->waitForCompletion(); + m_receiverThread = nullptr; +} + +void RemoteInspectorPipe::workerRun() +{ + const size_t bufSize = 256 * 1024; + auto buffer = makeUniqueArray(bufSize); + Vector line; + while (!m_terminated) { + size_t size = ReadBytes(buffer.get(), bufSize, false); + if (!size) + break; + size_t start = 0; + size_t end = line.size(); + line.append(buffer.get(), size); + while (true) { + for (; end < line.size(); ++end) { + if (line[end] == '\0') + break; + } + if (end == line.size()) + break; + + if (end > start) { + String message = String::fromUTF8(line.data() + start, end - start); + RunLoop::main().dispatch([this, message] { + if (!m_terminated) + m_browserInspectorController.dispatchMessageFromFrontend(message); + }); + } + ++end; + start = end; + } + if (start != 0 && start < line.size()) + memmove(line.data(), line.data() + start, line.size() - start); + line.shrink(line.size() - start); + } +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.h b/Source/WebKit/UIProcess/RemoteInspectorPipe.h new file mode 100644 index 0000000000000000000000000000000000000000..b1307da8b9ee02d63ef98d276473d65a1d8c3556 --- /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 BrowserInspectorController; + +class RemoteInspectorPipe { + WTF_MAKE_NONCOPYABLE(RemoteInspectorPipe); + WTF_MAKE_FAST_ALLOCATED; +public: + explicit RemoteInspectorPipe(BrowserInspectorController&); + ~RemoteInspectorPipe(); + +private: + class RemoteFrontendChannel; + + bool start(); + void stop(); + + void workerRun(); + + RefPtr m_receiverThread; + std::atomic m_terminated { false }; + std::unique_ptr m_remoteFrontendChannel; + BrowserInspectorController& m_browserInspectorController; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp index 977837517e1708bf2aa551fe64d6a25403cdaaaa..128a241c24cf12bb89af682f93566da2686db76e 100644 --- a/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp +++ b/Source/WebKit/UIProcess/WebAuthentication/AuthenticatorManager.cpp @@ -35,6 +35,7 @@ #include "NfcService.h" #include "WebPageProxy.h" #include "WebPreferencesKeys.h" +#include "WebProcessProxy.h" #include #include #include diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h index dee773c3e132e37b72727f3538714017b1d96cf3..c8273246ed7f7de53ec6b4d4132069450952db29 100644 --- a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h +++ b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h @@ -28,6 +28,7 @@ #if ENABLE(WEB_AUTHN) #include "LocalConnection.h" +#include #include namespace WebKit { diff --git a/Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp b/Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp index 04f3227cd55c992a42cd96a3f25d697aed7965a2..f0d36935f47bab03ea2ec50b705092068ecd3efa 100644 --- a/Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp +++ b/Source/WebKit/UIProcess/WebGeolocationManagerProxy.cpp @@ -128,7 +128,8 @@ void WebGeolocationManagerProxy::startUpdating(IPC::Connection& connection, WebP if (!wasUpdating) { m_provider->setEnableHighAccuracy(*this, isHighAccuracyEnabled()); m_provider->startUpdating(*this); - } else if (m_lastPosition) + } + if (m_lastPosition) connection.send(Messages::WebGeolocationManager::DidChangePosition(m_lastPosition.value()), 0); } diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c863bd49011debe4b06cab64c113810809633777 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp @@ -0,0 +1,124 @@ +/* + * 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, double deviceScaleFactor, bool fixedlayout, 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 + + m_page.setCustomDeviceScaleFactor(deviceScaleFactor); + 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); + }); +} + +void WebPageInspectorEmulationAgent::setJavaScriptEnabled(ErrorString&, bool enabled) +{ + auto copy = m_page.preferences().copy(); + copy->setJavaScriptEnabled(enabled); + m_page.setPreferences(copy); +} + +void WebPageInspectorEmulationAgent::setAuthCredentials(Inspector::ErrorString&, const String* username, const String* password) +{ + if (username && password) + m_page.setAuthCredentialsForAutomation(WebCore::Credential(*username, *password, CredentialPersistencePermanent)); + else + m_page.setAuthCredentialsForAutomation(Optional()); +} + +void WebPageInspectorEmulationAgent::setActiveAndFocused(Inspector::ErrorString&, const bool* active) +{ + Optional value; + if (active) + value = *active; + m_page.setActiveForAutomation(value); +} + +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..61969d8e4598f624df03beb56fc67375b9386edf --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h @@ -0,0 +1,72 @@ +/* + * 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, double deviceScaleFactor, bool fixedlayout, Ref&&) override; + void setJavaScriptEnabled(Inspector::ErrorString&, bool enabled) override; + void setAuthCredentials(Inspector::ErrorString&, const String*, const String*) override; + void setActiveAndFocused(Inspector::ErrorString&, const bool*) 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; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5043224bbd6378175c9ca7dce63fc5a233649878 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp @@ -0,0 +1,253 @@ +/* + * 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 "NativeWebMouseEvent.h" +#include "WebPageProxy.h" +#include + +namespace WebKit { + +using namespace Inspector; + +namespace { + +template +class CallbackList { + WTF_MAKE_FAST_ALLOCATED; +public: + ~CallbackList() + { + for (const auto& callback : m_callbacks) + callback->sendFailure("Page closed"); + } + + void append(Ref&& callback) + { + m_callbacks.append(WTFMove(callback)); + } + + void sendSuccess() + { + for (const auto& callback : m_callbacks) + callback->sendSuccess(); + m_callbacks.clear(); + } + +private: + Vector> m_callbacks; +}; + +} // namespace + +class WebPageInspectorInputAgent::KeyboardCallbacks : public CallbackList { +}; + +class WebPageInspectorInputAgent::MouseCallbacks : 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_mouseCallbacks->sendSuccess(); +} + +void WebPageInspectorInputAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ + m_keyboardCallbacks = makeUnique(); + m_mouseCallbacks = makeUnique(); +} + +void WebPageInspectorInputAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ + m_keyboardCallbacks = nullptr; + m_mouseCallbacks = nullptr; +} + +void WebPageInspectorInputAgent::dispatchKeyEvent(const String& type, const int* modifiers, const String* text, const String* unmodifiedText, const String* code, const String* key, const int* windowsVirtualKeyCode, const int* nativeVirtualKeyCode, const bool* autoRepeat, const bool* isKeypad, const bool* isSystemKey, const JSON::Array* commands, Ref&& callback) +{ + WebKit::WebEvent::Type eventType; + if (type == "keyDown") { + eventType = WebKit::WebEvent::KeyDown; + } else if (type == "keyUp") { + eventType = WebKit::WebEvent::KeyUp; + } else { + callback->sendFailure("Unsupported event type."); + return; + } + OptionSet eventModifiers; + if (modifiers) + eventModifiers = eventModifiers.fromRaw(*modifiers); + String eventText; + if (text) + eventText = *text; + String eventUnmodifiedText; + if (unmodifiedText) + eventUnmodifiedText = *unmodifiedText; + String eventCode; + if (code) + eventCode = *code; + String eventKey; + if (key) + eventKey = *key; + 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"); + return; + } + eventCommands.append(command); + } + } + + 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(); + + m_keyboardCallbacks->append(WTFMove(callback)); + platformDispatchKeyEvent( + eventType, + eventText, + eventUnmodifiedText, + eventKey, + eventCode, + eventWindowsVirtualKeyCode, + eventNativeVirtualKeyCode, + eventIsAutoRepeat, + eventIsKeypad, + eventIsSystemKey, + eventModifiers, + eventCommands, + timestamp); +} + +void WebPageInspectorInputAgent::dispatchMouseEvent(const String& type, int x, int y, const int* modifiers, const String* button, const int* buttons, const int* clickCount, const int* deltaX, const int* deltaY, Ref&& callback) +{ + WebEvent::Type eventType = WebEvent::NoType; + if (type == "down") + eventType = WebEvent::MouseDown; + else if (type == "up") + eventType = WebEvent::MouseUp; + else if (type == "move") + eventType = WebEvent::MouseMove; + else { + callback->sendFailure("Unsupported event type"); + return; + } + + OptionSet eventModifiers; + if (modifiers) + eventModifiers = eventModifiers.fromRaw(*modifiers); + + WebMouseEvent::Button eventButton = WebMouseEvent::NoButton; + if (button) { + if (*button == "left") + eventButton = WebMouseEvent::LeftButton; + else if (*button == "middle") + eventButton = WebMouseEvent::MiddleButton; + else if (*button == "right") + eventButton = WebMouseEvent::RightButton; + else if (*button == "none") + eventButton = WebMouseEvent::NoButton; + else { + callback->sendFailure("Unsupported eventButton"); + 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(); + x = clampToInteger(roundf(x * totalScale)); + y = clampToInteger(roundf(y * totalScale)); + eventDeltaX = clampToInteger(roundf(eventDeltaX * totalScale)); + eventDeltaY = clampToInteger(roundf(eventDeltaY * totalScale)); + +#if PLATFORM(MAC) + platformDispatchMouseEvent(type, x, y, modifiers, button, clickCount); +#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 +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..76290475097e756e3d932d22be4d8c797be4aa0c --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h @@ -0,0 +1,84 @@ +/* + * 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 + +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 didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + // Protocol handler + void dispatchKeyEvent(const String& type, const int* modifiers, const String* text, const String* unmodifiedText, const String* code, const String* key, const int* windowsVirtualKeyCode, const int* nativeVirtualKeyCode, const bool* autoRepeat, const bool* isKeypad, const bool* isSystemKey, const JSON::Array*, Ref&& callback) override; + void dispatchMouseEvent(const String& type, int x, int y, const int* modifiers, const String* button, const int* buttons, const int* clickCount, const int* deltaX, const int* deltaY, Ref&& callback) override; + +private: + void platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& commands, WallTime timestamp); +#if PLATFORM(WPE) + void platformDispatchMouseEvent(WebMouseEvent::Type type, int x, int y, WebMouseEvent::Button button, OptionSet modifiers); +#endif +#if PLATFORM(MAC) + void platformDispatchMouseEvent(const String& type, int x, int y, const int* modifier, const String* button, const int* clickCount); +#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; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp index 509faa03b0bf0c76ef0b74e7a503a3e537c42937..3eaa2499a962cc5921618ea35234668633d6ef57 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -930,6 +930,7 @@ void WebPageProxy::finishAttachingToWebProcess(ProcessLaunchReason reason) m_pageLoadState.didSwapWebProcesses(); if (reason != ProcessLaunchReason::InitialProcess) m_drawingArea->waitForBackingStoreUpdateOnNextPaint(); + m_inspectorController->didFinishAttachingToWebProcess(); } void WebPageProxy::didAttachToRunningProcess() @@ -1269,6 +1270,21 @@ WebProcessProxy& WebPageProxy::ensureRunningProcess() return m_process; } +RefPtr WebPageProxy::loadRequestForInspector(WebCore::ResourceRequest&& request, WebFrameProxy* frame) +{ + if (!frame || frame == mainFrame()) + return loadRequest(WTFMove(request), WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow); + + auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request), m_backForwardList->currentItem()); + LoadParameters loadParameters; + loadParameters.navigationID = navigation->navigationID(); + loadParameters.request = WTFMove(request); + loadParameters.shouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow; + loadParameters.shouldTreatAsContinuingLoad = false; + m_process->send(Messages::WebPage::LoadRequestInFrameForInspector(loadParameters, frame->frameID()), m_webPageID); + return navigation; +} + RefPtr WebPageProxy::loadRequest(ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData) { if (m_isClosed) @@ -1722,6 +1738,31 @@ void WebPageProxy::setControlledByAutomation(bool controlled) m_process->processPool().sendToNetworkingProcess(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation)); } +void WebPageProxy::setAuthCredentialsForAutomation(Optional&& credentials) +{ + m_credentialsForAutomation = WTFMove(credentials); +} + +void WebPageProxy::setPermissionsForAutomation(const HashMap>& permissions) +{ + m_permissionsForAutomation = permissions; +} + +void WebPageProxy::setActiveForAutomation(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) +{ + fprintf(stderr, "RENDERER: %s\n", str.utf8().data()); +} + void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { MESSAGE_CHECK(m_process, !targetId.isEmpty()); @@ -1864,6 +1905,25 @@ void WebPageProxy::updateActivityState(OptionSet flagsToUpd { bool wasVisible = isViewVisible(); m_activityState.remove(flagsToUpdate); + + + if (m_activeForAutomation) { + if (*m_activeForAutomation) { + if (flagsToUpdate & ActivityState::IsFocused) + m_activityState.add(ActivityState::IsFocused); + if (flagsToUpdate & ActivityState::WindowIsActive) + m_activityState.add(ActivityState::WindowIsActive); + if (flagsToUpdate & ActivityState::IsVisible) + m_activityState.add(ActivityState::IsVisible); + if (flagsToUpdate & ActivityState::IsVisibleOrOccluded) + m_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()) m_activityState.add(ActivityState::IsFocused); if (flagsToUpdate & ActivityState::WindowIsActive && pageClient().isViewWindowActive()) @@ -2810,7 +2870,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) const EventNames& names = eventNames(); for (auto& touchPoint : touchStartEvent.touchPoints()) { IntPoint location = touchPoint.location(); @@ -2843,7 +2903,7 @@ void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent m_touchAndPointerEventTracking.touchStartTracking = TrackingType::Synchronous; m_touchAndPointerEventTracking.touchMoveTracking = TrackingType::Synchronous; m_touchAndPointerEventTracking.touchEndTracking = TrackingType::Synchronous; -#endif // ENABLE(ASYNC_SCROLLING) +#endif // ENABLE(ASYNC_SCROLLING) && PLATFORM(IOS_FAMILY) } TrackingType WebPageProxy::touchEventTrackingType(const WebTouchEvent& touchStartEvent) const @@ -3207,6 +3267,7 @@ void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, A void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, Optional&& websitePolicies, Ref&& sender, WillContinueLoadInNewProcess willContinueLoadInNewProcess) { + m_inspectorController->didReceivePolicyDecision(action, navigation ? navigation->navigationID() : 0); if (!hasRunningProcess()) { sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), hasNavigatedAwayFromAppBoundDomain(), PolicyAction::Ignore, 0, DownloadID(), WTF::nullopt }); return; @@ -3891,6 +3952,11 @@ void WebPageProxy::pageScaleFactorDidChange(double scaleFactor) m_pageScaleFactor = scaleFactor; } +void WebPageProxy::viewScaleFactorDidChange(double scaleFactor) +{ + m_viewScaleFactor = scaleFactor; +} + void WebPageProxy::pluginScaleFactorDidChange(double pluginScaleFactor) { m_pluginScaleFactor = pluginScaleFactor; @@ -4310,6 +4376,7 @@ void WebPageProxy::didDestroyNavigation(uint64_t navigationID) // FIXME: Message check the navigationID. m_navigationState->didDestroyNavigation(navigationID); + m_inspectorController->didDestroyNavigation(navigationID); } void WebPageProxy::didStartProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData) @@ -4529,6 +4596,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; @@ -4971,7 +5040,14 @@ void WebPageProxy::decidePolicyForNavigationActionAsync(FrameIdentifier frameID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, Optional originatingPageID, const WebCore::ResourceRequest& originalRequest, WebCore::ResourceRequest&& request, IPC::FormDataReference&& requestBody, WebCore::ResourceResponse&& redirectResponse, const UserData& userData, uint64_t listenerID) { - decidePolicyForNavigationActionAsyncShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, listenerID); + if (m_inspectorController->shouldPauseLoading()) { + m_inspectorController->setContinueLoadingCallback([this, protectedThis = makeRef(*this), frameID, frameInfo = WTFMove(frameInfo), identifier, navigationID, navigationActionData = WTFMove(navigationActionData), + originatingFrameInfo = WTFMove(originatingFrameInfo), originatingPageID, originalRequest, request = WTFMove(request), requestBody = WTFMove(requestBody), redirectResponse = WTFMove(redirectResponse), userData, listenerID] () mutable { + decidePolicyForNavigationActionAsyncShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, listenerID); + }); + } else { + decidePolicyForNavigationActionAsyncShared(m_process.copyRef(), m_webPageID, frameID, WTFMove(frameInfo), identifier, navigationID, WTFMove(navigationActionData), WTFMove(originatingFrameInfo), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, listenerID); + } } void WebPageProxy::decidePolicyForNavigationActionAsyncShared(Ref&& process, PageIdentifier webPageID, FrameIdentifier frameID, FrameInfoData&& frameInfo, @@ -5490,6 +5566,7 @@ void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, Optio void WebPageProxy::showPage() { m_uiClient->showPage(this); + m_inspectorController->didShowPage(); } void WebPageProxy::exitFullscreenImmediately() @@ -5546,6 +5623,8 @@ void WebPageProxy::runJavaScriptAlert(FrameIdentifier frameID, FrameInfoData&& f if (auto* automationSession = process().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("alert"_s, message); m_uiClient->runJavaScriptAlert(*this, message, frame, WTFMove(frameInfo), WTFMove(reply)); } @@ -5565,6 +5644,8 @@ void WebPageProxy::runJavaScriptConfirm(FrameIdentifier frameID, FrameInfoData&& if (auto* automationSession = process().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("confirm"_s, message); m_uiClient->runJavaScriptConfirm(*this, message, frame, WTFMove(frameInfo), WTFMove(reply)); } @@ -5584,6 +5665,8 @@ void WebPageProxy::runJavaScriptPrompt(FrameIdentifier frameID, FrameInfoData&& if (auto* automationSession = process().processPool().automationSession()) automationSession->willShowJavaScriptDialog(*this); } + if (m_inspectorDialogAgent) + m_inspectorDialogAgent->javascriptDialogOpening("prompt"_s, message, &defaultValue); m_uiClient->runJavaScriptPrompt(*this, message, defaultValue, frame, WTFMove(frameInfo), WTFMove(reply)); } @@ -5743,6 +5826,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(FrameIdentifier frameID, FrameInf 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. m_process->stopResponsivenessTimer(); @@ -6805,6 +6890,7 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) if (auto* automationSession = process().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); didFinishProcessingAllPendingMouseEvents(); + m_inspectorController->didProcessAllPendingMouseEvents(); } break; @@ -6831,7 +6917,6 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) case WebEvent::RawKeyDown: case WebEvent::Char: { LOG(KeyHandling, "WebPageProxy::didReceiveEvent: %s (queue empty %d)", webKeyboardEventTypeString(type), m_keyEventQueue.isEmpty()); - MESSAGE_CHECK(m_process, !m_keyEventQueue.isEmpty()); NativeWebKeyboardEvent event = m_keyEventQueue.takeFirst(); @@ -6851,7 +6936,6 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) // The call to doneWithKeyEvent may close this WebPage. // Protect against this being destroyed. Ref protect(*this); - pageClient().doneWithKeyEvent(event, handled); if (!handled) m_uiClient->didNotHandleKeyEvent(this, event); @@ -6860,6 +6944,7 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) if (!canProcessMoreKeyEvents) { if (auto* automationSession = process().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); + m_inspectorController->didProcessAllPendingKeyboardEvents(); } break; } @@ -7317,8 +7402,10 @@ static bool shouldReloadAfterProcessTermination(ProcessTerminationReason reason) void WebPageProxy::dispatchProcessDidTerminate(ProcessTerminationReason reason) { RELEASE_LOG_IF_ALLOWED(Loading, "dispatchProcessDidTerminate: reason = %d", reason); + bool handledByClient = m_inspectorController->pageCrashed(reason); + if (handledByClient) + return; - bool handledByClient = false; if (m_loaderClient) handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); else @@ -7600,6 +7687,7 @@ void WebPageProxy::resetStateAfterProcessExited(ProcessTerminationReason termina WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& process, DrawingAreaProxy& drawingArea) { + WebPageCreationParameters parameters; parameters.processDisplayName = configuration().processDisplayName(); @@ -7734,6 +7822,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc parameters.shouldRenderCanvasInGPUProcess = preferences().renderCanvasInGPUProcessEnabled(); parameters.shouldCaptureDisplayInUIProcess = m_process->processPool().configuration().shouldCaptureDisplayInUIProcess(); + parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseLoading(); + #if PLATFORM(GTK) parameters.themeName = pageClient().themeName(); #endif @@ -7797,6 +7887,14 @@ void WebPageProxy::gamepadActivity(const Vector& gamepadDatas, bool void WebPageProxy::didReceiveAuthenticationChallengeProxy(Ref&& authenticationChallenge, NegotiatedLegacyTLS negotiatedLegacyTLS) { + if (m_credentialsForAutomation.hasValue()) { + if (m_credentialsForAutomation->isEmpty() || authenticationChallenge->core().previousFailureCount()) { + 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 = makeRef(*this), authenticationChallenge = authenticationChallenge.copyRef()] (bool shouldAllowLegacyTLS) { if (shouldAllowLegacyTLS) @@ -7877,7 +7975,8 @@ void WebPageProxy::requestGeolocationPermissionForFrame(uint64_t geolocationID, MESSAGE_CHECK(m_process, frame); // FIXME: Geolocation should probably be using toString() as its string representation instead of databaseIdentifier(). - auto origin = API::SecurityOrigin::create(frameInfo.securityOrigin.securityOrigin()); + auto securityOrigin = frameInfo.securityOrigin.securityOrigin(); + auto origin = API::SecurityOrigin::create(securityOrigin); auto request = m_geolocationPermissionRequestManager.createRequest(geolocationID); Function completionHandler = [request = WTFMove(request)](bool allowed) { if (allowed) @@ -7886,6 +7985,14 @@ void WebPageProxy::requestGeolocationPermissionForFrame(uint64_t geolocationID, request->deny(); }; + auto permissions = m_permissionsForAutomation.find(securityOrigin->toString()); + if (permissions == m_permissionsForAutomation.end()) + permissions = m_permissionsForAutomation.find("*"); + if (permissions != m_permissionsForAutomation.end()) { + completionHandler(permissions->value.contains("geolocation")); + 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 diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h index c7b6ec487a66bc92b2eb7f58d86c95646cadbfc4..9a444263299a0a5d26cbabed1a7e961866d2bb60 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -36,6 +36,7 @@ #include "FocusedElementInformation.h" #include "GeolocationPermissionRequestManagerProxy.h" #include "HiddenPageThrottlingAutoIncreasesCounter.h" +#include "InspectorDialogAgent.h" #include "LayerTreeContext.h" #include "MessageSender.h" #include "NotificationPermissionRequestManagerProxy.h" @@ -495,6 +496,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(); @@ -566,6 +569,11 @@ public: void setPageLoadStateObserver(std::unique_ptr&&); + void setAuthCredentialsForAutomation(Optional&&); + void setPermissionsForAutomation(const HashMap>&); + void setActiveForAutomation(Optional active); + void logToStderr(const String& str); + void initializeWebPage(); void setDrawingArea(std::unique_ptr&&); @@ -591,6 +599,7 @@ public: void closePage(); void addPlatformLoadParameters(LoadParameters&); + RefPtr loadRequestForInspector(WebCore::ResourceRequest&&, WebFrameProxy*); RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, API::Object* userData = nullptr); RefPtr loadFile(const String& fileURL, const String& resourceDirectoryURL, API::Object* userData = nullptr); RefPtr loadData(const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData = nullptr, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow); @@ -1071,6 +1080,7 @@ public: #endif void pageScaleFactorDidChange(double); + void viewScaleFactorDidChange(double); void pluginScaleFactorDidChange(double); void pluginZoomFactorDidChange(double); @@ -2328,6 +2338,7 @@ private: String m_overrideContentSecurityPolicy; RefPtr m_inspector; + InspectorDialogAgent* m_inspectorDialogAgent { nullptr }; #if ENABLE(FULLSCREEN_API) std::unique_ptr m_fullScreenManager; @@ -2748,6 +2759,9 @@ private: RefPtr messageBody; }; Vector m_pendingInjectedBundleMessages; + Optional m_credentialsForAutomation; + HashMap> m_permissionsForAutomation; + Optional m_activeForAutomation; #if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION) std::unique_ptr m_webDeviceOrientationUpdateProviderProxy; diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in index 94424d022edea92789d847ed2b18b58c2e9ac67f..9041c45c0bcca77cf2fa26f79318564e24204a12 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.messages.in +++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in @@ -29,6 +29,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, uint32_t modifiers, WebKit::UserData userData) + LogToStderr(String text) #if ENABLE(NETSCAPE_PLUGIN_API) UnavailablePluginButtonClicked(uint32_t pluginUnavailabilityReason, String mimeType, String pluginURLString, String pluginspageAttributeURLString, String frameURLString, String pageURLString) @@ -209,6 +210,7 @@ messages -> WebPageProxy { FindStringCallback(bool found, WebKit::CallbackID callbackID) PageScaleFactorDidChange(double scaleFactor) + ViewScaleFactorDidChange(double scaleFactor) PluginScaleFactorDidChange(double zoomFactor) PluginZoomFactorDidChange(double zoomFactor) diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp index ceef0483bc0201a00950450424144b9a906afec8..2796423306d03190888369901cee7391a860ba95 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.cpp +++ b/Source/WebKit/UIProcess/WebProcessPool.cpp @@ -432,12 +432,19 @@ void WebProcessPool::languageChanged(void* context) static_cast(context)->languageChanged(); } +void WebProcessPool::setLanguagesForAutomation(Vector&& languages) +{ + m_languagesForAutomation = WTFMove(languages); + languageChanged(); +} + void WebProcessPool::languageChanged() { - sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(userPreferredLanguages())); + const Vector& languages = m_languagesForAutomation.size() ? m_languagesForAutomation : userPreferredLanguages(); + sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(languages)); #if USE(SOUP) if (m_networkProcess) - m_networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(userPreferredLanguages()), 0); + m_networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(languages), 0); #endif } @@ -991,7 +998,10 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa #endif parameters.cacheModel = LegacyGlobalSettings::singleton().cacheModel(); - parameters.languages = configuration().overrideLanguages().isEmpty() ? userPreferredLanguages() : configuration().overrideLanguages(); + if (m_languagesForAutomation.size()) + parameters.languages = m_languagesForAutomation; + else + parameters.languages = configuration().overrideLanguages().isEmpty() ? userPreferredLanguages() : configuration().overrideLanguages(); parameters.urlSchemesRegisteredAsEmptyDocument = copyToVector(m_schemesToRegisterAsEmptyDocument); parameters.urlSchemesRegisteredAsSecure = copyToVector(LegacyGlobalSettings::singleton().schemesToRegisterAsSecure()); diff --git a/Source/WebKit/UIProcess/WebProcessPool.h b/Source/WebKit/UIProcess/WebProcessPool.h index d5b9c2637cda626b075e87484ba764a0b965372d..24d7c16c5afba982ddf5cf1cdf96d75ead64df9f 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.h +++ b/Source/WebKit/UIProcess/WebProcessPool.h @@ -417,7 +417,7 @@ public: void windowServerConnectionStateChanged(); -#if USE(SOUP) +#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN) void setIgnoreTLSErrors(bool); bool ignoreTLSErrors() const { return m_ignoreTLSErrors; } #endif @@ -538,6 +538,8 @@ public: PlugInAutoStartProvider& plugInAutoStartProvider() { return m_plugInAutoStartProvider; } + void setLanguagesForAutomation(Vector&&); + void setUseSeparateServiceWorkerProcess(bool); bool useSeparateServiceWorkerProcess() const { return m_useSeparateServiceWorkerProcess; } @@ -650,6 +652,7 @@ private: std::unique_ptr m_customProtocolManagerClient; RefPtr m_automationSession; + Vector m_languagesForAutomation; #if ENABLE(NETSCAPE_PLUGIN_API) PluginInfoStore m_pluginInfoStore; @@ -719,8 +722,8 @@ private: HashMap> m_dictionaryCallbacks; HashMap> m_statisticsRequests; -#if USE(SOUP) - bool m_ignoreTLSErrors { true }; +#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN) + bool m_ignoreTLSErrors { false }; #endif bool m_memoryCacheDisabled { false }; diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp index 7ba39332bce6e28f0f4b2f7acf636f835c54f486..7c3d8125df147b6049075491b12cce1dc84bf514 100644 --- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp +++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp @@ -60,6 +60,8 @@ void GeoclueGeolocationProvider::start(UpdateNotifyFunction&& updateNotifyFuncti m_isRunning = true; m_cancellable = adoptGRef(g_cancellable_new()); if (!m_manager) { + g_cancellable_cancel(m_cancellable_start.get()); + m_cancellable_start = adoptGRef(g_cancellable_new()); g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, nullptr, "org.freedesktop.GeoClue2", "/org/freedesktop/GeoClue2/Manager", "org.freedesktop.GeoClue2.Manager", m_cancellable.get(), [](GObject*, GAsyncResult* result, gpointer userData) { @@ -91,6 +93,12 @@ void GeoclueGeolocationProvider::stop() g_cancellable_cancel(m_cancellable.get()); m_cancellable = nullptr; stopClient(); + 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; destroyManagerLater(); } @@ -153,6 +161,8 @@ void GeoclueGeolocationProvider::createClient(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 31d29091985f34a65134a2b0e7cb3ace1dae441d..571ceac8a4b291fa6e91eb8b17065c0aba908ac3 100644 --- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h +++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h @@ -71,6 +71,9 @@ private: GRefPtr m_manager; GRefPtr m_client; GRefPtr m_cancellable; + GRefPtr m_cancellable_start; + GRefPtr m_cancellable_setup; + GRefPtr m_cancellable_create; UpdateNotifyFunction m_updateNotifyFunction; RunLoop::Timer m_destroyManagerLaterTimer; }; diff --git a/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c16ef9d7c0ba6b4aca36b0aad68296505dbacb50 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp @@ -0,0 +1,115 @@ +/* + * 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 "WebKitBrowserInspectorPrivate.h" +#include "WebKitWebContextPrivate.h" +#include "WebKitWebsiteDataManagerPrivate.h" +#include "WebKitWebViewPrivate.h" +#include "WebPageProxy.h" +#include +#include +#include +#include + +namespace WebKit { + +InspectorPlaywrightAgentClientGlib::InspectorPlaywrightAgentClientGlib(GMainLoop* mainLoop) + : m_mainLoop(mainLoop) +{ +} + +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"; + return nullptr; + } + + RefPtr page = webkitBrowserInspectorCreateNewPageInContext(context); + if (page == nullptr) { + error = "Failed to create new page in the context"; + return nullptr; + } + + if (context == nullptr && sessionID != page->sessionID()) { + ASSERT_NOT_REACHED(); + error = " Failed to create new page in default context"; + return nullptr; + } + + return page; +} + +void InspectorPlaywrightAgentClientGlib::closeBrowser() +{ + m_idToContext.clear(); +#if PLATFORM(GTK) + gtk_main_quit(); +#else + if (m_mainLoop) + g_main_loop_quit(m_mainLoop); +#endif +} + +static PAL::SessionID sessionIDFromContext(WebKitWebContext* context) +{ + WebKitWebsiteDataManager* data_manager = webkit_web_context_get_website_data_manager(context); + WebsiteDataStore& websiteDataStore = webkitWebsiteDataManagerGetDataStore(data_manager); + return websiteDataStore.sessionID(); +} + +BrowserContext InspectorPlaywrightAgentClientGlib::createBrowserContext(WTF::String& error) +{ + BrowserContext browserContext; + GRefPtr data_manager = adoptGRef(webkit_website_data_manager_new_ephemeral()); + GRefPtr context = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", data_manager.get(), "process-swap-on-cross-site-navigation-enabled", true, nullptr))); + if (!context) { + error = "Failed to create GLib ephemeral context"; + return browserContext; + } + browserContext.processPool = &webkitWebContextGetProcessPool(context.get()); + browserContext.dataStore = &webkitWebsiteDataManagerGetDataStore(data_manager.get()); + PAL::SessionID sessionID = sessionIDFromContext(context.get()); + m_idToContext.set(sessionID, WTFMove(context)); + return browserContext; +} + +void InspectorPlaywrightAgentClientGlib::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + m_idToContext.remove(sessionID); +} + +} // 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..4cba2671042d3517e4b8f66e7b2bb780d57aa402 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h @@ -0,0 +1,59 @@ +/* + * 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 "WebKitWebContext.h" +#include +#include +#include +#include + +namespace WebKit { + +class InspectorPlaywrightAgentClientGlib : public InspectorPlaywrightAgentClient { + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorPlaywrightAgentClientGlib(GMainLoop* mainLoop); + ~InspectorPlaywrightAgentClientGlib() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + BrowserContext createBrowserContext(WTF::String& error) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + WebKitWebContext* findContext(WTF::String& error, PAL::SessionID); + + HashMap> m_idToContext; + GMainLoop* m_mainLoop; +}; + +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a86cc348bc210b71bb463dcb3057f575ad7c1d3 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorTargetProxy.h" + +#include "WebPageProxy.h" +#include +#include + +namespace WebKit { + +void InspectorTargetProxy::platformActivate(String& error) const +{ + GtkWidget* parent = gtk_widget_get_toplevel(m_page.viewWidget()); + if (WebCore::widgetIsOnscreenToplevelWindow(parent)) + gtk_window_present(GTK_WINDOW(parent)); + else + error = "The view is not on screen"; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5e25acebabb76a05a77db02a99f1267bd99a3af --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp @@ -0,0 +1,69 @@ +/* + * 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 { +void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function&& callback) +{ + 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 (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())) { + drawingArea->waitForSizeUpdate([callback = WTFMove(callback)]() { + callback(String()); + }); + } else { + callback("No backing store for window"_s); + } + gtk_window_resize(GTK_WINDOW(window), width, height); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ad3fe416c5c747eaad8c6948c3549a3984223ea --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp @@ -0,0 +1,107 @@ +/* + * 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 Vector commandsForKeyEvent(GdkEventType type, unsigned keyVal, unsigned state) +{ + ASSERT(type == GDK_KEY_PRESS || type == GDK_KEY_RELEASE); + + GUniquePtr event(gdk_event_new(type)); + event->key.keyval = keyVal; + event->key.time = GDK_CURRENT_TIME; + event->key.state = state; + // When synthesizing an event, an invalid hardware_keycode value can cause it to be badly processed by GTK+. + GUniqueOutPtr keys; + int keysCount; + if (gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyVal, &keys.outPtr(), &keysCount) && keysCount) + event->key.hardware_keycode = keys.get()[0].keycode; + return KeyBindingTranslator().commandsForKeyEvent(&event->key); +} + +static unsigned modifiersToEventState(OptionSet modifiers) +{ + unsigned state = 0; + if (modifiers.contains(WebEvent::Modifier::ControlKey)) + state |= GDK_CONTROL_MASK; + if (modifiers.contains(WebEvent::Modifier::ShiftKey)) + state |= GDK_SHIFT_MASK; + if (modifiers.contains(WebEvent::Modifier::AltKey)) + state |= GDK_META_MASK; + if (modifiers.contains(WebEvent::Modifier::CapsLockKey)) + state |= GDK_LOCK_MASK; + return state; +} + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& macCommands, WallTime timestamp) +{ + Vector commands; + const guint keyVal = WebCore::PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(windowsVirtualKeyCode); + String keyIdentifier; + if (keyVal) { + GdkEventType event = GDK_NOTHING; + switch (type) + { + case WebKeyboardEvent::KeyDown: + event = GDK_KEY_PRESS; + break; + case WebKeyboardEvent::KeyUp: + event = GDK_KEY_RELEASE; + break; + default: + fprintf(stderr, "Unsupported event type = %d\n", type); + break; + } + unsigned state = modifiersToEventState(modifiers); + commands = commandsForKeyEvent(event, keyVal, state); + keyIdentifier = WebCore::PlatformKeyboardEvent::keyIdentifierForGdkKeyCode(keyVal); + } + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp, + WTFMove(commands)); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm index 8754183edc70b3a341a6584eaf277af1bb1fb4db..34296c8f37dc1914debe00c251db405957fdaccf 100644 --- a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm +++ b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm @@ -459,6 +459,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { + if (!event.nativeEvent()) + return; [m_contentView _didHandleKeyEvent:event.nativeEvent() eventWasHandled:eventWasHandled]; } diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h new file mode 100644 index 0000000000000000000000000000000000000000..b75c2ce5ce9e9da3a33bca41ab548ec7a2f819ed --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h @@ -0,0 +1,51 @@ +/* + * 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); + ~InspectorPlaywrightAgentClientMac() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + BrowserContext createBrowserContext(WTF::String& error) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + _WKBrowserInspectorDelegate* delegate_; +}; + + +} // namespace API diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..5db92c0580fd4f216ac86ede56eaac2eabec27da --- /dev/null +++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm @@ -0,0 +1,77 @@ +/* + * 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 +#import +#import "WebPageProxy.h" +#import "WebProcessPool.h" +#import "WebsiteDataStore.h" +#import "_WKBrowserInspector.h" +#import "WKProcessPoolInternal.h" +#import "WKWebsiteDataStoreInternal.h" +#import "WKWebView.h" +#import "WKWebViewInternal.h" + +namespace WebKit { + +InspectorPlaywrightAgentClientMac::InspectorPlaywrightAgentClientMac(_WKBrowserInspectorDelegate* delegate) + : delegate_(delegate) +{ +} + +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]; +} + +BrowserContext InspectorPlaywrightAgentClientMac::createBrowserContext(WTF::String& error) +{ + _WKBrowserContext* wkBrowserContext = [[delegate_ createBrowserContext] autorelease]; + BrowserContext browserContext; + browserContext.processPool = &static_cast([[wkBrowserContext processPool] _apiObject]); + browserContext.dataStore = &static_cast([[wkBrowserContext dataStore] _apiObject]); + return browserContext; +} + +void InspectorPlaywrightAgentClientMac::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + [delegate_ deleteBrowserContext:sessionID.toUInt64()]; +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..721826c8c98fc85b68a4f45deaee69c1219a7254 --- /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 f0cc38a489474fb9e964fefc91e837f6266d2c04..71caf1fd10757a34aa9ef21d88d7326a66bb3a47 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.h +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.h @@ -53,6 +53,8 @@ class PageClientImpl final : public PageClientImplCocoa #endif { public: + static void setHeadless(bool headless); + PageClientImpl(NSView *, WKWebView *); virtual ~PageClientImpl(); @@ -204,6 +206,10 @@ private: void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame) 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 03192d76aefb19cac18fdd5c4c6de50a2f2585c5..02ea60cb127f68fc073e417856c8c3248df3397c 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm @@ -78,6 +78,7 @@ #import #import #import +#import #import #import #import @@ -103,6 +104,13 @@ namespace WebKit { using namespace WebCore; +static bool _headless = false; + +// static +void PageClientImpl::setHeadless(bool headless) { + _headless = true; +} + PageClientImpl::PageClientImpl(NSView *view, WKWebView *webView) : PageClientImplCocoa(webView) , m_view(view) @@ -156,6 +164,9 @@ NSWindow *PageClientImpl::activeWindow() const bool PageClientImpl::isViewWindowActive() { + if (_headless) + return true; + ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer)); NSWindow *activeViewWindow = activeWindow(); return activeViewWindow.isKeyWindow || [NSApp keyWindow] == activeViewWindow; @@ -163,6 +174,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) @@ -186,6 +200,9 @@ void PageClientImpl::makeFirstResponder() bool PageClientImpl::isViewVisible() { + if (_headless) + return true; + NSView *activeView = this->activeView(); NSWindow *activeViewWindow = activeWindow(); @@ -269,7 +286,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) @@ -447,6 +465,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); } @@ -738,6 +758,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); @@ -904,6 +931,9 @@ void PageClientImpl::didRestoreScrollPosition() bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event) { + // Simulated event. + if (!event.nativeEvent()) + return false; return m_impl->windowIsFrontWindowUnderMouse(event.nativeEvent()); } diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm new file mode 100644 index 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..30e6ae3bdc8c1695189885afae949071add54c4e --- /dev/null +++ b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm @@ -0,0 +1,124 @@ +/* + * 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 "WebPageInspectorInputAgent.h" +#import "WebPageProxy.h" +#import +#import +#import "NativeWebKeyboardEvent.h" +#import + +namespace WebKit { + +using namespace WebCore; + +void WebPageInspectorInputAgent::platformDispatchMouseEvent(const String& type, int x, int y, const int* optionalModifiers, const String* button, const int* optionalClickCount) { + 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)0; + NSEventType dragEventType = (NSEventType)0; + NSEventType upEventType = (NSEventType)0; + + if (!button || *button == "none") { + downEventType = NSEventTypeMouseMoved; + dragEventType = NSEventTypeMouseMoved; + upEventType = NSEventTypeMouseMoved; + } else if (*button == "left") { + downEventType = NSEventTypeLeftMouseDown; + dragEventType = NSEventTypeLeftMouseDragged; + upEventType = NSEventTypeLeftMouseUp; + } else if (*button == "middle") { + downEventType = NSEventTypeOtherMouseDown; + dragEventType = NSEventTypeLeftMouseDragged; + upEventType = NSEventTypeOtherMouseUp; + } else if (*button == "right") { + downEventType = NSEventTypeRightMouseDown; + upEventType = NSEventTypeRightMouseUp; + } + + NSInteger eventNumber = 0; + + NSEvent* event = nil; + if (type == "move") { + 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") { + 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") { + event = [NSEvent mouseEventWithType:upEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:0.0f]; + } + + if (event) { + NativeWebMouseEvent nativeEvent(event, nil, [window contentView]); + m_page.handleMouseEvent(nativeEvent); + } +} + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& commands, WallTime timestamp) +{ + String keyIdentifier = key.length() == 1 ? makeString("U+", hex(toASCIIUpper(key.characterAt(0)), 4)) : key; + Vector macCommands; + for (const String& command : commands) + macCommands.append(WebCore::KeypressCommand(command.utf8().data())); + if (text.length() > 0 && macCommands.size() == 0) + macCommands.append(WebCore::KeypressCommand("insertText:", text)); + 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/win/InspectorPlaywrightAgentClientWin.cpp b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..544442b75afcba6e121ab202ad32dcdfaf923e2e --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp @@ -0,0 +1,83 @@ +/* + * 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 + +namespace WebKit { + +InspectorPlaywrightAgentClientWin::InspectorPlaywrightAgentClientWin(CreatePageCallback createPage, QuitCallback quit) + : m_createPage(createPage) + , m_quit(quit) +{ +} + +RefPtr InspectorPlaywrightAgentClientWin::createPage(WTF::String& error, const BrowserContext& context) +{ + auto conf = API::PageConfiguration::create(); + auto prefs = WebPreferences::create(String(), "WebKit2Automation.", "WebKit2Automation."); + conf->setProcessPool(context.processPool.get()); + conf->setWebsiteDataStore(context.dataStore.get()); + return toImpl(m_createPage(toAPI(&conf.get()))); +} + +void InspectorPlaywrightAgentClientWin::closeBrowser() +{ + m_quit(); +} + +BrowserContext InspectorPlaywrightAgentClientWin::createBrowserContext(WTF::String& error) +{ + auto config = API::ProcessPoolConfiguration::create(); + BrowserContext browserContext; + browserContext.processPool = WebKit::WebProcessPool::create(config); + browserContext.dataStore = WebKit::WebsiteDataStore::createNonPersistent(); + PAL::SessionID sessionID = browserContext.dataStore->sessionID(); + 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..2536fe399ef9a5916803954e1f4971a24b7ca4ec --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h @@ -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. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include +#include + +typedef WKPageRef (*CreatePageCallback)(WKPageConfigurationRef configuration); +typedef void (*QuitCallback)(); + +namespace WebKit { + +class InspectorPlaywrightAgentClientWin : public InspectorPlaywrightAgentClient { + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorPlaywrightAgentClientWin(CreatePageCallback, QuitCallback); + ~InspectorPlaywrightAgentClientWin() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + BrowserContext createBrowserContext(WTF::String& error) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + 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/WebPageInspectorEmulationAgentWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..520d9714bac279a8b778c2c377af4411fba8d5d7 --- /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 = m_page.viewWidget(); + HWND windowHwnd = GetAncestor(viewHwnd, GA_ROOT); + RECT viewRect; + RECT windowRect; + + if (!windowHwnd || !GetWindowRect(windowHwnd, &windowRect)) { + callback("Could not retrieve window size"); + return; + } + if (!GetWindowRect(viewHwnd, &viewRect)) { + callback("Could retrieve view size"); + 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_NOMOVE)) { + callback("Could not resize window"); + 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..a299240b1fea96694cb47fa11fc6a6411ffdaf70 --- /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(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& macCommands, WallTime timestamp) +{ + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + "", + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebProcessPoolWin.cpp b/Source/WebKit/UIProcess/win/WebProcessPoolWin.cpp index 18f9e93932793b7c3e44e6346be0f13ed6dbf233..acb0617bcded07029665d4949659c73adf2fd633 100644 --- a/Source/WebKit/UIProcess/win/WebProcessPoolWin.cpp +++ b/Source/WebKit/UIProcess/win/WebProcessPoolWin.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "WebProcessPool.h" - +#include "NetworkProcessMessages.h" #include "WebProcessCreationParameters.h" #include @@ -97,4 +97,11 @@ void WebProcessPool::platformResolvePathsForSandboxExtensions() { } +void WebProcessPool::setIgnoreTLSErrors(bool ignoreTLSErrors) +{ + m_ignoreTLSErrors = ignoreTLSErrors; + if (networkProcess()) + networkProcess()->send(Messages::NetworkProcess::SetIgnoreTLSErrors(m_ignoreTLSErrors), 0); +} + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7453194ca6f032ba86a4c67f5bf12688ab6ec1be --- /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/WebPageInspectorEmulationAgentWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5dc76aa302cb574307059e66a1b73730efe920da --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp @@ -0,0 +1,41 @@ +/* + * 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 "WebPageProxy.h" +#include + +namespace WebKit { + +void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function&& callback) +{ + struct wpe_view_backend* backend = m_page.viewBackend(); + wpe_view_backend_dispatch_set_size(backend, width, height); + 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..585fb151f302e4b376c705ed0d0974d518733605 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp @@ -0,0 +1,59 @@ +/* + * 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(WebKeyboardEvent::Type type, const String& text, const String& unmodifiedText, const String& key, const String& code, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& macCommands, WallTime timestamp) +{ + unsigned keyCode = WebCore::PlatformKeyboardEvent::WPEKeyCodeForWindowsKeyCode(windowsVirtualKeyCode); + String keyIdentifier; + if (keyCode) + keyIdentifier = WebCore::PlatformKeyboardEvent::keyIdentifierForWPEKeyCode(keyCode); + 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/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj index 864f9fa399b899a19223a0b31b9b5eaadbfe947f..82a73575abeaadb112ff0e3866e59adc62dac44b 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj @@ -1767,6 +1767,19 @@ CEE4AE2B1A5DCF430002F49B /* UIKitSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = CEE4AE2A1A5DCF430002F49B /* UIKitSPI.h */; }; D3B9484711FF4B6500032B39 /* WebPopupMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = D3B9484311FF4B6500032B39 /* WebPopupMenu.h */; }; D3B9484911FF4B6500032B39 /* WebSearchPopupMenu.h in Headers */ = {isa = PBXBuildFile; fileRef = D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */; }; + D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */; }; + D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */; }; + D71A94382370F032002C4D9E /* BrowserInspectorController.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94372370F032002C4D9E /* BrowserInspectorController.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, ); }; }; E105FE5418D7B9DE008F57A8 /* EditingRange.h in Headers */ = {isa = PBXBuildFile; fileRef = E105FE5318D7B9DE008F57A8 /* EditingRange.h */; }; @@ -5202,6 +5215,20 @@ D3B9484311FF4B6500032B39 /* WebPopupMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPopupMenu.h; sourceTree = ""; }; D3B9484411FF4B6500032B39 /* WebSearchPopupMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSearchPopupMenu.cpp; sourceTree = ""; }; D3B9484511FF4B6500032B39 /* WebSearchPopupMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSearchPopupMenu.h; sourceTree = ""; }; + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBrowserInspector.h; sourceTree = ""; }; + D71A94302370E025002C4D9E /* 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 = ""; }; + D71A94372370F032002C4D9E /* BrowserInspectorController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserInspectorController.h; sourceTree = ""; }; + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorPipe.h; sourceTree = ""; }; + 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 = ""; }; @@ -7131,6 +7158,7 @@ 37C4C08318149C2A003688B9 /* Cocoa */ = { isa = PBXGroup; children = ( + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */, 1A43E826188F38E2009E4D30 /* Deprecated */, 37A5E01218BBF937000A081E /* _WKActivatedElementInfo.h */, 37A5E01118BBF937000A081E /* _WKActivatedElementInfo.mm */, @@ -8833,6 +8861,13 @@ BC032DC310F438260058C15A /* UIProcess */ = { isa = PBXGroup; children = ( + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */, + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */, + D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */, + D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */, + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */, + D71A94372370F032002C4D9E /* BrowserInspectorController.h */, + D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */, BC032DC410F4387C0058C15A /* API */, 512F588D12A8836F00629530 /* Authentication */, 9955A6E81C79809000EB6A93 /* Automation */, @@ -9112,6 +9147,7 @@ BC0C376610F807660076D7CB /* C */ = { isa = PBXGroup; children = ( + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */, 5123CF18133D25E60056F800 /* cg */, 6EE849C41368D9040038D481 /* mac */, BCB63477116BF10600603215 /* WebKit2_C.h */, @@ -9714,6 +9750,11 @@ BCCF085C113F3B7500C650C5 /* mac */ = { isa = PBXGroup; children = ( + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */, + D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */, + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */, + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */, + D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */, B878B613133428DC006888E9 /* CorrectionPanel.h */, B878B614133428DC006888E9 /* CorrectionPanel.mm */, C1817362205844A900DFDA65 /* DisplayLink.cpp */, @@ -10467,6 +10508,7 @@ 991F492F23A812C60054642B /* _WKInspectorDebuggableInfo.h in Headers */, 99036AE223A949CF0000B06A /* _WKInspectorDebuggableInfoInternal.h in Headers */, 9197940C23DBC50300257892 /* _WKInspectorDelegate.h in Headers */, + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */, 5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */, 9979CA58237F49F10039EC05 /* _WKInspectorPrivate.h in Headers */, A5C0F0AB2000658200536536 /* _WKInspectorWindow.h in Headers */, @@ -10591,6 +10633,7 @@ 7C89D2981A6753B2003A5FDE /* APIPageConfiguration.h in Headers */, 1AC1336C18565C7A00F3EC05 /* APIPageHandle.h in Headers */, 1AFDD3151891B54000153970 /* APIPolicyClient.h in Headers */, + D71A94382370F032002C4D9E /* BrowserInspectorController.h in Headers */, 7CE4D2201A4914CA00C7F152 /* APIProcessPoolConfiguration.h in Headers */, 49BCA19223A177660028A836 /* APIResourceLoadStatisticsFirstParty.h in Headers */, 49BCA19723A1930D0028A836 /* APIResourceLoadStatisticsThirdParty.h in Headers */, @@ -10716,6 +10759,7 @@ BC06F43A12DBCCFB002D78DE /* GeolocationPermissionRequestProxy.h in Headers */, 2DA944A41884E4F000ED86DB /* GestureTypes.h in Headers */, 2DA049B8180CCD0A00AAFA9E /* GraphicsLayerCARemote.h in Headers */, + D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */, C0CE72AD1247E78D00BC0EC4 /* HandleMessage.h in Headers */, 1AC75A1B1B3368270056745B /* HangDetectionDisabler.h in Headers */, 57AC8F50217FEED90055438C /* HidConnection.h in Headers */, @@ -10842,8 +10886,10 @@ 41DC45961E3D6E2200B11F51 /* NetworkRTCProvider.h in Headers */, 413075AB1DE85F330039EC69 /* NetworkRTCSocket.h in Headers */, 5C20CBA01BB1ECD800895BB1 /* NetworkSession.h in Headers */, + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */, 532159551DBAE7290054AA3C /* NetworkSessionCocoa.h in Headers */, 417915B92257046F00D6F97E /* NetworkSocketChannel.h in Headers */, + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */, 570DAAC22303730300E8FC04 /* NfcConnection.h in Headers */, 570DAAAE23026F5C00E8FC04 /* NfcService.h in Headers */, 31A2EC5614899C0900810D71 /* NotificationPermissionRequest.h in Headers */, @@ -10927,6 +10973,7 @@ CD2865EE2255562000606AC7 /* ProcessTaskStateObserver.h in Headers */, 463FD4821EB94EC000A2982C /* ProcessTerminationReason.h in Headers */, 86E67A251910B9D100004AB7 /* ProcessThrottler.h in Headers */, + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */, 83048AE61ACA45DC0082C832 /* ProcessThrottlerClient.h in Headers */, A1E688701F6E2BAB007006A6 /* QuarantineSPI.h in Headers */, 57FD318222B3515E008D0E8B /* RedirectSOAuthorizationSession.h in Headers */, @@ -11355,6 +11402,7 @@ BCD25F1711D6BDE100169B0E /* WKBundleFrame.h in Headers */, BCF049E611FE20F600F86A58 /* WKBundleFramePrivate.h in Headers */, BC49862F124D18C100D834E1 /* WKBundleHitTestResult.h in Headers */, + D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */, BC204EF211C83EC8008F3375 /* WKBundleInitialize.h in Headers */, 65B86F1E12F11DE300B7DD8A /* WKBundleInspector.h in Headers */, 1A8B66B41BC45B010082DF77 /* WKBundleMac.h in Headers */, @@ -11407,6 +11455,7 @@ 5C795D71229F3757003FF1C4 /* WKContextMenuElementInfoPrivate.h in Headers */, 51A555F6128C6C47009ABCEC /* WKContextMenuItem.h in Headers */, 51A55601128C6D92009ABCEC /* WKContextMenuItemTypes.h in Headers */, + D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */, A1EA02381DABFF7E0096021F /* WKContextMenuListener.h in Headers */, BCC938E11180DE440085E5FE /* WKContextPrivate.h in Headers */, 9FB5F395169E6A80002C25BF /* WKContextPrivateMac.h in Headers */, @@ -11557,6 +11606,7 @@ 1AB8A1F818400BB800E9AE69 /* WKPageContextMenuClient.h in Headers */, 8372DB251A674C8F00C697C5 /* WKPageDiagnosticLoggingClient.h in Headers */, 1AB8A1F418400B8F00E9AE69 /* WKPageFindClient.h in Headers */, + D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */, 1AB8A1F618400B9D00E9AE69 /* WKPageFindMatchesClient.h in Headers */, 1AB8A1F018400B0000E9AE69 /* WKPageFormClient.h in Headers */, BC7B633712A45ABA00D174A4 /* WKPageGroup.h in Headers */, @@ -12605,6 +12655,7 @@ CDA93DB122F8BCF400490A69 /* FullscreenTouchSecheuristicParameters.cpp in Sources */, 2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */, 2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */, + D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */, 2D913441212CF9F000128AFD /* JSNPMethod.cpp in Sources */, 2D913442212CF9F000128AFD /* JSNPObject.cpp in Sources */, 2984F588164BA095004BC0C6 /* LegacyCustomProtocolManagerMessageReceiver.cpp in Sources */, @@ -12615,6 +12666,7 @@ 2D92A781212B6A7100F493FD /* MessageReceiverMap.cpp in Sources */, 2D92A782212B6A7100F493FD /* MessageSender.cpp in Sources */, 2D92A77A212B6A6100F493FD /* Module.cpp in Sources */, + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */, 57B826452304F14000B72EB0 /* NearFieldSoftLink.mm in Sources */, 2D913443212CF9F000128AFD /* NetscapeBrowserFuncs.cpp in Sources */, 2D913444212CF9F000128AFD /* NetscapePlugin.cpp in Sources */, @@ -12639,6 +12691,7 @@ 1A2D8439127F65D5001EB962 /* NPObjectMessageReceiverMessageReceiver.cpp in Sources */, 2D92A792212B6AD400F493FD /* NPObjectProxy.cpp in Sources */, 2D92A793212B6AD400F493FD /* NPRemoteObjectMap.cpp in Sources */, + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */, 2D913447212CF9F000128AFD /* NPRuntimeObjectMap.cpp in Sources */, 2D913448212CF9F000128AFD /* NPRuntimeUtilities.cpp in Sources */, 2D92A794212B6AD400F493FD /* NPVariantData.cpp in Sources */, @@ -12919,6 +12972,7 @@ 2D92A78C212B6AB100F493FD /* WebMouseEvent.cpp in Sources */, 31BA924D148831260062EDB5 /* WebNotificationManagerMessageReceiver.cpp in Sources */, 2DF6FE52212E110900469030 /* WebPage.cpp in Sources */, + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */, C0CE72A01247E71D00BC0EC4 /* WebPageMessageReceiver.cpp in Sources */, BCBD3914125BB1A800D2C29F /* WebPageProxyMessageReceiver.cpp in Sources */, 7CE9CE101FA0767A000177DE /* WebPageUpdatePreferences.cpp in Sources */, diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp index 446eb53a20bec268c51fd1dcb9c31db0efb96a97..483fd1d7b431312b6b5897fa2489773d0e7ae87e 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -228,8 +229,24 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } #endif + if (m_emulateOfflineState) { + scheduleInternallyFailedLoad(resourceLoader); + return; + } + if (!tryLoadingUsingURLSchemeHandler(resourceLoader, trackingParameters)) { WEBLOADERSTRATEGY_RELEASE_LOG_IF_ALLOWED("scheduleLoad: URL will be scheduled with the NetworkProcess"); + + RefPtr coreLoader = &resourceLoader; + if (!resourceLoader.options().serviceWorkerRegistrationIdentifier) { + if (InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, coreLoader, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource](bool handled) mutable { + if (!handled) + scheduleLoadFromNetworkProcess(*coreLoader, coreLoader->request(), trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource)); + })) { + return; + } + } + scheduleLoadFromNetworkProcess(resourceLoader, resourceLoader.request(), trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource)); return; } @@ -774,7 +791,7 @@ void WebLoaderStrategy::didFinishPreconnection(uint64_t preconnectionIdentifier, bool WebLoaderStrategy::isOnLine() const { - return m_isOnLine; + return m_emulateOfflineState ? false : m_isOnLine; } void WebLoaderStrategy::addOnlineStateChangeListener(Function&& listener) @@ -785,6 +802,11 @@ void WebLoaderStrategy::addOnlineStateChangeListener(Function&& list void WebLoaderStrategy::setOnLineState(bool isOnLine) { + if (m_emulateOfflineState) { + m_isOnLine = isOnLine; + return; + } + if (m_isOnLine == isOnLine) return; @@ -793,6 +815,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 22f644fd7f450d32ea45f97e27488ef5f34c153a..9ac93959568cb4561c039cc0ce7b28c404699390 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h @@ -88,6 +88,7 @@ public: bool isOnLine() const final; void addOnlineStateChangeListener(Function&&) final; void setOnLineState(bool); + void setEmulateOfflineState(bool) final; private: void scheduleLoad(WebCore::ResourceLoader&, WebCore::CachedResource*, bool shouldClearReferrerOnHTTPSToHTTPRedirect); @@ -126,6 +127,7 @@ private: HashMap m_preconnectCompletionHandlers; Vector> m_onlineStateChangeListeners; bool m_isOnLine { true }; + bool m_emulateOfflineState { false }; HashSet m_loadersWithUploads; }; diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp index 25fb020932123687c79c0bee74e3e54d22c47b74..0a3935937f42913db2ca26ad980d030b448f712d 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp @@ -410,6 +410,8 @@ void WebChromeClient::setResizable(bool resizable) void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, unsigned columnNumber, const String& sourceID) { + if (level == MessageLevel::Error) + m_page.send(Messages::WebPageProxy::LogToStderr(message)); // Notify the bundle client. m_page.injectedBundleUIClient().willAddMessageToConsole(&m_page, source, level, message, lineNumber, columnNumber, sourceID); } diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp index 2c1a3362304c0aab9eccca58c3fe67b7250d2232..bde6a8e7b76eaa367aeba99489c06e46419890be 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp @@ -244,12 +244,20 @@ void DrawingAreaCoordinatedGraphics::updatePreferences(const WebPreferencesStore settings.setAcceleratedCompositingEnabled(false); } #endif + +#if USE(LIBWPE) + settings.setAcceleratedCompositingEnabled(false); + settings.setForceCompositingMode(false); + settings.setAcceleratedCompositingForFixedPositionEnabled(false); + m_alwaysUseCompositing = false; +#else settings.setForceCompositingMode(store.getBoolValueForKey(WebPreferencesKey::forceCompositingModeKey())); // Fixed position elements need to be composited and create stacking contexts // in order to be scrolled by the ScrollingCoordinator. settings.setAcceleratedCompositingForFixedPositionEnabled(settings.acceleratedCompositingEnabled()); m_alwaysUseCompositing = settings.acceleratedCompositingEnabled() && settings.forceCompositingMode(); +#endif // If async scrolling is disabled, we have to force-disable async frame and overflow scrolling // to keep the non-async scrolling on those elements working. diff --git a/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.cpp b/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.cpp index b2d54a627b94583bda3518c4e7c3364481b605a4..d407e32b6a7b8b27925c49391e86d42c9b3dfa8b 100644 --- a/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.cpp @@ -47,6 +47,14 @@ void WebDocumentLoader::detachFromFrame() DocumentLoader::detachFromFrame(); } +void WebDocumentLoader::replacedByFragmentNavigation(Frame& frame) +{ + ASSERT(!this->frame()); + // Notify WebPageProxy that the navigation has been converted into same page navigation. + if (m_navigationID) + WebFrame::fromCoreFrame(frame)->documentLoaderDetached(m_navigationID); +} + void WebDocumentLoader::setNavigationID(uint64_t navigationID) { ASSERT(navigationID); diff --git a/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.h b/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.h index f127d64d005ab7b93875591b94a5899205e91579..df0de26e4dc449a0fbf93e7037444df4e5365822 100644 --- a/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.h +++ b/Source/WebKit/WebProcess/WebPage/WebDocumentLoader.h @@ -43,7 +43,10 @@ public: private: WebDocumentLoader(const WebCore::ResourceRequest&, const WebCore::SubstituteData&); + uint64_t loaderIDForInspector() override { return navigationID(); } + void detachFromFrame() override; + void replacedByFragmentNavigation(WebCore::Frame&) override; uint64_t m_navigationID; }; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp index 1ba789ad1a31c400cab17e03ef2cb43a6108c309..e8133744a9eca8660d90e3aeb8d038a5c0be271f 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -746,6 +746,9 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) send(Messages::WebPageProxy::DidCreateContextForVisibilityPropagation(m_contextForVisibilityPropagation->contextID())); #endif + if (parameters.shouldPauseInInspectorWhenShown) + m_page->inspectorController().pauseWhenShown(); + updateThrottleState(); } @@ -1575,6 +1578,22 @@ void WebPage::platformDidReceiveLoadParameters(const LoadParameters& loadParamet } #endif +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->coreFrame(), loadParameters.request, ShouldOpenExternalURLsPolicy::ShouldNotAllow }; + frame->coreFrame()->loader().load(WTFMove(frameLoadRequest)); + ASSERT(!m_pendingFrameNavigationID); +} + void WebPage::loadRequest(LoadParameters&& loadParameters) { setIsNavigatingToAppBoundDomain(loadParameters.isNavigatingToAppBoundDomain); @@ -1782,17 +1801,13 @@ void WebPage::setSize(const WebCore::IntSize& viewSize) view->resize(viewSize); m_drawingArea->setNeedsDisplay(); -#if USE(COORDINATED_GRAPHICS) if (view->useFixedLayout()) sendViewportAttributesChanged(m_page->viewportArguments()); -#endif } -#if USE(COORDINATED_GRAPHICS) void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArguments) { - FrameView* view = m_page->mainFrame().view(); - ASSERT(view && view->useFixedLayout()); + ASSERT(m_page->mainFrame().view() && m_page->mainFrame().view()->useFixedLayout()); // Viewport properties have no impact on zero sized fixed viewports. if (m_viewSize.isEmpty()) @@ -1809,20 +1824,18 @@ void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArg ViewportAttributes attr = computeViewportAttributes(viewportArguments, minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize); - // If no layout was done yet set contentFixedOrigin to (0,0). - IntPoint contentFixedOrigin = view->didFirstLayout() ? view->fixedVisibleContentRect().location() : IntPoint(); - - // Put the width and height to the viewport width and height. In css units however. - // Use FloatSize to avoid truncated values during scale. - FloatSize contentFixedSize = m_viewSize; - - contentFixedSize.scale(1 / attr.initialScale); - view->setFixedVisibleContentRect(IntRect(contentFixedOrigin, roundedIntSize(contentFixedSize))); +#if ENABLE(CSS_DEVICE_ADAPTATION) + FrameView* view = m_page->mainFrame().view(); + // CSS viewport descriptors might be applied to already affected viewport size + // if the page enables/disables stylesheets, so need to keep initial viewport size. + view->setInitialViewportSize(roundedIntSize(m_viewSize)); +#endif attr.initialScale = m_page->viewportArguments().zoom; // Resets auto (-1) if no value was set by user. // This also takes care of the relayout. setFixedLayoutSize(roundedIntSize(attr.layoutSize)); + scaleView(deviceWidth / attr.layoutSize.width()); #if USE(COORDINATED_GRAPHICS) m_drawingArea->didChangeViewportAttributes(WTFMove(attr)); @@ -1830,7 +1843,6 @@ void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArg send(Messages::WebPageProxy::DidChangeViewportProperties(attr)); #endif } -#endif void WebPage::scrollMainFrameIfNotAtMaxScrollPosition(const IntSize& scrollOffset) { @@ -2112,6 +2124,7 @@ void WebPage::scaleView(double scale) } m_page->setViewScaleFactor(scale); + send(Messages::WebPageProxy::ViewScaleFactorDidChange(scale)); scalePage(pageScale, scrollPositionAtNewScale); } @@ -2216,17 +2229,13 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum viewportConfigurationChanged(); #endif -#if USE(COORDINATED_GRAPHICS) FrameView* view = m_page->mainFrame().view(); if (view && view->useFixedLayout()) sendViewportAttributesChanged(viewportArguments); +#if USE(COORDINATED_GRAPHICS) else m_drawingArea->didChangeViewportAttributes(ViewportAttributes()); #endif - -#if !PLATFORM(IOS_FAMILY) && !USE(COORDINATED_GRAPHICS) - UNUSED_PARAM(viewportArguments); -#endif } void WebPage::listenForLayoutMilestones(OptionSet milestones) @@ -3111,6 +3120,11 @@ void WebPage::sendMessageToTargetBackend(const String& targetId, const String& m m_inspectorTargetController->sendMessageToTargetBackend(targetId, message); } +void WebPage::resumeInspectorIfPausedInNewWindow() +{ + m_page->inspectorController().resumeIfPausedInNewWindow(); +} + void WebPage::insertNewlineInQuotedContent() { Frame& frame = m_page->focusController().focusedOrMainFrame(); @@ -3357,6 +3371,7 @@ void WebPage::didCompletePageTransition() void WebPage::show() { send(Messages::WebPageProxy::ShowPage()); + m_page->inspectorController().didShowNewWindow(); } String WebPage::userAgent(const URL& webCoreURL) const @@ -6364,6 +6379,9 @@ Ref WebPage::createDocumentLoader(Frame& frame, const ResourceRe WebsitePoliciesData::applyToDocumentLoader(WTFMove(*m_pendingWebsitePolicies), documentLoader); m_pendingWebsitePolicies = WTF::nullopt; } + } else if (m_pendingFrameNavigationID) { + documentLoader->setNavigationID(m_pendingFrameNavigationID); + m_pendingFrameNavigationID = 0; } return documentLoader; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h index 8fa0b2a5f4e4df26ea73ce4605336ba502b58869..1d8a0b3a17c9b491cd36f1327dc6ad6a3276296b 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h @@ -1145,6 +1145,7 @@ 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 insertNewlineInQuotedContent(); @@ -1401,6 +1402,7 @@ private: // Actions void tryClose(CompletionHandler&&); void platformDidReceiveLoadParameters(const LoadParameters&); + void loadRequestInFrameForInspector(LoadParameters&&, WebCore::FrameIdentifier); void loadRequest(LoadParameters&&); NO_RETURN void loadRequestWaitingForProcessLaunch(LoadParameters&&, URL&&, WebPageProxyIdentifier, bool); void loadData(LoadParameters&&); @@ -1545,9 +1547,7 @@ private: void countStringMatches(const String&, uint32_t findOptions, uint32_t maxMatchCount); void replaceMatches(const Vector& matchIndices, const String& replacementText, bool selectionOnly, CallbackID); -#if USE(COORDINATED_GRAPHICS) void sendViewportAttributesChanged(const WebCore::ViewportArguments&); -#endif void didChangeSelectedIndexForActivePopupMenu(int32_t newIndex); void setTextForActivePopupMenu(int32_t index); @@ -2006,6 +2006,7 @@ private: UserActivity m_userActivity; uint64_t m_pendingNavigationID { 0 }; + uint64_t m_pendingFrameNavigationID { 0 }; Optional m_pendingWebsitePolicies; bool m_mainFrameProgressCompleted { false }; diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in index 04fc425228e62a535b314ba027b6b3f4570f4bf8..a085d46b64a03a6dc24aeb138e4fe1d4fc37ddba 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in @@ -128,6 +128,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType ConnectInspector(String targetId, Inspector::FrontendChannel::ConnectionType connectionType) DisconnectInspector(String targetId) SendMessageToTargetBackend(String targetId, String message) + ResumeInspectorIfPausedInNewWindow(); #if ENABLE(REMOTE_INSPECTOR) SetIndicating(bool indicating); @@ -168,6 +169,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType LoadURLInFrame(URL url, String referrer, WebCore::FrameIdentifier frameID) LoadDataInFrame(IPC::DataReference data, String MIMEType, String encodingName, URL baseURL, WebCore::FrameIdentifier frameID) LoadRequest(struct WebKit::LoadParameters loadParameters) + 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) LoadAlternateHTML(struct WebKit::LoadParameters loadParameters) diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp index fa6d520a55a11e811092587f2adb2af1b938dbef..85b926277a0660d8b01ae1cdf77f3d13f8466735 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp @@ -82,6 +82,7 @@ #include "WebsiteData.h" #include "WebsiteDataStoreParameters.h" #include "WebsiteDataType.h" +#include #include #include #include @@ -276,6 +277,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter platformInitializeProcess(parameters); updateCPULimit(); + + Inspector::IdentifiersFactory::initializeWithProcessID(parameters.processIdentifier->toUInt64()); } void WebProcess::initializeConnection(IPC::Connection* connection) diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm index eeaf0a09e8b906d165daa148146c4c832ce6ba2e..37c37de1447185f11449841f012c77ac056e60c9 100644 --- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm @@ -4245,7 +4245,7 @@ static BOOL currentScrollIsBlit(NSView *clipView) _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 cb3379a7bcddb0f83e0c5db7621aebbc4bccac88..8c1e472f0800b7a1c80c49cce6c7c46f6d4784d6 100644 --- a/Source/WebKitLegacy/mac/WebView/WebView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebView.mm @@ -4343,7 +4343,7 @@ IGNORE_WARNINGS_END } #endif // PLATFORM(IOS_FAMILY) -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(IOS_TOUCH_EVENTS) - (NSArray *)_touchEventRegions { auto* frame = [self _mainCoreFrame]; @@ -4389,7 +4389,7 @@ IGNORE_WARNINGS_END return eventRegionArray; } -#endif // ENABLE(TOUCH_EVENTS) +#endif // ENABLE(IOS_TOUCH_EVENTS) // For backwards compatibility with the WebBackForwardList API, we honor both // a per-WebView and a per-preferences setting for whether to use the back/forward cache. diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake index d88133c6c1dcb5554ffa61ee8c08c824181ee2de..ffa751ee547c3e60b5d2ff147ca680c6619cb14f 100644 --- a/Source/cmake/OptionsGTK.cmake +++ b/Source/cmake/OptionsGTK.cmake @@ -3,6 +3,7 @@ include(VersioningUtils) SET_PROJECT_VERSION(2 29 0) set(WEBKITGTK_API_VERSION 4.0) +set(ENABLE_WEBKIT_LEGACY OFF) CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(WEBKIT 82 0 45) CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(JAVASCRIPTCORE 35 0 17) @@ -172,6 +173,13 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_PAINTING_API PRIVATE ${ENABLE_EXPERI WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_TYPED_OM PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_CONIC_GRADIENTS PRIVATE ON) +# Playwright +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_APPLICATION_MANIFEST PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_TRAILING_WORD PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CURSOR_VISIBILITY PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DOWNLOAD_ATTRIBUTE PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_LEGACY_CSS_VENDOR_PREFIXES PRIVATE ON) + 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 d3e08c87f458a079e5061069484899169f1774fd..c7edfdd83591aa8f13282c0582c74ca5f80a69bc 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -3,6 +3,7 @@ include(VersioningUtils) SET_PROJECT_VERSION(2 27 4) set(WPE_API_VERSION 1.0) +set(ENABLE_WEBKIT_LEGACY OFF) CALCULATE_LIBRARY_VERSIONS_FROM_LIBTOOL_TRIPLE(WEBKIT 12 0 9) @@ -66,6 +67,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_PAINTING_API PRIVATE ${ENABLE_EXPERI WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_TYPED_OM PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_CONIC_GRADIENTS PRIVATE ON) +# Playwright +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_APPLICATION_MANIFEST PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_TRAILING_WORD 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_DOWNLOAD_ATTRIBUTE PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_LEGACY_CSS_VENDOR_PREFIXES PRIVATE ON) + # 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 any other WebKit ports. diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake index 705b2ae2bc5d9ee8f52db307efcd0a1efeddd05d..64b7af40e559651560ab7cdb0dbcd8343c3b790b 100644 --- a/Source/cmake/OptionsWin.cmake +++ b/Source/cmake/OptionsWin.cmake @@ -7,8 +7,9 @@ add_definitions(-D_WINDOWS -DWINVER=0x601 -D_WIN32_WINNT=0x601) add_definitions(-DNOMINMAX) add_definitions(-DUNICODE -D_UNICODE) +set(ENABLE_WEBKIT_LEGACY OFF) + if ((NOT DEFINED ENABLE_WEBKIT_LEGACY) OR ENABLE_WEBKIT_LEGACY) - set(ENABLE_WEBKIT_LEGACY ON) set(ENABLE_WEBKIT OFF) endif () @@ -93,6 +94,14 @@ if (${WTF_PLATFORM_WIN_CAIRO}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBDRIVER PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEB_CRYPTO PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) + # Playwright + WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_CONIC_GRADIENTS PRIVATE ON) + WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_TRAILING_WORD PRIVATE ON) + WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DARK_MODE_CSS PRIVATE ON) + WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DOWNLOAD_ATTRIBUTE PRIVATE ON) + WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_EVENTS PRIVATE ON) + WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_TOUCH_EVENTS PRIVATE ON) + # FIXME: Implement plugin process on Modern WebKit. https://bugs.webkit.org/show_bug.cgi?id=185313 WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NETSCAPE_PLUGIN_API PRIVATE OFF) else () diff --git a/Tools/MiniBrowser/gtk/BrowserTab.c b/Tools/MiniBrowser/gtk/BrowserTab.c index 9e9978efd3d821c7afcd7b65e14c64e36b355802..a5eef119bddd011470319ac80a0ac443ff0e5441 100644 --- a/Tools/MiniBrowser/gtk/BrowserTab.c +++ b/Tools/MiniBrowser/gtk/BrowserTab.c @@ -147,6 +147,11 @@ static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, Brows gtk_container_foreach(GTK_CONTAINER(tab), (GtkCallback)removeChildIfInfoBar, tab); } +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); @@ -457,6 +462,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); diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.c b/Tools/MiniBrowser/gtk/BrowserWindow.c index 37f9eefbafd14b69c2bedf928ef379670cfef531..5e7e5db253cf788a079e4a0922833b0778b4640d 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.c +++ b/Tools/MiniBrowser/gtk/BrowserWindow.c @@ -79,6 +79,8 @@ static const gdouble defaultZoomLevel = 1; static const gdouble zoomStep = 1.2; static GList *windowList; +static gboolean no_quit = false; + G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW) static char *getExternalURI(const char *uri) @@ -707,7 +709,7 @@ static void browserWindowFinalize(GObject *gObject) G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject); - if (!windowList) + if (!windowList && !no_quit) gtk_main_quit(); } @@ -1233,6 +1235,11 @@ void browser_window_set_background_color(BrowserWindow *window, GdkRGBA *rgba) gtk_widget_set_app_paintable(GTK_WIDGET(window), TRUE); } +void browser_window_no_quit(void) +{ + no_quit = true; +} + static BrowserWindow *findActiveWindow(void) { GList *l; diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.h b/Tools/MiniBrowser/gtk/BrowserWindow.h index 1570d65effb5d601ee3c44a2a7461436f4691c2c..65e62adad0c3684e5cec2f6bc8e7f5281e1f77eb 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.h +++ b/Tools/MiniBrowser/gtk/BrowserWindow.h @@ -37,7 +37,7 @@ G_BEGIN_DECLS #define BROWSER_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_WINDOW)) #define BROWSER_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BROWSER_TYPE_WINDOW)) #define BROWSER_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), BROWSER_TYPE_WINDOW, BrowserWindowClass)) -#define BROWSER_DEFAULT_URL "http://www.webkitgtk.org/" +#define BROWSER_DEFAULT_URL "about:blank" #define BROWSER_ABOUT_SCHEME "minibrowser-about" typedef struct _BrowserWindow BrowserWindow; @@ -53,7 +53,7 @@ void browser_window_load_session(BrowserWindow *, const char *sessionFile); void browser_window_set_background_color(BrowserWindow*, GdkRGBA*); WebKitWebView* browser_window_get_or_create_web_view_for_automation(void); WebKitWebView *browser_window_create_web_view_in_new_tab_for_automation(void); - +void browser_window_no_quit(void); G_END_DECLS #endif diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c index 4c5147dcd38a53e2feaeaae0fce38f92dc60eba6..77d031add801b2f45c9d90e74afab8802aa08e20 100644 --- a/Tools/MiniBrowser/gtk/main.c +++ b/Tools/MiniBrowser/gtk/main.c @@ -53,6 +53,10 @@ static const char *cookiesFile; static const char *cookiesPolicy; static const char *proxy; static gboolean darkMode; +static gboolean inspectorPipe; +static gboolean headless; +static gboolean noStartupWindow; +static const char *userDataDir; static gboolean printVersion; typedef enum { @@ -121,6 +125,10 @@ static const GOptionEntry commandLineOptions[] = { "ignore-tls-errors", 0, 0, G_OPTION_ARG_NONE, &ignoreTLSErrors, "Ignore TLS errors", NULL }, { "content-filter", 0, 0, G_OPTION_ARG_FILENAME, &contentFilter, "JSON with content filtering rules", "FILE" }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WebKitGTK version", NULL }, + { "inspector-pipe", 0, 0, G_OPTION_ARG_NONE, &inspectorPipe, "Open pipe connection to the remote inspector", NULL }, + { "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 } }; @@ -498,6 +506,34 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } +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, + "is-ephemeral", webkit_web_context_is_ephemeral(context), + "is-controlled-by-automation", TRUE, + NULL)); + GtkWidget *newWindow = browser_window_new(NULL, context); + browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView); + gtk_widget_grab_focus(GTK_WIDGET(newWebView)); + gtk_widget_show(GTK_WIDGET(newWindow)); + webkit_web_view_load_uri(newWebView, "about:blank"); + return newWebView; +} + +static void configureBrowserInspectorPipe() +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + + webkit_browser_inspector_initialize_pipe(NULL); +} + int main(int argc, char *argv[]) { #if ENABLE_DEVELOPER_MODE @@ -541,8 +577,28 @@ int main(int argc, char *argv[]) return 0; } - WebKitWebsiteDataManager *manager = (privateMode || automationMode) ? webkit_website_data_manager_new_ephemeral() : webkit_website_data_manager_new(NULL); + if (inspectorPipe) + configureBrowserInspectorPipe(); + + if (noStartupWindow) { + browser_window_no_quit(); + gtk_main(); + g_clear_object(&webkitSettings); + return 0; + } + + 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); + } + WebKitWebContext *webContext = g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", manager, "process-swap-on-cross-site-navigation-enabled", TRUE, NULL); + persistentWebContext = webContext; g_object_unref(manager); if (cookiesPolicy) { @@ -648,8 +704,7 @@ int main(int argc, char *argv[]) gtk_main(); - if (privateMode) - g_object_unref(webContext); + g_object_unref(webContext); return 0; } diff --git a/Tools/MiniBrowser/win/Common.cpp b/Tools/MiniBrowser/win/Common.cpp index 87fde928c12a91f13a4f8bc2f2dc24097e42f2d0..40f62e51f18279a1c48d01386120b49a0f9f6029 100644 --- a/Tools/MiniBrowser/win/Common.cpp +++ b/Tools/MiniBrowser/win/Common.cpp @@ -278,6 +278,14 @@ CommandLineOptions parseCommandLine() #if ENABLE(WEBKIT) else if (!wcsicmp(argv[i], L"--wk2") || !wcsicmp(argv[i], L"--webkit")) options.windowType = BrowserWindowType::WebKit; + else if (!wcsicmp(argv[i], L"--inspector-pipe")) + options.inspectorPipe = true; + else if (!wcsncmp(argv[i], L"--user-data-dir=", 16)) + options.userDataDir = argv[i] + 16; + else if (!wcsicmp(argv[i], L"--headless")) + options.headless = true; + else if (!wcsicmp(argv[i], L"--no-startup-window")) + options.noStartupWindow = true; #endif else if (!options.requestedURL) options.requestedURL = argv[i]; diff --git a/Tools/MiniBrowser/win/Common.h b/Tools/MiniBrowser/win/Common.h index d996feb64e02d7399f2ed0b34d3d0dd03133f824..044069ecd792654e533bac276b98ad45410fb9c7 100644 --- a/Tools/MiniBrowser/win/Common.h +++ b/Tools/MiniBrowser/win/Common.h @@ -36,8 +36,12 @@ enum class BrowserWindowType { struct CommandLineOptions { bool usesLayeredWebView { }; bool useFullDesktop { }; + bool inspectorPipe { }; + bool headless { }; + bool noStartupWindow { }; BrowserWindowType windowType; _bstr_t requestedURL; + _bstr_t userDataDir; CommandLineOptions() #if ENABLE(WEBKIT) diff --git a/Tools/MiniBrowser/win/MainWindow.cpp b/Tools/MiniBrowser/win/MainWindow.cpp index 08131e61107bc4163c4fb1e9a65ee5a1ecda6b04..d157cb5c13bf61ad2593989353237629ae60d710 100644 --- a/Tools/MiniBrowser/win/MainWindow.cpp +++ b/Tools/MiniBrowser/win/MainWindow.cpp @@ -60,6 +60,14 @@ static INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); std::wstring MainWindow::s_windowClass; size_t MainWindow::s_numInstances; +bool MainWindow::s_headless = false; +bool MainWindow::s_noStartupWindow = false; + +void MainWindow::configure(bool headless, bool noStartupWindow) { + s_headless = headless; + s_noStartupWindow = noStartupWindow; +} + static std::wstring loadString(int id) { constexpr size_t length = 100; @@ -102,7 +110,9 @@ bool MainWindow::isInstance(HWND hwnd) return s_windowClass == buff; } -MainWindow::MainWindow() +MainWindow::MainWindow(WKContextRef context, WKWebsiteDataStoreRef dataStore) + : m_context(context) + , m_dataStore(dataStore) { s_numInstances++; } @@ -112,9 +122,9 @@ MainWindow::~MainWindow() s_numInstances--; } -Ref MainWindow::create() +Ref MainWindow::create(WKContextRef context, WKWebsiteDataStoreRef dataStore) { - return adoptRef(*new MainWindow()); + return adoptRef(*new MainWindow(context, dataStore)); } void MainWindow::createToolbar(HINSTANCE hInstance) @@ -202,24 +212,26 @@ bool MainWindow::init(BrowserWindowFactory factory, HINSTANCE hInstance, bool us auto title = loadString(IDS_APP_TITLE); - m_hMainWnd = CreateWindow(s_windowClass.c_str(), title.c_str(), WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, this); + m_hMainWnd = CreateWindowExW(s_headless ? WS_EX_NOACTIVATE : 0, s_windowClass.c_str(), title.c_str(), + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, this); if (!m_hMainWnd) return false; + if (!s_headless) { #if !ENABLE(WEBKIT) - EnableMenuItem(GetMenu(m_hMainWnd), IDM_NEW_WEBKIT_WINDOW, MF_GRAYED); + EnableMenuItem(GetMenu(m_hMainWnd), IDM_NEW_WEBKIT_WINDOW, MF_GRAYED); #endif #if !ENABLE(WEBKIT_LEGACY) - EnableMenuItem(GetMenu(m_hMainWnd), IDM_NEW_WEBKITLEGACY_WINDOW, MF_GRAYED); + EnableMenuItem(GetMenu(m_hMainWnd), IDM_NEW_WEBKITLEGACY_WINDOW, MF_GRAYED); #endif - createToolbar(hInstance); - if (!m_hToolbarWnd) - return false; + createToolbar(hInstance); + if (!m_hToolbarWnd) + return false; + } - m_browserWindow = factory(*this, m_hMainWnd, usesLayeredWebView); + m_browserWindow = factory(*this, m_hMainWnd, m_context.get(), m_dataStore.get(), usesLayeredWebView); if (!m_browserWindow) return false; HRESULT hr = m_browserWindow->init(); @@ -228,7 +240,13 @@ bool MainWindow::init(BrowserWindowFactory factory, HINSTANCE hInstance, bool us updateDeviceScaleFactor(); resizeSubViews(); - SetFocus(m_hURLBarWnd); + + if (s_headless) { + SetMenu(m_hMainWnd, NULL); + } else { + SetFocus(m_hURLBarWnd); + ShowWindow(m_hMainWnd, SW_SHOW); + } return true; } @@ -236,6 +254,10 @@ void MainWindow::resizeSubViews() { RECT rcClient; GetClientRect(m_hMainWnd, &rcClient); + if (s_headless) { + MoveWindow(m_browserWindow->hwnd(), 0, 0, rcClient.right, rcClient.bottom, true); + return; + } resizeToolbar(rcClient.right); @@ -254,6 +276,9 @@ LRESULT CALLBACK MainWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPA { LRESULT result = 0; RefPtr thisWindow = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); + if (!thisWindow && message != WM_CREATE) + return DefWindowProc(hWnd, message, wParam, lParam); + switch (message) { case WM_ACTIVATE: switch (LOWORD(wParam)) { @@ -309,17 +334,15 @@ LRESULT CALLBACK MainWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPA break; #if ENABLE(WEBKIT) case IDM_NEW_WEBKIT_WINDOW: { - auto& newWindow = MainWindow::create().leakRef(); + auto& newWindow = MainWindow::create(thisWindow->m_context.get(), thisWindow->m_dataStore.get()).leakRef(); newWindow.init(WebKitBrowserWindow::create, hInst); - ShowWindow(newWindow.hwnd(), SW_SHOW); break; } #endif #if ENABLE(WEBKIT_LEGACY) case IDM_NEW_WEBKITLEGACY_WINDOW: { - auto& newWindow = MainWindow::create().leakRef(); + auto& newWindow = MainWindow::create(thisWindow->m_context.get(), thisWindow->m_dataStore.get()).leakRef(); newWindow.init(WebKitLegacyBrowserWindow::create, hInst); - ShowWindow(newWindow.hwnd(), SW_SHOW); break; } #endif @@ -384,7 +407,7 @@ LRESULT CALLBACK MainWindow::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPA case WM_DESTROY: SetWindowLongPtr(hWnd, GWLP_USERDATA, 0); thisWindow->deref(); - if (s_numInstances > 1) + if (s_noStartupWindow || s_numInstances > 1) return 0; #if USE(CF) CFRunLoopStop(CFRunLoopGetMain()); @@ -443,6 +466,9 @@ void MainWindow::setDefaultURLToCurrentURL() bool MainWindow::toggleMenuItem(UINT menuID) { + if (s_headless) + return (INT_PTR)FALSE; + HMENU menu = ::GetMenu(hwnd()); switch (menuID) { @@ -518,6 +544,8 @@ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) INT_PTR CALLBACK MainWindow::cachesDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + if (s_headless) + return (INT_PTR)FALSE; MainWindow& thisWindow = *reinterpret_cast(GetWindowLongPtr(hDlg, DWLP_USER)); switch (message) { case WM_INITDIALOG: @@ -548,6 +576,8 @@ INT_PTR CALLBACK MainWindow::cachesDialogProc(HWND hDlg, UINT message, WPARAM wP INT_PTR CALLBACK MainWindow::customUserAgentDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { + if (s_headless) + return (INT_PTR)FALSE; MainWindow& thisWindow = *reinterpret_cast(GetWindowLongPtr(hDlg, DWLP_USER)); switch (message) { case WM_INITDIALOG: { @@ -594,27 +624,26 @@ void MainWindow::loadURL(std::wstring url) if (SUCCEEDED(::UrlCreateFromPath(url.c_str(), fileURL, &fileURLLength, 0))) url = fileURL; } - if (url.find(L"://") == url.npos) + if (url.find(L"://") == url.npos && url.find(L"about:blank") == url.npos) url = L"http://" + url; if (FAILED(m_browserWindow->loadURL(_bstr_t(url.c_str())))) return; - SetFocus(m_browserWindow->hwnd()); + if (!s_headless) + SetFocus(m_browserWindow->hwnd()); } void MainWindow::goHome() { - std::wstring defaultURL = L"https://www.webkit.org/"; - wchar_t url[INTERNET_MAX_URL_LENGTH]; - DWORD urlLength = sizeof(url); - if (!RegGetValue(HKEY_CURRENT_USER, kMiniBrowserRegistryKey, L"DefaultURL", RRF_RT_REG_SZ, nullptr, &url, &urlLength)) - defaultURL = url; + std::wstring defaultURL = L"about:blank"; loadURL(defaultURL); } void MainWindow::onURLBarEnter() { + if (s_headless) + return; wchar_t url[INTERNET_MAX_URL_LENGTH]; GetWindowText(m_hURLBarWnd, url, INTERNET_MAX_URL_LENGTH); loadURL(url); @@ -622,6 +651,8 @@ void MainWindow::onURLBarEnter() void MainWindow::updateDeviceScaleFactor() { + if (s_headless) + return; if (m_hURLBarFont) ::DeleteObject(m_hURLBarFont); @@ -638,6 +669,8 @@ void MainWindow::updateDeviceScaleFactor() void MainWindow::progressChanged(double progress) { + if (s_headless) + return; std::wostringstream text; text << static_cast(progress * 100) << L'%'; SetWindowText(m_hProgressIndicator, text.str().c_str()); @@ -645,10 +678,14 @@ void MainWindow::progressChanged(double progress) void MainWindow::progressFinished() { + if (s_headless) + return; SetWindowText(m_hProgressIndicator, L""); } void MainWindow::activeURLChanged(std::wstring url) { + if (s_headless) + return; SetWindowText(m_hURLBarWnd, url.c_str()); } diff --git a/Tools/MiniBrowser/win/MainWindow.h b/Tools/MiniBrowser/win/MainWindow.h index d79c6fdc4fa05e1e4b9acdcc6932e571163320eb..99718b19797788634f4233a8892729b57ae642d0 100644 --- a/Tools/MiniBrowser/win/MainWindow.h +++ b/Tools/MiniBrowser/win/MainWindow.h @@ -26,6 +26,8 @@ #pragma once #include "BrowserWindow.h" +#include +#include #include #include #include @@ -33,9 +35,10 @@ class MainWindow final : public RefCounted, public BrowserWindowClient { public: - using BrowserWindowFactory = std::function(BrowserWindowClient&, HWND mainWnd, bool usesLayeredWebView)>; + using BrowserWindowFactory = std::function(BrowserWindowClient&, HWND mainWnd, WKContextRef, WKWebsiteDataStoreRef, bool usesLayeredWebView)>; + static void configure(bool headless, bool noStartupWindow); - static Ref create(); + static Ref create(WKContextRef context, WKWebsiteDataStoreRef dataStore); ~MainWindow(); bool init(BrowserWindowFactory, HINSTANCE hInstance, bool usesLayeredWebView = false); @@ -56,8 +59,10 @@ private: static void registerClass(HINSTANCE hInstance); static std::wstring s_windowClass; static size_t s_numInstances; + static bool s_headless; + static bool s_noStartupWindow; - MainWindow(); + MainWindow(WKContextRef context, WKWebsiteDataStoreRef dataStore); void setDefaultURLToCurrentURL(); bool toggleMenuItem(UINT menuID); void onURLBarEnter(); @@ -78,6 +83,8 @@ private: HWND m_hProgressIndicator { nullptr }; HWND m_hCacheWnd { nullptr }; HGDIOBJ m_hURLBarFont { nullptr }; + WKRetainPtr m_context; + WKRetainPtr m_dataStore; RefPtr m_browserWindow; int m_toolbarItemsWidth { }; }; diff --git a/Tools/MiniBrowser/win/WebKitBrowserWindow.cpp b/Tools/MiniBrowser/win/WebKitBrowserWindow.cpp index dc2b3f257600e3f4d172875ebb821769a160979d..9e0072a181ebea8834b96ba5c0020a722f7f3cd4 100644 --- a/Tools/MiniBrowser/win/WebKitBrowserWindow.cpp +++ b/Tools/MiniBrowser/win/WebKitBrowserWindow.cpp @@ -107,7 +107,7 @@ WKRetainPtr createWKURL(const std::wstring& str) return adoptWK(WKURLCreateWithUTF8CString(utf8.data())); } -Ref WebKitBrowserWindow::create(BrowserWindowClient& client, HWND mainWnd, bool) +Ref WebKitBrowserWindow::create(BrowserWindowClient& client, HWND mainWnd, WKContextRef context, WKWebsiteDataStoreRef dataStore, bool) { auto conf = adoptWK(WKPageConfigurationCreate()); @@ -121,8 +121,8 @@ Ref WebKitBrowserWindow::create(BrowserWindowClient& client, HWND WKPreferencesSetDeveloperExtrasEnabled(prefs.get(), true); WKPageConfigurationSetPreferences(conf.get(), prefs.get()); - auto context =adoptWK(WKContextCreateWithConfiguration(nullptr)); - WKPageConfigurationSetContext(conf.get(), context.get()); + WKPageConfigurationSetContext(conf.get(), context); + WKPageConfigurationSetWebsiteDataStore(conf.get(), dataStore); return adoptRef(*new WebKitBrowserWindow(client, conf.get(), mainWnd)); } @@ -143,11 +143,17 @@ WebKitBrowserWindow::WebKitBrowserWindow(BrowserWindowClient& client, WKPageConf navigationClient.didReceiveAuthenticationChallenge = didReceiveAuthenticationChallenge; WKPageSetPageNavigationClient(page, &navigationClient.base); - WKPageUIClientV13 uiClient = { }; - uiClient.base.version = 13; + WKPageUIClientV14 uiClient = { }; + uiClient.base.version = 14; uiClient.base.clientInfo = this; uiClient.createNewPage = createNewPage; uiClient.didNotHandleKeyEvent = didNotHandleKeyEvent; + uiClient.close = closeWindow; + uiClient.runJavaScriptAlert = runJavaScriptAlert; + uiClient.runJavaScriptConfirm = runJavaScriptConfirm; + uiClient.runJavaScriptPrompt = runJavaScriptPrompt; + uiClient.runBeforeUnloadConfirmPanel = runBeforeUnloadConfirmPanel; + uiClient.handleJavaScriptDialog = handleJavaScriptDialog; WKPageSetPageUIClient(page, &uiClient.base); WKPageStateClientV0 stateClient = { }; @@ -159,7 +165,6 @@ WebKitBrowserWindow::WebKitBrowserWindow(BrowserWindowClient& client, WKPageConf stateClient.didChangeActiveURL = didChangeActiveURL; WKPageSetPageStateClient(page, &stateClient.base); - updateProxySettings(); resetZoom(); } @@ -183,6 +188,29 @@ void WebKitBrowserWindow::updateProxySettings() WKWebsiteDataStoreEnableCustomNetworkProxySettings(store, url.get(), excludeHosts.get()); } +WebKitBrowserWindow::~WebKitBrowserWindow() +{ + if (m_alertDialog) { + WKRelease(m_alertDialog); + m_alertDialog = NULL; + } + + if (m_confirmDialog) { + WKRelease(m_confirmDialog); + m_confirmDialog = NULL; + } + + if (m_promptDialog) { + WKRelease(m_promptDialog); + m_promptDialog = NULL; + } + + if (m_beforeUnloadDialog) { + WKRelease(m_beforeUnloadDialog); + m_beforeUnloadDialog = NULL; + } +} + HRESULT WebKitBrowserWindow::init() { return S_OK; @@ -251,7 +279,6 @@ void WebKitBrowserWindow::openProxySettings() { if (askProxySettings(m_hMainWnd, m_proxy)) updateProxySettings(); - } void WebKitBrowserWindow::setUserAgent(_bstr_t& customUAString) @@ -381,18 +408,94 @@ bool WebKitBrowserWindow::canTrustServerCertificate(WKProtectionSpaceRef protect return false; } -WKPageRef WebKitBrowserWindow::createNewPage(WKPageRef page, WKPageConfigurationRef configuration, WKNavigationActionRef navigationAction, WKWindowFeaturesRef windowFeatures, const void *clientInfo) +void WebKitBrowserWindow::closeWindow(WKPageRef page, const void* clientInfo) { - auto& newWindow = MainWindow::create().leakRef(); - auto factory = [configuration](BrowserWindowClient& client, HWND mainWnd, bool) -> auto { + auto& thisWindow = toWebKitBrowserWindow(clientInfo); + PostMessage(thisWindow.m_hMainWnd, WM_CLOSE, 0, 0); +} + +void WebKitBrowserWindow::runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void *clientInfo) +{ + auto& thisWindow = toWebKitBrowserWindow(clientInfo); + WKRetain(listener); + thisWindow.m_alertDialog = listener; +} + +void WebKitBrowserWindow::runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void *clientInfo) +{ + auto& thisWindow = toWebKitBrowserWindow(clientInfo); + WKRetain(listener); + thisWindow.m_confirmDialog = listener; +} + +void WebKitBrowserWindow::runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void *clientInfo) +{ + auto& thisWindow = toWebKitBrowserWindow(clientInfo); + WKRetain(listener); + thisWindow.m_promptDialog = listener; +} + +void WebKitBrowserWindow::runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, WKPageRunBeforeUnloadConfirmPanelResultListenerRef listener, const void *clientInfo) +{ + auto& thisWindow = toWebKitBrowserWindow(clientInfo); + WKRetain(listener); + thisWindow.m_beforeUnloadDialog = listener; +} + +void WebKitBrowserWindow::handleJavaScriptDialog(WKPageRef page, bool accept, WKStringRef value, const void *clientInfo) +{ + auto& thisWindow = toWebKitBrowserWindow(clientInfo); + if (thisWindow.m_alertDialog) { + WKPageRunJavaScriptAlertResultListenerCall(thisWindow.m_alertDialog); + WKRelease(thisWindow.m_alertDialog); + thisWindow.m_alertDialog = NULL; + } + + if (thisWindow.m_confirmDialog) { + WKPageRunJavaScriptConfirmResultListenerCall(thisWindow.m_confirmDialog, accept); + WKRelease(thisWindow.m_confirmDialog); + thisWindow.m_confirmDialog = NULL; + } + + if (thisWindow.m_promptDialog) { + WKPageRunJavaScriptPromptResultListenerCall(thisWindow.m_promptDialog, accept ? value : NULL); + WKRelease(thisWindow.m_promptDialog); + thisWindow.m_promptDialog = NULL; + } + + if (thisWindow.m_beforeUnloadDialog) { + WKPageRunBeforeUnloadConfirmPanelResultListenerCall(thisWindow.m_beforeUnloadDialog, accept); + WKRelease(thisWindow.m_beforeUnloadDialog); + thisWindow.m_beforeUnloadDialog = NULL; + } +} + +WKPageRef WebKitBrowserWindow::createPageCallback(WKPageConfigurationRef configuration) +{ + return WebKitBrowserWindow::createViewCallback(configuration, true); +} + +WKPageRef WebKitBrowserWindow::createViewCallback(WKPageConfigurationRef configuration, bool navigate) +{ + auto context = WKPageConfigurationGetContext(configuration); + auto dataStore = WKPageConfigurationGetWebsiteDataStore(configuration); + auto& newWindow = MainWindow::create(context, dataStore).leakRef(); + auto factory = [configuration](BrowserWindowClient& client, HWND mainWnd, WKContextRef, WKWebsiteDataStoreRef, bool) -> auto { return adoptRef(*new WebKitBrowserWindow(client, configuration, mainWnd)); }; bool ok = newWindow.init(factory, hInst); - if (!ok) - return nullptr; - ShowWindow(newWindow.hwnd(), SW_SHOW); + if (navigate) + newWindow.browserWindow()->loadURL(_bstr_t("about:blank").GetBSTR()); + auto& newBrowserWindow = *static_cast(newWindow.browserWindow()); - WKRetainPtr newPage = WKViewGetPage(newBrowserWindow.m_view.get()); + return WKViewGetPage(newBrowserWindow.m_view.get()); +} + + +WKPageRef WebKitBrowserWindow::createNewPage(WKPageRef, WKPageConfigurationRef configuration, WKNavigationActionRef, WKWindowFeaturesRef, const void*) +{ + // Retain popups as per API contract. + WKRetainPtr newPage = createViewCallback(configuration, false); return newPage.leakRef(); } diff --git a/Tools/MiniBrowser/win/WebKitBrowserWindow.h b/Tools/MiniBrowser/win/WebKitBrowserWindow.h index 373d0de77e852c673a6615e0acedd5195e3c021b..cfeb4f806f79d1a213fdb13346e2b383b9a64273 100644 --- a/Tools/MiniBrowser/win/WebKitBrowserWindow.h +++ b/Tools/MiniBrowser/win/WebKitBrowserWindow.h @@ -26,6 +26,7 @@ #include "BrowserWindow.h" #include "Common.h" +#include #include #include #include @@ -33,10 +34,13 @@ class WebKitBrowserWindow : public BrowserWindow { public: - static Ref create(BrowserWindowClient&, HWND mainWnd, bool useLayeredWebView = false); + static Ref create(BrowserWindowClient&, HWND mainWnd, WKContextRef, WKWebsiteDataStoreRef, bool useLayeredWebView = false); + static WKPageRef createPageCallback(WKPageConfigurationRef); private: + static WKPageRef createViewCallback(WKPageConfigurationRef, bool navigate); WebKitBrowserWindow(BrowserWindowClient&, WKPageConfigurationRef, HWND mainWnd); + ~WebKitBrowserWindow() override; HRESULT init() override; HWND hwnd() override; @@ -71,6 +75,12 @@ private: static void didChangeActiveURL(const void*); static void didReceiveAuthenticationChallenge(WKPageRef, WKAuthenticationChallengeRef, const void*); static WKPageRef createNewPage(WKPageRef, WKPageConfigurationRef, WKNavigationActionRef, WKWindowFeaturesRef, const void *); + static void closeWindow(WKPageRef, const void*); + static void runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void *clientInfo); + static void runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void *clientInfo); + static void runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void *clientInfo); + static void runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, WKPageRunBeforeUnloadConfirmPanelResultListenerRef listener, const void *clientInfo); + static void handleJavaScriptDialog(WKPageRef page, bool accept, WKStringRef value, const void *clientInfo); static void didNotHandleKeyEvent(WKPageRef, WKNativeEventPtr, const void*); BrowserWindowClient& m_client; @@ -78,4 +88,8 @@ private: HWND m_hMainWnd { nullptr }; ProxySettings m_proxy { }; std::unordered_map m_acceptedServerTrustCerts; + WKPageRunJavaScriptAlertResultListenerRef m_alertDialog = { }; + WKPageRunJavaScriptConfirmResultListenerRef m_confirmDialog = { }; + WKPageRunJavaScriptPromptResultListenerRef m_promptDialog = { }; + WKPageRunBeforeUnloadConfirmPanelResultListenerRef m_beforeUnloadDialog = { }; }; diff --git a/Tools/MiniBrowser/win/WinMain.cpp b/Tools/MiniBrowser/win/WinMain.cpp index 6008ca19e26a938cf962c0c336299fff7d13f9a3..8005d72f8c0d9ef82efda8aec1ff0e7d96501ae8 100644 --- a/Tools/MiniBrowser/win/WinMain.cpp +++ b/Tools/MiniBrowser/win/WinMain.cpp @@ -31,6 +31,10 @@ #include "stdafx.h" #include "Common.h" #include "MiniBrowserLibResource.h" +#include "MiniBrowserReplace.h" +#include +#include +#include #include #if USE(CF) @@ -46,9 +50,25 @@ #include #endif +#include +#include + SOFT_LINK_LIBRARY(user32); SOFT_LINK_OPTIONAL(user32, SetProcessDpiAwarenessContext, BOOL, STDAPICALLTYPE, (DPI_AWARENESS_CONTEXT)); +WKRetainPtr toWK(const std::string& string) +{ + return adoptWK(WKStringCreateWithUTF8CString(string.c_str())); +} + +std::string toUTF8String(const wchar_t* src, size_t srcLength) +{ + int length = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, 0, 0, nullptr, nullptr); + std::vector buffer(length); + size_t actualLength = WideCharToMultiByte(CP_UTF8, 0, src, srcLength, buffer.data(), length, nullptr, nullptr); + return { buffer.data(), actualLength }; +} + int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpstrCmdLine, _In_ int nCmdShow) { #ifdef _CRTDBG_MAP_ALLOC @@ -66,6 +86,11 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, InitCommonControlsEx(&InitCtrlEx); auto options = parseCommandLine(); + if (options.inspectorPipe) { + WKInspectorInitializeRemoteInspectorPipe( + WebKitBrowserWindow::createPageCallback, + []() { PostQuitMessage(0); }); + } if (options.useFullDesktop) computeFullDesktopFrame(); @@ -74,32 +99,50 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, OleInitialize(nullptr); if (SetProcessDpiAwarenessContextPtr()) - SetProcessDpiAwarenessContextPtr()(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); - else - ::SetProcessDPIAware(); + SetProcessDpiAwarenessContextPtr()(DPI_AWARENESS_CONTEXT_UNAWARE); + + MainWindow::configure(options.headless, options.noStartupWindow); + if (!options.noStartupWindow) { #if !ENABLE(WEBKIT_LEGACY) - auto factory = WebKitBrowserWindow::create; + auto factory = WebKitBrowserWindow::create; #elif !ENABLE(WEBKIT) - auto factory = WebKitLegacyBrowserWindow::create; + auto factory = WebKitLegacyBrowserWindow::create; #else - auto factory = options.windowType == BrowserWindowType::WebKit ? WebKitBrowserWindow::create : WebKitLegacyBrowserWindow::create; + auto factory = options.windowType == BrowserWindowType::WebKit ? WebKitBrowserWindow::create : WebKitLegacyBrowserWindow::create; #endif - auto& mainWindow = MainWindow::create().leakRef(); - HRESULT hr = mainWindow.init(factory, hInst, options.usesLayeredWebView); - if (FAILED(hr)) - goto exit; - ShowWindow(mainWindow.hwnd(), nCmdShow); + auto configuration = adoptWK(WKWebsiteDataStoreConfigurationCreate()); + if (options.userDataDir.length()) { + std::string profileFolder = toUTF8String(options.userDataDir, options.userDataDir.length()); + WKWebsiteDataStoreConfigurationSetApplicationCacheDirectory(configuration.get(), toWK(profileFolder + "\\ApplicationCache").get()); + WKWebsiteDataStoreConfigurationSetNetworkCacheDirectory(configuration.get(), toWK(profileFolder + "\\Cache").get()); + WKWebsiteDataStoreConfigurationSetCacheStorageDirectory(configuration.get(), toWK(profileFolder + "\\CacheStorage").get()); + WKWebsiteDataStoreConfigurationSetIndexedDBDatabaseDirectory(configuration.get(), toWK(profileFolder + "\\Databases" + "\\IndexedDB").get()); + WKWebsiteDataStoreConfigurationSetLocalStorageDirectory(configuration.get(), toWK(profileFolder + "\\LocalStorage").get()); + WKWebsiteDataStoreConfigurationSetWebSQLDatabaseDirectory(configuration.get(), toWK(profileFolder + "\\Databases" + "\\WebSQL").get()); + WKWebsiteDataStoreConfigurationSetMediaKeysStorageDirectory(configuration.get(), toWK(profileFolder + "\\MediaKeys").get()); + WKWebsiteDataStoreConfigurationSetResourceLoadStatisticsDirectory(configuration.get(), toWK(profileFolder + "\\ResourceLoadStatistics").get()); + WKWebsiteDataStoreConfigurationSetServiceWorkerRegistrationDirectory(configuration.get(), toWK(profileFolder + "\\ServiceWorkers").get()); + } + auto context = adoptWK(WKContextCreateWithConfiguration(nullptr)); + auto dataStore = adoptWK(WKWebsiteDataStoreCreateWithConfiguration(configuration.get())); + WKContextSetPrimaryDataStore(context.get(), dataStore.get()); + + auto& mainWindow = MainWindow::create(context.get(), dataStore.get()).leakRef(); + HRESULT hr = mainWindow.init(factory, hInst, options.usesLayeredWebView); + if (FAILED(hr)) + goto exit; + + if (options.requestedURL.length()) + mainWindow.loadURL(options.requestedURL.GetBSTR()); + else + mainWindow.goHome(); + } hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_MINIBROWSER)); hPreAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDR_ACCELERATORS_PRE)); - if (options.requestedURL.length()) - mainWindow.loadURL(options.requestedURL.GetBSTR()); - else - mainWindow.goHome(); - #pragma warning(disable:4509) // Main message loop: diff --git a/Tools/MiniBrowser/wpe/CMakeLists.txt b/Tools/MiniBrowser/wpe/CMakeLists.txt index 04d3630dc2b0f5e937af173046268001da003753..ba0a60b832cd353776bb50b8198df2d8c4ee9f68 100644 --- a/Tools/MiniBrowser/wpe/CMakeLists.txt +++ b/Tools/MiniBrowser/wpe/CMakeLists.txt @@ -13,6 +13,7 @@ set(MiniBrowser_INCLUDE_DIRECTORIES set(MiniBrowser_SYSTEM_INCLUDE_DIRECTORIES ${ATK_INCLUDE_DIRS} + ${GLIB_INCLUDE_DIRS} ${WPEBACKEND_FDO_INCLUDE_DIRS} ) diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp index a8cccb6c1d567823fe8e6503f1a137856b0a9975..00b39f96b6b48dc0bd3df54659850dfc233ea0be 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp @@ -25,7 +25,7 @@ #include "cmakeconfig.h" -#include "HeadlessViewBackend.h" +#include "NullViewBackend.h" #include "WindowViewBackend.h" #if ENABLE_WEB_AUDIO || ENABLE_VIDEO #include @@ -43,6 +43,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; @@ -64,6 +67,9 @@ static const GOptionEntry commandLineOptions[] = { "content-filter", 0, 0, G_OPTION_ARG_FILENAME, &contentFilter, "JSON with content filtering rules", "FILE" }, { "bg-color", 0, 0, G_OPTION_ARG_STRING, &bgColor, "Window background color. Default: white", "COLOR" }, { "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 } }; @@ -132,7 +138,7 @@ static gboolean decidePermissionRequest(WebKitWebView *, WebKitPermissionRequest static std::unique_ptr createViewBackend(uint32_t width, uint32_t height) { if (headlessMode) - return std::make_unique(width, height); + return std::make_unique(); return std::make_unique(width, height); } @@ -148,13 +154,34 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul g_main_loop_quit(data->mainLoop); } +static gboolean webViewLoadFailed() +{ + return TRUE; +} + static void webViewClose(WebKitWebView* webView, gpointer) { // Hash table key delete func takes care of unref'ing the view g_hash_table_remove(openViews, webView); } -static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer) +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 WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer); + +static WebKitWebView* createWebViewImpl(WebKitWebView* webView, WebKitWebContext *webContext) { auto backend = createViewBackend(1280, 720); struct wpe_view_backend* wpeBackend = backend->backend(); @@ -166,16 +193,50 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi delete static_cast(data); }, backend.release()); - auto* newWebView = webkit_web_view_new_with_related_view(viewBackend, webView); - webkit_web_view_set_settings(newWebView, webkit_web_view_get_settings(webView)); + WebKitWebView* newWebView; + if (webView) { + newWebView = webkit_web_view_new_with_related_view(viewBackend, webView); + } else { + newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, + "backend", viewBackend, + "web-context", webContext, + nullptr)); + } g_signal_connect(newWebView, "close", G_CALLBACK(webViewClose), nullptr); g_hash_table_add(openViews, newWebView); + 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, "create", G_CALLBACK(createWebView), nullptr); return newWebView; } +static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer) +{ + return createWebViewImpl(webView, nullptr); +} + +static WebKitWebContext *persistentWebContext = NULL; + +static WebKitWebView* createNewPage(WebKitBrowserInspector*, WebKitWebContext *webContext) +{ + if (!webContext) + webContext = persistentWebContext; + WebKitWebView* webView = createWebViewImpl(nullptr, webContext); + webkit_web_view_load_uri(webView, "about:blank"); + return webView; +} + +static void configureBrowserInspector(GMainLoop* mainLoop) +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + webkit_browser_inspector_initialize_pipe(mainLoop); +} + int main(int argc, char *argv[]) { #if ENABLE_DEVELOPER_MODE @@ -210,6 +271,16 @@ int main(int argc, char *argv[]) } auto* loop = g_main_loop_new(nullptr, FALSE); + if (inspectorPipe) + configureBrowserInspector(loop); + + openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr); + + if (noStartupWindow) { + g_main_loop_run(loop); + g_main_loop_unref(loop); + return 0; + } auto backend = createViewBackend(1280, 720); struct wpe_view_backend* wpeBackend = backend->backend(); @@ -219,7 +290,19 @@ int main(int argc, char *argv[]) return 1; } - auto* webContext = (privateMode || automationMode) ? webkit_web_context_new_ephemeral() : webkit_web_context_get_default(); + 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); + } + + WebKitWebContext *webContext = WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "website-data-manager", manager, "process-swap-on-cross-site-navigation-enabled", TRUE, NULL)); + persistentWebContext = webContext; + g_object_unref(manager); if (cookiesPolicy) { auto* cookieManager = webkit_web_context_get_cookie_manager(webContext); @@ -300,8 +383,6 @@ int main(int argc, char *argv[]) backendPtr->setAccessibleChild(ATK_OBJECT(accessible)); #endif - openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr); - webkit_web_context_set_automation_allowed(webContext, automationMode); g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), webView); g_signal_connect(webView, "permission-request", G_CALLBACK(decidePermissionRequest), nullptr); @@ -326,7 +407,7 @@ int main(int argc, char *argv[]) g_object_unref(file); webkit_web_view_load_uri(webView, url); g_free(url); - } else if (automationMode) + } else if (automationMode || inspectorPipe) webkit_web_view_load_uri(webView, "about:blank"); else webkit_web_view_load_uri(webView, "https://wpewebkit.org"); @@ -336,8 +417,7 @@ int main(int argc, char *argv[]) g_hash_table_destroy(openViews); - if (privateMode || automationMode) - g_object_unref(webContext); + g_object_unref(webContext); g_main_loop_unref(loop); return 0; diff --git a/Tools/Playwright/Configurations/Base.xcconfig b/Tools/Playwright/Configurations/Base.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..fc61d5227c8608488514cbd92a28dc7c1c2efaf4 --- /dev/null +++ b/Tools/Playwright/Configurations/Base.xcconfig @@ -0,0 +1,87 @@ +// Copyright (C) 2010-2017 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? "../../../../Internal/Configurations/HaveInternalSDK.xcconfig" +#include "SDKVariant.xcconfig" + +USE_INTERNAL_SDK = $(USE_INTERNAL_SDK_$(CONFIGURATION)); +USE_INTERNAL_SDK_Production = YES; +USE_INTERNAL_SDK_Debug = $(HAVE_INTERNAL_SDK); +USE_INTERNAL_SDK_Release = $(HAVE_INTERNAL_SDK); + +GCC_PREPROCESSOR_DEFINITIONS = DISABLE_LEGACY_WEBKIT_DEPRECATIONS $(inherited); + +CLANG_CXX_LANGUAGE_STANDARD = gnu++1z; +CLANG_CXX_LIBRARY = libc++; +CLANG_ENABLE_OBJC_WEAK = YES; +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym; +PREBINDING = NO +GCC_C_LANGUAGE_STANDARD = gnu99 +GCC_ENABLE_CPP_EXCEPTIONS = NO; +GCC_PRECOMPILE_PREFIX_HEADER = YES +ENABLE_STRICT_OBJC_MSGSEND = YES; +GCC_TREAT_WARNINGS_AS_ERRORS = YES +CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; +CLANG_WARN_BOOL_CONVERSION = YES; +CLANG_WARN_COMMA = YES; +CLANG_WARN_CONSTANT_CONVERSION = YES; +CLANG_WARN_EMPTY_BODY = YES; +CLANG_WARN_ENUM_CONVERSION = YES; +CLANG_WARN_INFINITE_RECURSION = YES; +CLANG_WARN_INT_CONVERSION = YES; +CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; +CLANG_WARN_STRICT_PROTOTYPES = YES; +CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; +CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; +CLANG_WARN_SUSPICIOUS_MOVE = YES; +CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; +CLANG_WARN_UNREACHABLE_CODE = YES; +GCC_WARN_64_TO_32_BIT_CONVERSION = YES; +GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO; +GCC_WARN_ABOUT_RETURN_TYPE = YES; +GCC_WARN_UNINITIALIZED_AUTOS = YES; +GCC_WARN_UNUSED_FUNCTION = YES +GCC_WARN_UNUSED_VARIABLE = YES +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; +GCC_WARN_UNDECLARED_SELECTOR = YES; +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; +CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; +GCC_VERSION = com.apple.compilers.llvm.clang.1_0; +WARNING_CFLAGS = -Wall -W -Wno-unused-parameter +GCC_NO_COMMON_BLOCKS = YES; + +SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx tvos tvsimulator watchos watchsimulator; + +TARGET_MAC_OS_X_VERSION_MAJOR = $(TARGET_MAC_OS_X_VERSION_MAJOR$(MACOSX_DEPLOYMENT_TARGET:suffix:identifier)); +TARGET_MAC_OS_X_VERSION_MAJOR_13 = 101300; +TARGET_MAC_OS_X_VERSION_MAJOR_14 = 101400; +TARGET_MAC_OS_X_VERSION_MAJOR_15 = 101500; +TARGET_MAC_OS_X_VERSION_MAJOR_16 = 101600; + +SDKROOT = macosx.internal; + +OTHER_CFLAGS = $(ASAN_OTHER_CFLAGS); +OTHER_CPLUSPLUSFLAGS = $(ASAN_OTHER_CPLUSPLUSFLAGS); +OTHER_LDFLAGS = $(ASAN_OTHER_LDFLAGS); + +CODE_SIGN_IDENTITY = -; diff --git a/Tools/Playwright/Configurations/DebugRelease.xcconfig b/Tools/Playwright/Configurations/DebugRelease.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..44dc1139c298bd119368ef4f45bbf0888dc71cdb --- /dev/null +++ b/Tools/Playwright/Configurations/DebugRelease.xcconfig @@ -0,0 +1,45 @@ +// Copyright (C) 2010, 2013 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 "Base.xcconfig" + +ARCHS = $(ARCHS_STANDARD_32_64_BIT); + +ONLY_ACTIVE_ARCH = YES; + +TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR); + +MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR)) +MACOSX_DEPLOYMENT_TARGET_101300 = 10.13; +MACOSX_DEPLOYMENT_TARGET_101400 = 10.14; +MACOSX_DEPLOYMENT_TARGET_101500 = 10.15; +MACOSX_DEPLOYMENT_TARGET_101600 = 10.16; + +GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; + +SDKROOT = $(SDKROOT_$(USE_INTERNAL_SDK)); +SDKROOT_ = macosx; +SDKROOT_YES = macosx.internal; + +WK_CCACHE_DIR = $(SRCROOT)/../ccache; +#include "../../ccache/ccache.xcconfig" diff --git a/Tools/Playwright/Configurations/Playwright.xcconfig b/Tools/Playwright/Configurations/Playwright.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..d05c841a5b0f5fce481f16b8c98caf3a5846db77 --- /dev/null +++ b/Tools/Playwright/Configurations/Playwright.xcconfig @@ -0,0 +1,30 @@ +// Copyright (C) 2010 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. + +PRODUCT_NAME = Playwright +PRODUCT_BUNDLE_IDENTIFIER = org.webkit.$(PRODUCT_NAME:rfc1034identifier) +GCC_PREFIX_HEADER = mac/Playwright_Prefix.pch +INFOPLIST_FILE = mac/Info.plist +EXCLUDED_SOURCE_FILE_NAMES[sdk=iphone*] = * +OTHER_LDFLAGS[sdk=macosx*] = $(inherited) -framework Cocoa -framework WebKit +STRIP_STYLE = debugging; diff --git a/Tools/Playwright/Configurations/SDKVariant.xcconfig b/Tools/Playwright/Configurations/SDKVariant.xcconfig new file mode 100644 index 0000000000000000000000000000000000000000..fcdf7e65a67c61fb19ef19c428652f336c180e8e --- /dev/null +++ b/Tools/Playwright/Configurations/SDKVariant.xcconfig @@ -0,0 +1,45 @@ +// Copyright (C) 2019 Apple Inc. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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. + +WK_EMPTY_ = YES; +WK_NOT_ = YES; +WK_NOT_YES = NO; + +WK_ALTERNATE_FRAMEWORKS_DIR = $(WK_ALTERNATE_FRAMEWORKS_DIR_$(SDK_VARIANT)); +WK_ALTERNATE_FRAMEWORKS_DIR_iosmac = /System/iOSSupport; +WK_USE_ALTERNATE_FRAMEWORKS_DIR = $(WK_NOT_$(WK_EMPTY_$(WK_ALTERNATE_FRAMEWORKS_DIR))); + +WK_ALTERNATE_PLATFORM_NAME = $(WK_ALTERNATE_PLATFORM_NAME_$(SDK_VARIANT)); +WK_ALTERNATE_PLATFORM_NAME_iosmac = maccatalyst; +WK_USE_ALTERNATE_PLATFORM_NAME = $(WK_NOT_$(WK_EMPTY_$(WK_ALTERNATE_PLATFORM_NAME))); + +WK_ALTERNATE_WEBKIT_SDK_PATH = $(WK_ALTERNATE_WEBKIT_SDK_PATH_$(WK_USE_ALTERNATE_FRAMEWORKS_DIR)); +WK_ALTERNATE_WEBKIT_SDK_PATH_YES = $(WK_ALTERNATE_FRAMEWORKS_DIR)/; + +WK_PLATFORM_NAME = $(WK_PLATFORM_NAME_ALTERNATE_$(WK_USE_ALTERNATE_PLATFORM_NAME)); +WK_PLATFORM_NAME_ALTERNATE_YES = $(WK_ALTERNATE_PLATFORM_NAME); +WK_PLATFORM_NAME_ALTERNATE_NO = $(PLATFORM_NAME); + +EFFECTIVE_PLATFORM_NAME = $(EFFECTIVE_PLATFORM_NAME_ALTERNATE_$(WK_USE_ALTERNATE_PLATFORM_NAME)); +EFFECTIVE_PLATFORM_NAME_ALTERNATE_YES = -$(WK_ALTERNATE_PLATFORM_NAME); +EFFECTIVE_PLATFORM_NAME_ALTERNATE_NO = $(EFFECTIVE_PLATFORM_NAME); diff --git a/Tools/Playwright/MBToolbarItem.h b/Tools/Playwright/MBToolbarItem.h new file mode 100644 index 0000000000000000000000000000000000000000..9971d4c1023a9f6e57c6058ae20729e51bb6d503 --- /dev/null +++ b/Tools/Playwright/MBToolbarItem.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +@interface MBToolbarItem : NSToolbarItem +@end diff --git a/Tools/Playwright/MBToolbarItem.m b/Tools/Playwright/MBToolbarItem.m new file mode 100644 index 0000000000000000000000000000000000000000..56f777891519e820105ae50a86141a534ec4794b --- /dev/null +++ b/Tools/Playwright/MBToolbarItem.m @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "MBToolbarItem.h" + +@implementation MBToolbarItem + +- (void)validate +{ + [self setEnabled:[[self target] validateUserInterfaceItem:self]]; +} + +@end diff --git a/Tools/Playwright/Makefile b/Tools/Playwright/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..58e52428388d927ae7681d999e6dd28e0fb3ec6b --- /dev/null +++ b/Tools/Playwright/Makefile @@ -0,0 +1,21 @@ +# Build Playwright only on SnowLeopard and later. + +OSX_VERSION ?= $(shell sw_vers -productVersion | cut -d. -f 2) +BUILD_PLAYWRIGHT = $(shell (( $(OSX_VERSION) >= 6 )) && echo "YES" ) + +ifeq "$(BUILD_PLAYWRIGHT)" "YES" + +SCRIPTS_PATH = ../Scripts +include ../../Makefile.shared + +else + +all: ; + +debug d development dev develop: ; + +release r deployment dep deploy: ; + +clean: ; + +endif diff --git a/Tools/Playwright/Playwright.xcodeproj/project.pbxproj b/Tools/Playwright/Playwright.xcodeproj/project.pbxproj new file mode 100644 index 0000000000000000000000000000000000000000..75a945e72d9fcad94bb89fc6325df18d3259383d --- /dev/null +++ b/Tools/Playwright/Playwright.xcodeproj/project.pbxproj @@ -0,0 +1,264 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 256AC3DA0F4B6AC300CF336A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF336A /* AppDelegate.m */; }; + 51E244FA11EFCE07008228D2 /* MBToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 51E244F911EFCE07008228D2 /* MBToolbarItem.m */; }; + BC329487116A92E2008635D1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BC329486116A92E2008635D1 /* main.m */; }; + BC329498116A941B008635D1 /* BrowserWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC329497116A941B008635D1 /* BrowserWindowController.m */; }; + BC72B89511E57E07001EB4EB /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58150DA1D0A300B3202A /* MainMenu.xib */; }; + BC72B89611E57E0F001EB4EB /* BrowserWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC3294A2116A9852008635D1 /* BrowserWindow.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1AFFEF761860EE6800DA465F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 1AFFEF781860EE6800DA465F /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 1DDD58150DA1D0A300B3202A /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = mac/MainMenu.xib; sourceTree = ""; }; + 256AC3D80F4B6AC300CF336A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = mac/AppDelegate.h; sourceTree = ""; }; + 256AC3D90F4B6AC300CF336A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = mac/AppDelegate.m; sourceTree = ""; }; + 256AC3F00F4B6AF500CF336A /* Playwright_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Playwright_Prefix.pch; path = mac/Playwright_Prefix.pch; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEB /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 37BAF90620218053000EA87A /* Playwright.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Playwright.entitlements; sourceTree = ""; }; + 51E244F811EFCE07008228D2 /* MBToolbarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBToolbarItem.h; sourceTree = ""; }; + 51E244F911EFCE07008228D2 /* MBToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBToolbarItem.m; sourceTree = ""; }; + 8D1107320486CEB800E47091 /* Playwright.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Playwright.app; sourceTree = BUILT_PRODUCTS_DIR; }; + A1B89B95221E027A00EB4CEB /* SDKVariant.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = SDKVariant.xcconfig; sourceTree = ""; }; + BC329486116A92E2008635D1 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = mac/main.m; sourceTree = ""; }; + BC329496116A941B008635D1 /* BrowserWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BrowserWindowController.h; path = mac/BrowserWindowController.h; sourceTree = ""; }; + BC329497116A941B008635D1 /* BrowserWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BrowserWindowController.m; path = mac/BrowserWindowController.m; sourceTree = ""; }; + BC3294A2116A9852008635D1 /* BrowserWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = BrowserWindow.xib; path = mac/BrowserWindow.xib; sourceTree = ""; }; + BC72B89A11E57E8A001EB4EB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = mac/Info.plist; sourceTree = ""; }; + BCA8CBDD11E578A000812FB8 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = ""; }; + BCA8CBDE11E578A000812FB8 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = ""; }; + BCA8CBDF11E578A000812FB8 /* Playwright.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Playwright.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D11072E0486CEB800E47091 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000002 /* Playwright */ = { + isa = PBXGroup; + children = ( + 256AC3D80F4B6AC300CF336A /* AppDelegate.h */, + 256AC3D90F4B6AC300CF336A /* AppDelegate.m */, + BC72B89A11E57E8A001EB4EB /* Info.plist */, + BC329486116A92E2008635D1 /* main.m */, + 51E244F811EFCE07008228D2 /* MBToolbarItem.h */, + 51E244F911EFCE07008228D2 /* MBToolbarItem.m */, + 37BAF90620218053000EA87A /* Playwright.entitlements */, + BC329496116A941B008635D1 /* BrowserWindowController.h */, + BC329497116A941B008635D1 /* BrowserWindowController.m */, + ); + name = Playwright; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBC /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEB /* AppKit.framework */, + 1AFFEF781860EE6800DA465F /* CoreData.framework */, + 29B97325FDCFA39411CA2CEB /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBC /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47091 /* Playwright.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEB /* Playwright */ = { + isa = PBXGroup; + children = ( + 256AC3F00F4B6AF500CF336A /* Playwright_Prefix.pch */, + 080E96DDFE201D6D7F000002 /* Playwright */, + 29B97317FDCFA39411CA2CEB /* Resources */, + BCA8CBDA11E5787800812FB8 /* Configurations */, + 29B97323FDCFA39411CA2CEB /* Frameworks */, + 19C28FACFE9D520D11CA2CBC /* Products */, + ); + name = Playwright; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEB /* Resources */ = { + isa = PBXGroup; + children = ( + BC3294A2116A9852008635D1 /* BrowserWindow.xib */, + 1DDD58150DA1D0A300B3202A /* MainMenu.xib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEB /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A2FEA54F0111CA2CBC /* Other Frameworks */, + 1AFFEF761860EE6800DA465F /* Cocoa.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + BCA8CBDA11E5787800812FB8 /* Configurations */ = { + isa = PBXGroup; + children = ( + BCA8CBDD11E578A000812FB8 /* Base.xcconfig */, + BCA8CBDE11E578A000812FB8 /* DebugRelease.xcconfig */, + BCA8CBDF11E578A000812FB8 /* Playwright.xcconfig */, + A1B89B95221E027A00EB4CEB /* SDKVariant.xcconfig */, + ); + path = Configurations; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D1107260486CEB800E47091 /* Playwright */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247C /* Build configuration list for PBXNativeTarget "Playwright" */; + buildPhases = ( + 8D1107290486CEB800E47091 /* Resources */, + 8D11072C0486CEB800E47091 /* Sources */, + 8D11072E0486CEB800E47091 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Playwright; + productInstallPath = "$(HOME)/Applications"; + productName = Playwright; + productReference = 8D1107320486CEB800E47091 /* Playwright.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEC /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 1000; + TargetAttributes = { + 8D1107260486CEB800E47091 = { + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + }; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Playwright" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEB /* Playwright */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D1107260486CEB800E47091 /* Playwright */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D1107290486CEB800E47091 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BC72B89611E57E0F001EB4EB /* BrowserWindow.xib in Resources */, + BC72B89511E57E07001EB4EB /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D11072C0486CEB800E47091 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 256AC3DA0F4B6AC300CF336A /* AppDelegate.m in Sources */, + BC329487116A92E2008635D1 /* main.m in Sources */, + 51E244FA11EFCE07008228D2 /* MBToolbarItem.m in Sources */, + BC329498116A941B008635D1 /* BrowserWindowController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + C01FCF4B08A954540054247C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCA8CBDF11E578A000812FB8 /* Playwright.xcconfig */; + buildSettings = { + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCA8CBDF11E578A000812FB8 /* Playwright.xcconfig */; + buildSettings = { + }; + name = Release; + }; + C01FCF4F08A954540054247C /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCA8CBDE11E578A000812FB8 /* DebugRelease.xcconfig */; + buildSettings = { + GCC_OPTIMIZATION_LEVEL = 0; + }; + name = Debug; + }; + C01FCF5008A954540054247C /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = BCA8CBDE11E578A000812FB8 /* DebugRelease.xcconfig */; + buildSettings = { + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C01FCF4A08A954540054247C /* Build configuration list for PBXNativeTarget "Playwright" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247C /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Playwright" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247C /* Debug */, + C01FCF5008A954540054247C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEC /* Project object */; +} diff --git a/Tools/Playwright/Playwright.xcodeproj/xcshareddata/xcschemes/Playwright.xcscheme b/Tools/Playwright/Playwright.xcodeproj/xcshareddata/xcschemes/Playwright.xcscheme new file mode 100644 index 0000000000000000000000000000000000000000..00fb6b0006c743091a8bbf8edb18b21192ea7d6c --- /dev/null +++ b/Tools/Playwright/Playwright.xcodeproj/xcshareddata/xcschemes/Playwright.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/Playwright/mac/AppDelegate.h b/Tools/Playwright/mac/AppDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..86e7b0c64df5fccdd66b87eecd995e0a10d57b83 --- /dev/null +++ b/Tools/Playwright/mac/AppDelegate.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +@interface WebViewDialog : NSObject +@property (nonatomic, strong) WKWebView *webView; +@property (nonatomic, copy) void (^completionHandler)(BOOL accept, NSString* value); +@end + +@interface BrowserAppDelegate : NSObject { + NSMutableSet *_browserWindowControllers; + NSMutableSet *_headlessWindows; + NSMutableSet *_browserContexts; + bool _headless; + bool _noStartupWindow; + NSMutableSet *_dialogs; + NSString* _initialURL; + NSString* _userDataDir; + IBOutlet NSMenuItem *_newWebKit2WindowItem; +} + +- (void)browserWindowWillClose:(NSWindow *)window; + +@end + +@interface NSApplication (PlaywrightApplicationExtensions) + +- (BrowserAppDelegate *)browserAppDelegate; + +@end diff --git a/Tools/Playwright/mac/AppDelegate.m b/Tools/Playwright/mac/AppDelegate.m new file mode 100644 index 0000000000000000000000000000000000000000..144bb42f13cc92a5ddd91417cbef2512613bd27c --- /dev/null +++ b/Tools/Playwright/mac/AppDelegate.m @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "AppDelegate.h" + +#import "BrowserWindowController.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +@implementation NSApplication (PlaywrightApplicationExtensions) + +- (BrowserAppDelegate *)browserAppDelegate +{ + return (BrowserAppDelegate *)[self delegate]; +} + +@end + +@interface NSApplication (TouchBar) +@property (getter=isAutomaticCustomizeTouchBarMenuItemEnabled) BOOL automaticCustomizeTouchBarMenuItemEnabled; + +@property (readonly, nonatomic) WKWebViewConfiguration *defaultConfiguration; + +@end + +@implementation WebViewDialog +- (void)dealloc +{ + [_webView release]; + _webView = nil; + [super dealloc]; +} +@end + +enum { + _NSBackingStoreUnbuffered = 3 +}; + +NSString* const ActivityReason = @"Batch headless process"; +const NSActivityOptions ActivityOptions = + (NSActivityUserInitiatedAllowingIdleSystemSleep | + NSActivityLatencyCritical) & + ~(NSActivitySuddenTerminationDisabled | + NSActivityAutomaticTerminationDisabled); + +@implementation BrowserAppDelegate + +- (id)init +{ + self = [super init]; + if (!self) + return nil; + + _initialURL = nil; + _userDataDir = nil; + NSArray *arguments = [[NSProcessInfo processInfo] arguments]; + NSRange subargs = NSMakeRange(1, [arguments count] - 1); + NSArray *subArray = [arguments subarrayWithRange:subargs]; + + for (NSString *argument in subArray) { + if (![argument hasPrefix:@"--"]) + _initialURL = argument; + if ([argument hasPrefix:@"--user-data-dir="]) { + NSRange range = NSMakeRange(16, [argument length] - 16); + _userDataDir = [[argument substringWithRange:range] copy]; + } + } + + _headless = [arguments containsObject: @"--headless"]; + _noStartupWindow = [arguments containsObject: @"--no-startup-window"]; + _browserContexts = [[NSMutableSet alloc] init]; + + if (_headless) { + _headlessWindows = [[NSMutableSet alloc] init]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; + [[NSProcessInfo processInfo] beginActivityWithOptions:ActivityOptions + reason:ActivityReason]; + _dialogs = [[NSMutableSet alloc] init]; + } else { + [NSApp activateIgnoringOtherApps:YES]; + _browserWindowControllers = [[NSMutableSet alloc] init]; + } + if ([arguments containsObject: @"--inspector-pipe"]) + [_WKBrowserInspector initializeRemoteInspectorPipe:self headless:_headless]; + return self; +} + +- (void)awakeFromNib +{ + if ([NSApp respondsToSelector:@selector(setAutomaticCustomizeTouchBarMenuItemEnabled:)]) + [NSApp setAutomaticCustomizeTouchBarMenuItemEnabled:YES]; +} + +- (WKWebsiteDataStore *)persistentDataStore +{ + static WKWebsiteDataStore *dataStore; + + if (!dataStore) { + _WKWebsiteDataStoreConfiguration *configuration = [[[_WKWebsiteDataStoreConfiguration alloc] init] autorelease]; + if (_userDataDir) { + NSURL *cookieFile = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/cookie.db", _userDataDir]]; + [configuration _setCookieStorageFile:cookieFile]; + + NSURL *applicationCacheDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/ApplicationCache", _userDataDir]]; + [configuration setApplicationCacheDirectory:applicationCacheDirectory]; + + NSURL *cacheStorageDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/CacheStorage", _userDataDir]]; + [configuration _setCacheStorageDirectory:cacheStorageDirectory]; + + NSURL *indexedDBDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/IndexedDB", _userDataDir]]; + [configuration _setIndexedDBDatabaseDirectory:indexedDBDirectory]; + + NSURL *localStorageDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/LocalStorage", _userDataDir]]; + [configuration _setWebStorageDirectory:localStorageDirectory]; + + NSURL *mediaCacheDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/MediaCache", _userDataDir]]; + [configuration setMediaCacheDirectory:mediaCacheDirectory]; + + NSURL *mediaKeysDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/MediaKeys", _userDataDir]]; + [configuration setMediaKeysStorageDirectory:mediaKeysDirectory]; + + NSURL *networkCacheDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/NetworkCache", _userDataDir]]; + [configuration setNetworkCacheDirectory:networkCacheDirectory]; + + NSURL *loadStatsDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/ResourceLoadStatistics", _userDataDir]]; + [configuration _setResourceLoadStatisticsDirectory:loadStatsDirectory]; + + NSURL *serviceWorkersDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/ServiceWorkers", _userDataDir]]; + [configuration _setServiceWorkerRegistrationDirectory:serviceWorkersDirectory]; + + NSURL *webSqlDirectory = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/WebSQL", _userDataDir]]; + [configuration _setWebSQLDatabaseDirectory:webSqlDirectory]; + } + dataStore = [[WKWebsiteDataStore alloc] _initWithConfiguration:configuration]; + } + + return dataStore; +} + +- (WKWebViewConfiguration *)defaultConfiguration +{ + static WKWebViewConfiguration *configuration; + + if (!configuration) { + configuration = [[WKWebViewConfiguration alloc] init]; + configuration.websiteDataStore = [self persistentDataStore]; + configuration.preferences._fullScreenEnabled = YES; + configuration.preferences._developerExtrasEnabled = YES; + configuration.preferences._mediaDevicesEnabled = YES; + configuration.preferences._mockCaptureDevicesEnabled = YES; + configuration.preferences._hiddenPageDOMTimerThrottlingEnabled = NO; + configuration.preferences._hiddenPageDOMTimerThrottlingAutoIncreases = NO; + configuration.preferences._pageVisibilityBasedProcessSuppressionEnabled = NO; + configuration.preferences._domTimersThrottlingEnabled = NO; + configuration.preferences._requestAnimationFrameEnabled = YES; + _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease]; + processConfiguration.forceOverlayScrollbars = YES; + configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration AndDataStore:configuration.websiteDataStore] autorelease]; + } + return configuration; +} + +- (BrowserWindowController *)createBrowserWindowController:(id)sender +{ + if (_headless) + return nil; + + BrowserWindowController *controller = [[[BrowserWindowController alloc] initWithConfiguration:[self defaultConfiguration]] autorelease]; + if (!controller) + return nil; + [_browserWindowControllers addObject:controller]; + return controller; +} + +- (void)browserWindowWillClose:(NSWindow *)window +{ + [_browserWindowControllers removeObject:window.windowController]; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + if (!_headless) + [self _updateNewWindowKeyEquivalents]; + + if (_noStartupWindow) + return; + + [self createNewPage:0]; + _initialURL = nil; +} + +- (BrowserWindowController *)frontmostBrowserWindowController +{ + for (NSWindow* window in [NSApp windows]) { + id delegate = [window delegate]; + + if (![delegate isKindOfClass:[BrowserWindowController class]]) + continue; + + BrowserWindowController *controller = (BrowserWindowController *)delegate; + assert([_browserWindowControllers containsObject:controller]); + return controller; + } + + return nil; +} + +- (void)_updateNewWindowKeyEquivalents +{ + NSString *normalWindowEquivalent = @"n"; + _newWebKit2WindowItem.keyEquivalentModifierMask = NSEventModifierFlagCommand; + _newWebKit2WindowItem.keyEquivalent = normalWindowEquivalent; +} + +#pragma mark WKBrowserInspectorDelegate + +- (WKWebViewConfiguration *) sessionConfiguration:(uint64_t)sessionID +{ + for (_WKBrowserContext *browserContext in _browserContexts) { + if ([[browserContext dataStore] sessionID] != sessionID) + continue; + WKWebViewConfiguration *configuration = [[[self defaultConfiguration] copy] autorelease]; + configuration.websiteDataStore = [browserContext dataStore]; + configuration.processPool = [browserContext processPool]; + return configuration; + } + return [self defaultConfiguration]; +} + +- (WKWebView *)createNewPage:(uint64_t)sessionID +{ + NSString* urlString = _initialURL ? _initialURL : @"about:blank"; + WKWebViewConfiguration *configuration = [self sessionConfiguration:sessionID]; + if (_headless) + return [self createHeadlessPage:configuration withURL:urlString]; + return [self createHeadfulPage:configuration withURL:urlString]; +} + +- (WKWebView *)createHeadfulPage:(WKWebViewConfiguration *)configuration withURL:(NSString*)urlString +{ + + BrowserWindowController *controller = [[[BrowserWindowController alloc] initWithConfiguration:configuration] autorelease]; + if (!controller) + return nil; + [[controller window] makeKeyAndOrderFront:nil]; + [_browserWindowControllers addObject:controller]; + [controller loadURLString:urlString]; + return [controller webView]; +} + +- (WKWebView *)createHeadlessPage:(WKWebViewConfiguration *)configuration withURL:(NSString*)urlString +{ + NSRect rect = NSMakeRect(0, 0, 1024, 768); + NSScreen *firstScreen = [[NSScreen screens] objectAtIndex:0]; + NSRect windowRect = NSOffsetRect(rect, -10000, [firstScreen frame].size.height - rect.size.height + 10000); + NSWindow* window = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSWindowStyleMaskBorderless backing:(NSBackingStoreType)_NSBackingStoreUnbuffered defer:YES]; + + WKWebView* webView = [[WKWebView alloc] initWithFrame:[window.contentView bounds] configuration:configuration]; + webView._windowOcclusionDetectionEnabled = NO; + if (!webView) + return nil; + + webView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [window.contentView addSubview:webView]; + if (urlString) { + NSURL *url = [NSURL _webkit_URLWithUserTypedString:urlString]; + [webView loadRequest:[NSURLRequest requestWithURL:url]]; + } + [_headlessWindows addObject:window]; + webView.UIDelegate = self; + return [webView autorelease]; +} + +- (_WKBrowserContext *)createBrowserContext +{ + _WKBrowserContext *browserContext = [[_WKBrowserContext alloc] init]; + _WKProcessPoolConfiguration *processConfiguration = [[[_WKProcessPoolConfiguration alloc] init] autorelease]; + processConfiguration.forceOverlayScrollbars = YES; + browserContext.dataStore = [WKWebsiteDataStore nonPersistentDataStore]; + browserContext.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease]; + [_browserContexts addObject:browserContext]; + return browserContext; +} + +- (void)deleteBrowserContext:(uint64_t)sessionID +{ + for (_WKBrowserContext *browserContext in _browserContexts) { + if ([[browserContext dataStore] sessionID] != sessionID) + continue; + [_browserContexts removeObject:browserContext]; + return; + } +} + +- (void)quit +{ + [NSApp performSelector:@selector(terminate:) withObject:nil afterDelay:0.0]; +} + +#pragma mark WKUIDelegate + +- (void)webViewDidClose:(WKWebView *)webView { + for (NSWindow *window in _headlessWindows) { + if (webView.window != window) + continue; + [webView removeFromSuperview]; + [window close]; + [_headlessWindows removeObject:window]; + break; + } +} + +- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(); + }; + [_dialogs addObject:dialog]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(accept); + }; + [_dialogs addObject:dialog]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(accept && value ? value : nil); + }; + [_dialogs addObject:dialog]; +} + +- (void)_webView:(WKWebView *)webView runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler +{ + WebViewDialog* dialog = [[WebViewDialog alloc] autorelease]; + dialog.webView = webView; + dialog.completionHandler = ^void (BOOL accept, NSString* value) { + completionHandler(accept); + }; + [_dialogs addObject:dialog]; +} + +- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(NSString *)value +{ + for (WebViewDialog *dialog in _dialogs) { + if (dialog.webView != webView) + continue; + dialog.completionHandler(accept, value); + [_dialogs removeObject:dialog]; + break; + } +} + +- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures +{ + return [self createHeadlessPage:configuration withURL:nil]; +} + +@end diff --git a/Tools/Playwright/mac/BrowserWindow.xib b/Tools/Playwright/mac/BrowserWindow.xib new file mode 100644 index 0000000000000000000000000000000000000000..f6f3d8e3a0f163e61b2f3d54819e9d25a0a3eb75 --- /dev/null +++ b/Tools/Playwright/mac/BrowserWindow.xib @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/Playwright/mac/BrowserWindowController.h b/Tools/Playwright/mac/BrowserWindowController.h new file mode 100644 index 0000000000000000000000000000000000000000..4dbf13c8fb31a745ae8e1965a457d4fbcd8e5866 --- /dev/null +++ b/Tools/Playwright/mac/BrowserWindowController.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +@class WKWebView; + +@interface BrowserWindowController : NSWindowController + +- (IBAction)goBack:(id)sender; +- (IBAction)goForward:(id)sender; +- (IBAction)reload:(id)sender; +- (IBAction)saveAsPDF:(id)sender; +- (IBAction)saveAsWebArchive:(id)sender; +- (IBAction)zoomIn:(id)sender; +- (IBAction)zoomOut:(id)sender; +- (IBAction)resetZoom:(id)sender; +- (IBAction)showHideWebInspector:(id)sender; + +- (IBAction)setPageScale:(id)sender; +- (IBAction)setViewScale:(id)sender; +- (instancetype)initWithConfiguration:(WKWebViewConfiguration *)configuration; +- (void)loadURLString:(NSString *)urlString; +- (WKWebView *)webView; + +@end diff --git a/Tools/Playwright/mac/BrowserWindowController.m b/Tools/Playwright/mac/BrowserWindowController.m new file mode 100644 index 0000000000000000000000000000000000000000..72edf5c432f58659765d16dabdb536b44942b1f2 --- /dev/null +++ b/Tools/Playwright/mac/BrowserWindowController.m @@ -0,0 +1,828 @@ +/* + * Copyright (C) 2010-2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "BrowserWindowController.h" + +#import "AppDelegate.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +static void* keyValueObservingContext = &keyValueObservingContext; + +@interface PlaywrightNSTextFinder : NSTextFinder + +@property (nonatomic, copy) dispatch_block_t hideInterfaceCallback; + +@end + +@implementation PlaywrightNSTextFinder + +- (void)performAction:(NSTextFinderAction)op +{ + [super performAction:op]; + + if (op == NSTextFinderActionHideFindInterface && _hideInterfaceCallback) + _hideInterfaceCallback(); +} + +@end + +@interface BrowserWindowController () +@end + +@implementation BrowserWindowController { + IBOutlet NSProgressIndicator *progressIndicator; + IBOutlet NSButton *reloadButton; + IBOutlet NSButton *backButton; + IBOutlet NSButton *forwardButton; + IBOutlet NSButton *share; + IBOutlet NSToolbar *toolbar; + IBOutlet NSTextField *urlText; + IBOutlet NSView *containerView; + IBOutlet NSButton *toggleUseShrinkToFitButton; + + WKWebViewConfiguration *_configuration; + WKWebView *_webView; + BOOL _zoomTextOnly; + BOOL _isPrivateBrowsingWindow; + NSAlert* _alert; + + BOOL _useShrinkToFit; + + PlaywrightNSTextFinder *_textFinder; + NSView *_textFindBarView; + BOOL _findBarVisible; +} + +- (id)initWithWindow:(NSWindow *)window +{ + self = [super initWithWindow:window]; + return self; +} + +- (void)windowDidLoad +{ + [share sendActionOn:NSEventMaskLeftMouseDown]; + [super windowDidLoad]; +} + +- (IBAction)openLocation:(id)sender +{ + [[self window] makeFirstResponder:urlText]; +} + +- (NSString *)addProtocolIfNecessary:(NSString *)address +{ + if ([address rangeOfString:@"://"].length > 0) + return address; + + if ([address hasPrefix:@"data:"]) + return address; + + if ([address hasPrefix:@"about:"]) + return address; + + return [@"http://" stringByAppendingString:address]; +} + +- (IBAction)share:(id)sender +{ + NSSharingServicePicker *picker = [[NSSharingServicePicker alloc] initWithItems:@[ self.currentURL ]]; + picker.delegate = self; + [picker showRelativeToRect:NSZeroRect ofView:sender preferredEdge:NSRectEdgeMinY]; +} + +- (IBAction)showHideWebView:(id)sender +{ + self.mainContentView.hidden = !self.mainContentView.isHidden; +} + +- (CGFloat)pageScaleForMenuItemTag:(NSInteger)tag +{ + if (tag == 1) + return 1; + if (tag == 2) + return 1.25; + if (tag == 3) + return 1.5; + if (tag == 4) + return 2.0; + + return 1; +} + +- (void)awakeFromNib +{ + _webView = [[WKWebView alloc] initWithFrame:[containerView bounds] configuration:_configuration]; + _webView._windowOcclusionDetectionEnabled = NO; + + _webView.allowsMagnification = YES; + _webView.allowsBackForwardNavigationGestures = YES; + + [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + [containerView addSubview:_webView]; + + [progressIndicator bind:NSHiddenBinding toObject:_webView withKeyPath:@"loading" options:@{ NSValueTransformerNameBindingOption : NSNegateBooleanTransformerName }]; + [progressIndicator bind:NSValueBinding toObject:_webView withKeyPath:@"estimatedProgress" options:nil]; + + [_webView addObserver:self forKeyPath:@"title" options:0 context:keyValueObservingContext]; + [_webView addObserver:self forKeyPath:@"URL" options:0 context:keyValueObservingContext]; + + _webView.navigationDelegate = self; + _webView.UIDelegate = self; + + _webView._observedRenderingProgressEvents = _WKRenderingProgressEventFirstLayout + | _WKRenderingProgressEventFirstVisuallyNonEmptyLayout + | _WKRenderingProgressEventFirstPaintWithSignificantArea + | _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering + | _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering; + + _webView.customUserAgent = @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.4 Safari/605.1.15"; + + _webView._usePlatformFindUI = NO; + + _textFinder = [[PlaywrightNSTextFinder alloc] init]; + _textFinder.incrementalSearchingEnabled = YES; + _textFinder.incrementalSearchingShouldDimContentView = NO; + _textFinder.client = _webView; + _textFinder.findBarContainer = self; + _textFinder.hideInterfaceCallback = ^{ + [_webView _hideFindUI]; + }; + + _zoomTextOnly = NO; +} + +- (instancetype)initWithConfiguration:(WKWebViewConfiguration *)configuration +{ + if (!(self = [super initWithWindowNibName:@"BrowserWindow"])) + return nil; + _configuration = [configuration copy]; + _isPrivateBrowsingWindow = !_configuration.websiteDataStore.isPersistent; + self.window.styleMask &= ~NSWindowStyleMaskFullSizeContentView; + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [progressIndicator unbind:NSHiddenBinding]; + [progressIndicator unbind:NSValueBinding]; + + [_textFinder release]; + [_webView release]; + [_configuration release]; + + [super dealloc]; +} + +- (IBAction)fetch:(id)sender +{ + [urlText setStringValue:[self addProtocolIfNecessary:urlText.stringValue]]; + NSURL *url = [NSURL _webkit_URLWithUserTypedString:urlText.stringValue]; + [_webView loadRequest:[NSURLRequest requestWithURL:url]]; +} + +- (IBAction)setPageScale:(id)sender +{ + CGFloat scale = [self pageScaleForMenuItemTag:[sender tag]]; + [_webView _setPageScale:scale withOrigin:CGPointZero]; +} + +- (CGFloat)viewScaleForMenuItemTag:(NSInteger)tag +{ + if (tag == 1) + return 1; + if (tag == 2) + return 0.75; + if (tag == 3) + return 0.5; + if (tag == 4) + return 0.25; + + return 1; +} + +- (IBAction)setViewScale:(id)sender +{ + CGFloat scale = [self viewScaleForMenuItemTag:[sender tag]]; + CGFloat oldScale = [_webView _viewScale]; + + if (scale == oldScale) + return; + + [_webView _setLayoutMode:_WKLayoutModeDynamicSizeComputedFromViewScale]; + + NSRect oldFrame = self.window.frame; + NSSize newFrameSize = NSMakeSize(oldFrame.size.width * (scale / oldScale), oldFrame.size.height * (scale / oldScale)); + [self.window setFrame:NSMakeRect(oldFrame.origin.x, oldFrame.origin.y - (newFrameSize.height - oldFrame.size.height), newFrameSize.width, newFrameSize.height) display:NO animate:NO]; + + [_webView _setViewScale:scale]; +} + +static BOOL areEssentiallyEqual(double a, double b) +{ + double tolerance = 0.001; + return (fabs(a - b) <= tolerance); +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-implementations" +- (BOOL)validateMenuItem:(NSMenuItem *)menuItem +#pragma GCC diagnostic pop +{ + SEL action = menuItem.action; + + if (action == @selector(saveAsPDF:)) + return YES; + if (action == @selector(saveAsWebArchive:)) + return YES; + + if (action == @selector(zoomIn:)) + return [self canZoomIn]; + if (action == @selector(zoomOut:)) + return [self canZoomOut]; + if (action == @selector(resetZoom:)) + return [self canResetZoom]; + + if (action == @selector(toggleZoomMode:)) + [menuItem setState:_zoomTextOnly ? NSControlStateValueOn : NSControlStateValueOff]; + else if (action == @selector(showHideWebInspector:)) + [menuItem setTitle:_webView._inspector.isVisible ? @"Close Web Inspector" : @"Show Web Inspector"]; + + if (action == @selector(setPageScale:)) + [menuItem setState:areEssentiallyEqual([_webView _pageScale], [self pageScaleForMenuItemTag:[menuItem tag]])]; + + if (action == @selector(setViewScale:)) + [menuItem setState:areEssentiallyEqual([_webView _viewScale], [self viewScaleForMenuItemTag:[menuItem tag]])]; + + return YES; +} + +- (IBAction)reload:(id)sender +{ + [_webView reload]; +} + +- (IBAction)goBack:(id)sender +{ + [_webView goBack]; +} + +- (IBAction)goForward:(id)sender +{ + [_webView goForward]; +} + +- (IBAction)toggleZoomMode:(id)sender +{ + if (_zoomTextOnly) { + _zoomTextOnly = NO; + double currentTextZoom = _webView._textZoomFactor; + _webView._textZoomFactor = 1; + _webView.pageZoom = currentTextZoom; + } else { + _zoomTextOnly = YES; + double currentPageZoom = _webView._pageZoomFactor; + _webView._textZoomFactor = currentPageZoom; + _webView.pageZoom = 1; + } +} + +- (IBAction)resetZoom:(id)sender +{ + if (![self canResetZoom]) + return; + + if (_zoomTextOnly) + _webView._textZoomFactor = 1; + else + _webView.pageZoom = 1; +} + +- (BOOL)canResetZoom +{ + return _zoomTextOnly ? (_webView._textZoomFactor != 1) : (_webView.pageZoom != 1); +} + +- (IBAction)showHideWebInspector:(id)sender +{ + _WKInspector *inspector = _webView._inspector; + if (inspector.isVisible) + [inspector hide]; + else + [inspector show]; +} + +- (NSURL *)currentURL +{ + return _webView.URL; +} + +- (NSView *)mainContentView +{ + return _webView; +} + +- (BOOL)validateUserInterfaceItem:(id )item +{ + SEL action = item.action; + + if (action == @selector(goBack:) || action == @selector(goForward:)) + return [_webView validateUserInterfaceItem:item]; + + return YES; +} + +- (void)validateToolbar +{ + [toolbar validateVisibleItems]; +} + +- (BOOL)windowShouldClose:(id)sender +{ + return YES; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + [[[NSApplication sharedApplication] browserAppDelegate] browserWindowWillClose:self.window]; + [_webView removeObserver:self forKeyPath:@"title"]; + [_webView removeObserver:self forKeyPath:@"URL"]; + [self autorelease]; +} + +- (void)webViewDidClose:(WKWebView *)webView { + [self.window close]; +} + +#define DefaultMinimumZoomFactor (.5) +#define DefaultMaximumZoomFactor (3.0) +#define DefaultZoomFactorRatio (1.2) + +- (CGFloat)currentZoomFactor +{ + return _zoomTextOnly ? _webView._textZoomFactor : _webView.pageZoom; +} + +- (void)setCurrentZoomFactor:(CGFloat)factor +{ + if (_zoomTextOnly) + _webView._textZoomFactor = factor; + else + _webView.pageZoom = factor; +} + +- (BOOL)canZoomIn +{ + return self.currentZoomFactor * DefaultZoomFactorRatio < DefaultMaximumZoomFactor; +} + +- (void)zoomIn:(id)sender +{ + if (!self.canZoomIn) + return; + + self.currentZoomFactor *= DefaultZoomFactorRatio; +} + +- (BOOL)canZoomOut +{ + return self.currentZoomFactor / DefaultZoomFactorRatio > DefaultMinimumZoomFactor; +} + +- (void)zoomOut:(id)sender +{ + if (!self.canZoomIn) + return; + + self.currentZoomFactor /= DefaultZoomFactorRatio; +} + +- (void)updateTitle:(NSString *)title +{ + if (!title) { + NSURL *url = _webView.URL; + title = url.lastPathComponent ?: url._web_userVisibleString; + } + + self.window.title = [NSString stringWithFormat:@"%@%@ [%d]%@", _isPrivateBrowsingWindow ? @"🙈 " : @"", title, _webView._webProcessIdentifier, @""]; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if (context != keyValueObservingContext || object != _webView) + return; + + if ([keyPath isEqualToString:@"title"]) + [self updateTitle:_webView.title]; + else if ([keyPath isEqualToString:@"URL"]) + [self updateTextFieldFromURL:_webView.URL]; +} + +- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures +{ + BrowserWindowController *controller = [[BrowserWindowController alloc] initWithConfiguration:configuration]; + [controller.window makeKeyAndOrderFront:self]; + + return controller->_webView; +} + +- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler +{ + NSAlert* alert = [[NSAlert alloc] init]; + + [alert setMessageText:[NSString stringWithFormat:@"JavaScript alert dialog from %@.", [frame.request.URL absoluteString]]]; + [alert setInformativeText:message]; + [alert addButtonWithTitle:@"OK"]; + + _alert = alert; + [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { + completionHandler(); + [alert release]; + _alert = nil; + }]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler +{ + NSAlert* alert = [[NSAlert alloc] init]; + + [alert setMessageText:[NSString stringWithFormat:@"JavaScript confirm dialog from %@.", [frame.request.URL absoluteString]]]; + [alert setInformativeText:message]; + + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + + _alert = alert; + [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { + completionHandler(response == NSAlertFirstButtonReturn); + [alert release]; + _alert = nil; + }]; +} + +- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler +{ + NSAlert* alert = [[NSAlert alloc] init]; + + [alert setMessageText:[NSString stringWithFormat:@"JavaScript prompt dialog from %@.", [frame.request.URL absoluteString]]]; + [alert setInformativeText:prompt]; + + [alert addButtonWithTitle:@"OK"]; + [alert addButtonWithTitle:@"Cancel"]; + + NSTextField* input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)]; + [input setStringValue:defaultText]; + [alert setAccessoryView:input]; + + _alert = alert; + [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { + [input validateEditing]; + completionHandler(response == NSAlertFirstButtonReturn ? [input stringValue] : nil); + [alert release]; + _alert = nil; + }]; +} + +- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(NSString *)value +{ + if (!_alert) + return; + NSTextField* input = (NSTextField*)_alert.accessoryView; + if (accept && input && value) + [input setStringValue:value]; + [self.window endSheet:_alert.window returnCode: accept ? NSAlertFirstButtonReturn : NSModalResponseCancel]; +} + +#if __has_feature(objc_generics) +- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray * URLs))completionHandler +#else +- (void)webView:(WKWebView *)webView runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSArray *URLs))completionHandler +#endif +{ + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + + openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection; + + [openPanel beginSheetModalForWindow:webView.window completionHandler:^(NSInteger result) { + if (result == NSModalResponseOK) + completionHandler(openPanel.URLs); + else + completionHandler(nil); + }]; +} + +- (void)_webView:(WebView *)sender runBeforeUnloadConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler +{ + NSAlert *alert = [[NSAlert alloc] init]; + + alert.messageText = [NSString stringWithFormat:@"JavaScript before unload dialog from %@.", [frame.request.URL absoluteString]]; + alert.informativeText = message; + + [alert addButtonWithTitle:@"Leave Page"]; + [alert addButtonWithTitle:@"Stay On Page"]; + + _alert = alert; + [alert beginSheetModalForWindow:self.window completionHandler:^void (NSModalResponse response) { + completionHandler(response == NSAlertFirstButtonReturn); + [alert release]; + _alert = nil; + }]; +} + +- (WKDragDestinationAction)_webView:(WKWebView *)webView dragDestinationActionMaskForDraggingInfo:(id)draggingInfo +{ + return WKDragDestinationActionAny; +} + +- (void)updateTextFieldFromURL:(NSURL *)URL +{ + if (!URL) + return; + + if (!URL.absoluteString.length) + return; + + urlText.stringValue = [URL _web_userVisibleString]; +} + +- (void)loadURLString:(NSString *)urlString +{ + // FIXME: We shouldn't have to set the url text here. + [urlText setStringValue:urlString]; + [self fetch:nil]; +} + +- (void)loadHTMLString:(NSString *)HTMLString +{ + [_webView loadHTMLString:HTMLString baseURL:nil]; +} + +static NSSet *dataTypes() +{ + return [WKWebsiteDataStore allWebsiteDataTypes]; +} + +- (IBAction)fetchWebsiteData:(id)sender +{ + [_configuration.websiteDataStore _fetchDataRecordsOfTypes:dataTypes() withOptions:_WKWebsiteDataStoreFetchOptionComputeSizes completionHandler:^(NSArray *websiteDataRecords) { + NSLog(@"did fetch website data %@.", websiteDataRecords); + }]; +} + +- (IBAction)fetchAndClearWebsiteData:(id)sender +{ + [_configuration.websiteDataStore fetchDataRecordsOfTypes:dataTypes() completionHandler:^(NSArray *websiteDataRecords) { + [_configuration.websiteDataStore removeDataOfTypes:dataTypes() forDataRecords:websiteDataRecords completionHandler:^{ + [_configuration.websiteDataStore fetchDataRecordsOfTypes:dataTypes() completionHandler:^(NSArray *websiteDataRecords) { + NSLog(@"did clear website data, after clearing data is %@.", websiteDataRecords); + }]; + }]; + }]; +} + +- (IBAction)clearWebsiteData:(id)sender +{ + [_configuration.websiteDataStore removeDataOfTypes:dataTypes() modifiedSince:[NSDate distantPast] completionHandler:^{ + NSLog(@"Did clear website data."); + }]; +} + +- (IBAction)printWebView:(id)sender +{ + [[_webView printOperationWithPrintInfo:[NSPrintInfo sharedPrintInfo]] runOperationModalForWindow:self.window delegate:nil didRunSelector:nil contextInfo:nil]; +} + +#pragma mark WKNavigationDelegate + +- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler +{ + LOG(@"decidePolicyForNavigationAction"); + + if (navigationAction._canHandleRequest) { + decisionHandler(WKNavigationActionPolicyAllow); + return; + } + decisionHandler(WKNavigationActionPolicyCancel); +} + +- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler +{ + LOG(@"decidePolicyForNavigationResponse"); + decisionHandler(WKNavigationResponsePolicyAllow); +} + +- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation +{ + LOG(@"didStartProvisionalNavigation: %@", navigation); +} + +- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation +{ + LOG(@"didReceiveServerRedirectForProvisionalNavigation: %@", navigation); +} + +- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error +{ + LOG(@"didFailProvisionalNavigation: %@navigation, error: %@", navigation, error); +} + +- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation +{ + LOG(@"didCommitNavigation: %@", navigation); + [self updateTitle:nil]; +} + +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation +{ + LOG(@"didFinishNavigation: %@", navigation); +} + +- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *__nullable credential))completionHandler +{ + LOG(@"didReceiveAuthenticationChallenge: %@", challenge); + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic]) { + NSAlert *alert = [[NSAlert alloc] init]; + NSView *container = [[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 48)] autorelease]; + NSTextField *userInput = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 24, 200, 24)] autorelease]; + NSTextField *passwordInput = [[[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)] autorelease]; + + [alert setMessageText:[NSString stringWithFormat:@"Log in to %@:%lu.", challenge.protectionSpace.host, challenge.protectionSpace.port]]; + [alert addButtonWithTitle:@"Log in"]; + [alert addButtonWithTitle:@"Cancel"]; + [container addSubview:userInput]; + [container addSubview:passwordInput]; + [alert setAccessoryView:container]; + [userInput setNextKeyView:passwordInput]; + [alert.window setInitialFirstResponder:userInput]; + + [alert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse response) { + [userInput validateEditing]; + if (response == NSAlertFirstButtonReturn) + completionHandler(NSURLSessionAuthChallengeUseCredential, [[[NSURLCredential alloc] initWithUser:[userInput stringValue] password:[passwordInput stringValue] persistence:NSURLCredentialPersistenceForSession] autorelease]); + else + completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil); + [alert release]; + }]; + return; + } + completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil); +} + +- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error +{ + LOG(@"didFailNavigation: %@, error %@", navigation, error); +} + +- (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView +{ + NSLog(@"WebContent process crashed; reloading"); + [self reload:nil]; +} + +- (void)_webView:(WKWebView *)webView renderingProgressDidChange:(_WKRenderingProgressEvents)progressEvents +{ + if (progressEvents & _WKRenderingProgressEventFirstLayout) + LOG(@"renderingProgressDidChange: %@", @"first layout"); + + if (progressEvents & _WKRenderingProgressEventFirstVisuallyNonEmptyLayout) + LOG(@"renderingProgressDidChange: %@", @"first visually non-empty layout"); + + if (progressEvents & _WKRenderingProgressEventFirstPaintWithSignificantArea) + LOG(@"renderingProgressDidChange: %@", @"first paint with significant area"); + + if (progressEvents & _WKRenderingProgressEventFirstLayoutAfterSuppressedIncrementalRendering) + LOG(@"renderingProgressDidChange: %@", @"first layout after suppressed incremental rendering"); + + if (progressEvents & _WKRenderingProgressEventFirstPaintAfterSuppressedIncrementalRendering) + LOG(@"renderingProgressDidChange: %@", @"first paint after suppressed incremental rendering"); +} + +- (void)webView:(WKWebView *)webView shouldLoadIconWithParameters:(_WKLinkIconParameters *)parameters completionHandler:(void (^)(void (^)(NSData*)))completionHandler +{ + completionHandler(^void (NSData *data) { + LOG(@"Icon URL %@ received icon data of length %u", parameters.url, (unsigned)data.length); + }); +} + +#pragma mark Find in Page + +- (IBAction)performTextFinderAction:(id)sender +{ + [_textFinder performAction:[sender tag]]; +} + +- (NSView *)findBarView +{ + return _textFindBarView; +} + +- (void)setFindBarView:(NSView *)findBarView +{ + _textFindBarView = findBarView; + _findBarVisible = YES; + [_textFindBarView setFrame:NSMakeRect(0, 0, containerView.bounds.size.width, _textFindBarView.frame.size.height)]; +} + +- (BOOL)isFindBarVisible +{ + return _findBarVisible; +} + +- (void)setFindBarVisible:(BOOL)findBarVisible +{ + _findBarVisible = findBarVisible; + if (findBarVisible) + [containerView addSubview:_textFindBarView]; + else + [_textFindBarView removeFromSuperview]; +} + +- (NSView *)contentView +{ + return _webView; +} + +- (void)findBarViewDidChangeHeight +{ +} + +- (void)_webView:(WKWebView *)webView requestMediaCaptureAuthorization: (_WKCaptureDevices)devices decisionHandler:(void (^)(BOOL authorized))decisionHandler +{ + decisionHandler(true); +} + +- (void)_webView:(WKWebView *)webView includeSensitiveMediaDeviceDetails:(void (^)(BOOL includeSensitiveDetails))decisionHandler +{ + decisionHandler(false); +} + +- (IBAction)saveAsPDF:(id)sender +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + panel.allowedFileTypes = @[ @"pdf" ]; + [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { + if (result == NSModalResponseOK) { + [_webView createPDFWithConfiguration:nil completionHandler:^(NSData *pdfSnapshotData, NSError *error) { + [pdfSnapshotData writeToURL:[panel URL] options:0 error:nil]; + }]; + } + }]; +} + +- (IBAction)saveAsWebArchive:(id)sender +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + panel.allowedFileTypes = @[ @"webarchive" ]; + [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { + if (result == NSModalResponseOK) { + [_webView createWebArchiveDataWithCompletionHandler:^(NSData *archiveData, NSError *error) { + [archiveData writeToURL:[panel URL] options:0 error:nil]; + }]; + } + }]; +} + +- (WKWebView *)webView +{ + return _webView; +} + +@end diff --git a/Tools/Playwright/mac/CMakeLists.txt b/Tools/Playwright/mac/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..410d47425b79367114b17274355350894a70a5e6 --- /dev/null +++ b/Tools/Playwright/mac/CMakeLists.txt @@ -0,0 +1,43 @@ +set(PLAYWRIGHT_DIR "${TOOLS_DIR}/Playwright/mac") + +#FIXME: This should not need WEBCORE_EXPORT defined. This means we are including WebCore headers, and we should not. +add_definitions("-include Playwright_Prefix.pch -DWEBCORE_EXPORT=") + +set(Playwright_SOURCES + ${PLAYWRIGHT_DIR}/AppDelegate.m + ${PLAYWRIGHT_DIR}/BrowserWindowController.m + ${PLAYWRIGHT_DIR}/main.m + ${TOOLS_DIR}/Playwright/MBToolbarItem.m +) + +set(Playwright_INCLUDE_DIRECTORIES + ${CMAKE_SOURCE_DIR}/Source + ${FORWARDING_HEADERS_DIR} + ${PLAYWRIGHT_DIR} +) + +set(Playwright_LIBRARIES + WebKit +) + +set(CMAKE_EXE_LINKER_FLAGS "-framework Cocoa") + +set(EXECUTABLE_NAME Playwright) +set(PRODUCT_NAME Playwright) + +set(Playwright_Contents_Directory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Playwright.app/Contents) +make_directory(${Playwright_Contents_Directory}/Resources) +add_custom_command(OUTPUT ${Playwright_Contents_Directory}/Resources/BrowserWindow.nib + COMMAND ibtool --compile ${Playwright_Contents_Directory}/Resources/BrowserWindow.nib ${PLAYWRIGHT_DIR}/BrowserWindow.xib VERBATIM) +add_custom_command(OUTPUT ${Playwright_Contents_Directory}/Resources/MainMenu.nib + COMMAND ibtool --compile ${Playwright_Contents_Directory}/Resources/MainMenu.nib ${PLAYWRIGHT_DIR}/MainMenu.xib VERBATIM) +add_custom_target(PlaywrightNibs ALL DEPENDS + ${Playwright_Contents_Directory}/Resources/BrowserWindow.nib + ${Playwright_Contents_Directory}/Resources/MainMenu.nib +) + +include_directories(${Playwright_INCLUDE_DIRECTORIES}) +add_executable(Playwright MACOSX_BUNDLE ${Playwright_SOURCES}) +set_target_properties(Playwright PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${PLAYWRIGHT_DIR}/Info.plist) +target_link_libraries(Playwright ${Playwright_LIBRARIES}) +add_dependencies(Playwright PlaywrightNibs) diff --git a/Tools/Playwright/mac/Info.plist b/Tools/Playwright/mac/Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..4ed50c40f2f0dfd0ddf7c546b3451ab426c0501e --- /dev/null +++ b/Tools/Playwright/mac/Info.plist @@ -0,0 +1,56 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + WebKit Browser + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleShortVersionString + 1.0 + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + CFBundleVersion + 1 + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSSupportsAutomaticGraphicsSwitching + + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + html + + CFBundleTypeMIMETypes + + text/html + + CFBundleTypeName + HTML + CFBundleTypeRole + Editor + + + + diff --git a/Tools/Playwright/mac/MainMenu.xib b/Tools/Playwright/mac/MainMenu.xib new file mode 100644 index 0000000000000000000000000000000000000000..b16d639a1ad18354e058c613987d846acd70b361 --- /dev/null +++ b/Tools/Playwright/mac/MainMenu.xib @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tools/Playwright/mac/Playwright_Prefix.pch b/Tools/Playwright/mac/Playwright_Prefix.pch new file mode 100644 index 0000000000000000000000000000000000000000..ab6e9bce9a41291bb35664c2c63751c3413601f2 --- /dev/null +++ b/Tools/Playwright/mac/Playwright_Prefix.pch @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef __OBJC__ +#import +#import +#endif + +#define ENABLE_LOGGING 0 + +#if ENABLE_LOGGING +#define LOG NSLog +#else +#define LOG(...) ((void)0) +#endif diff --git a/Tools/Playwright/mac/main.m b/Tools/Playwright/mac/main.m new file mode 100644 index 0000000000000000000000000000000000000000..ba2ca12482c0ab809998131f693c876019c595f1 --- /dev/null +++ b/Tools/Playwright/mac/main.m @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +int main(int argc, char *argv[]) +{ + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"WebKitLinkedOnOrAfterEverything"]; + + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/Tools/Scripts/build-webkit b/Tools/Scripts/build-webkit index fc0664a6505546f428c7514b9675119b75a62140..14556b3742856ba88d9363957ea97f337fe63191 100755 --- a/Tools/Scripts/build-webkit +++ b/Tools/Scripts/build-webkit @@ -246,7 +246,7 @@ if (isAppleCocoaWebKit()) { push @projects, ("Source/WebKit"); if (!isIOSWebKit()) { - 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/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 71c358a27de26c8fc9e68e72fc6753a52a6a927e..1f561a039ff72ca5b1bce17d138c6e5ec62e4a3f 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -727,7 +727,8 @@ void TestController::createWebViewWithOptions(const TestOptions& options) 0, // didResignInputElementStrongPasswordAppearance 0, // requestStorageAccessConfirm shouldAllowDeviceOrientationAndMotionAccess, - runWebAuthenticationPanel + runWebAuthenticationPanel, + 0 // handleJavaScriptDialog }; WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient.base); diff --git a/Tools/WebKitTestRunner/win/EventSenderProxyWin.cpp b/Tools/WebKitTestRunner/win/EventSenderProxyWin.cpp index 06f19261b387ce02a44c319bd7016e824847ad24..c4e2f8f8816b06a105c18872e735ae4dbca6fe68 100644 --- a/Tools/WebKitTestRunner/win/EventSenderProxyWin.cpp +++ b/Tools/WebKitTestRunner/win/EventSenderProxyWin.cpp @@ -312,4 +312,59 @@ void EventSenderProxy::keyDown(WKStringRef keyRef, WKEventModifiers wkModifiers, SetKeyboardState(keyState); } +void EventSenderProxy::addTouchPoint(int, int) +{ + notImplemented(); +} + +void EventSenderProxy::updateTouchPoint(int, int, int) +{ + notImplemented(); +} + +void EventSenderProxy::setTouchModifier(WKEventModifiers, bool) +{ + notImplemented(); +} + +void EventSenderProxy::setTouchPointRadius(int, int) +{ + notImplemented(); +} + +void EventSenderProxy::touchStart() +{ + notImplemented(); +} + +void EventSenderProxy::touchMove() +{ + notImplemented(); +} + +void EventSenderProxy::touchEnd() +{ + notImplemented(); +} + +void EventSenderProxy::touchCancel() +{ + notImplemented(); +} + +void EventSenderProxy::clearTouchPoints() +{ + notImplemented(); +} + +void EventSenderProxy::releaseTouchPoint(int) +{ + notImplemented(); +} + +void EventSenderProxy::cancelTouchPoint(int) +{ + notImplemented(); +} + } // namespace WTR diff --git a/Tools/wpe/backends/CMakeLists.txt b/Tools/wpe/backends/CMakeLists.txt index 6456f4408c95b22246817912d430c42fc982932b..a08cc6da1936127a516fe0e95007de9cd18bdb02 100644 --- a/Tools/wpe/backends/CMakeLists.txt +++ b/Tools/wpe/backends/CMakeLists.txt @@ -10,6 +10,7 @@ file(MAKE_DIRECTORY ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}) set(WPEToolingBackends_SOURCES ${DERIVED_SOURCES_WPETOOLINGBACKENDS_DIR}/xdg-shell-unstable-v6-protocol.c ${TOOLS_DIR}/wpe/backends/HeadlessViewBackend.cpp + ${TOOLS_DIR}/wpe/backends/NullViewBackend.cpp ${TOOLS_DIR}/wpe/backends/ViewBackend.cpp ${TOOLS_DIR}/wpe/backends/WebKitAccessibleApplication.cpp ${TOOLS_DIR}/wpe/backends/WindowViewBackend.cpp diff --git a/Tools/wpe/backends/NullViewBackend.cpp b/Tools/wpe/backends/NullViewBackend.cpp new file mode 100644 index 0000000000000000000000000000000000000000..033ff802d3971a455667cd64c0e68dd10f448aa7 --- /dev/null +++ b/Tools/wpe/backends/NullViewBackend.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 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 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 "NullViewBackend.h" + +#include + +namespace WPEToolingBackends { + +NullViewBackend::NullViewBackend() + : ViewBackend(1, 1) +{ + static struct wpe_view_backend_exportable_fdo_egl_client exportableClient = { nullptr, nullptr, nullptr, nullptr, nullptr }; + m_exportable = wpe_view_backend_exportable_fdo_egl_create(&exportableClient, this, 1, 1); + initializeAccessibility(); + addActivityState(wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window); +} + +} // namespace WPEToolingBackends diff --git a/Tools/wpe/backends/NullViewBackend.h b/Tools/wpe/backends/NullViewBackend.h new file mode 100644 index 0000000000000000000000000000000000000000..c4489294acfe73adcb3593f2d54a3be625307f28 --- /dev/null +++ b/Tools/wpe/backends/NullViewBackend.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 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 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 "ViewBackend.h" +#include +#include +#include + +namespace WPEToolingBackends { + +class NullViewBackend final : public ViewBackend { +public: + NullViewBackend(); + virtual ~NullViewBackend() = default; +private: + void displayBuffer(struct wpe_fdo_egl_exported_image*) override { }; +#if WPE_FDO_CHECK_VERSION(1, 5, 0) + void displayBuffer(struct wpe_fdo_shm_exported_buffer*) override { }; +#endif +}; + +} // namespace WPEToolingBackends