diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index d0c56839b9671ac0e8ffc59edfbe37b3d5a1c338..6a292724bcccfc574ee611ec5b97d4b7f3adada3 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -1243,22 +1243,27 @@ 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/Emulation.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/GenericTypes.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Heap.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/IndexedDB.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Input.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Inspector.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/LayerTree.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Memory.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Network.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Page.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Playwright.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Recording.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Runtime.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/ScriptProfiler.json + ${JAVASCRIPTCORE_DIR}/inspector/protocol/Screencast.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Security.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/ServiceWorker.json ${JAVASCRIPTCORE_DIR}/inspector/protocol/Target.json diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make index 7542c7f77465e26e19d4a68a5db76091fdd46539..1225d0638393ed2ee1992bae8bf7c70140dfe3a3 100644 --- a/Source/JavaScriptCore/DerivedSources.make +++ b/Source/JavaScriptCore/DerivedSources.make @@ -266,22 +266,27 @@ 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/Emulation.json \ $(JavaScriptCore)/inspector/protocol/GenericTypes.json \ $(JavaScriptCore)/inspector/protocol/Heap.json \ $(JavaScriptCore)/inspector/protocol/IndexedDB.json \ + $(JavaScriptCore)/inspector/protocol/Input.json \ $(JavaScriptCore)/inspector/protocol/Inspector.json \ $(JavaScriptCore)/inspector/protocol/LayerTree.json \ $(JavaScriptCore)/inspector/protocol/Memory.json \ $(JavaScriptCore)/inspector/protocol/Network.json \ $(JavaScriptCore)/inspector/protocol/Page.json \ + $(JavaScriptCore)/inspector/protocol/Playwright.json \ $(JavaScriptCore)/inspector/protocol/Recording.json \ $(JavaScriptCore)/inspector/protocol/Runtime.json \ $(JavaScriptCore)/inspector/protocol/ScriptProfiler.json \ + $(JavaScriptCore)/inspector/protocol/Screencast.json \ $(JavaScriptCore)/inspector/protocol/Security.json \ $(JavaScriptCore)/inspector/protocol/ServiceWorker.json \ $(JavaScriptCore)/inspector/protocol/Target.json \ diff --git a/Source/JavaScriptCore/bindings/ScriptValue.cpp b/Source/JavaScriptCore/bindings/ScriptValue.cpp index 52d955b1e4929f6d0dede53097d275559b29b91d..71c538e57acf3912f9a777f7bc7eba6efb8877eb 100644 --- a/Source/JavaScriptCore/bindings/ScriptValue.cpp +++ b/Source/JavaScriptCore/bindings/ScriptValue.cpp @@ -79,7 +79,10 @@ static RefPtr jsToInspectorValue(JSGlobalObject* globalObject, JSVa PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); object.methodTable(vm)->getOwnPropertyNames(&object, globalObject, propertyNames, DontEnumPropertiesMode::Exclude); 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(), inspectorValue.releaseNonNull()); 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 8b290faebc1865519b0e7c514f497585dfc0bbda..53c68bca057c85c94201ef8e9870f0cb9e4cef6f 100644 --- a/Source/JavaScriptCore/inspector/InjectedScript.cpp +++ b/Source/JavaScriptCore/inspector/InjectedScript.cpp @@ -91,7 +91,7 @@ void InjectedScript::awaitPromise(const String& promiseObjectId, bool returnByVa makeAsyncCall(function, WTFMove(callback)); } -void InjectedScript::callFunctionOn(Protocol::ErrorString& errorString, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr& result, std::optional& wasThrown) +void InjectedScript::callFunctionOn(const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, bool awaitPromise, AsyncCallCallback&& callback) { Deprecated::ScriptFunctionCall function(injectedScriptObject(), "callFunctionOn"_s, inspectorEnvironment()->functionCallHandler()); function.appendArgument(objectId); @@ -99,10 +99,8 @@ void InjectedScript::callFunctionOn(Protocol::ErrorString& errorString, const St function.appendArgument(arguments); function.appendArgument(returnByValue); function.appendArgument(generatePreview); - - std::optional savedResultIndex; - makeEvalCall(errorString, function, result, wasThrown, savedResultIndex); - ASSERT(!savedResultIndex); + function.appendArgument(awaitPromise); + makeAsyncCall(function, WTFMove(callback)); } void InjectedScript::evaluateOnCallFrame(Protocol::ErrorString& errorString, JSC::JSValue callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr& result, std::optional& wasThrown, std::optional& savedResultIndex) @@ -289,6 +287,10 @@ 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; auto resultValue = toInspectorValue(globalObject(), callResult.value()); if (!resultValue) diff --git a/Source/JavaScriptCore/inspector/InjectedScript.h b/Source/JavaScriptCore/inspector/InjectedScript.h index e6b24967273095ae424ac9b3fe5e081ee8999ab7..9f7b72259ab79504b8bfcc24d35abe70d7372065 100644 --- a/Source/JavaScriptCore/inspector/InjectedScript.h +++ b/Source/JavaScriptCore/inspector/InjectedScript.h @@ -64,7 +64,7 @@ public: void evaluate(Protocol::ErrorString&, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr& result, std::optional& wasThrown, std::optional& savedResultIndex); void awaitPromise(const String& promiseObjectId, bool returnByValue, bool generatePreview, bool saveResult, AsyncCallCallback&&); void evaluateOnCallFrame(Protocol::ErrorString&, JSC::JSValue callFrames, const String& callFrameId, const String& expression, const String& objectGroup, bool includeCommandLineAPI, bool returnByValue, bool generatePreview, bool saveResult, RefPtr& result, std::optional& wasThrown, std::optional& savedResultIndex); - void callFunctionOn(Protocol::ErrorString&, const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, RefPtr& result, std::optional& wasThrown); + void callFunctionOn(const String& objectId, const String& expression, const String& arguments, bool returnByValue, bool generatePreview, bool awaitPromise, AsyncCallCallback&&); void getFunctionDetails(Protocol::ErrorString&, const String& functionId, RefPtr& result); void functionDetails(Protocol::ErrorString&, JSC::JSValue, RefPtr& result); void getPreview(Protocol::ErrorString&, const String& objectId, RefPtr& result); diff --git a/Source/JavaScriptCore/inspector/InjectedScriptSource.js b/Source/JavaScriptCore/inspector/InjectedScriptSource.js index 48baed6a1b7ffad453379a2f1eb71b8c4925f6c4..40d36f784f46e44dbad908402a71e6b02f499629 100644 --- a/Source/JavaScriptCore/inspector/InjectedScriptSource.js +++ b/Source/JavaScriptCore/inspector/InjectedScriptSource.js @@ -136,7 +136,7 @@ let InjectedScript = class InjectedScript return; } - if (!(promiseObject instanceof Promise)) { + if (InjectedScriptHost.internalConstructorName(promiseObject) !== 'Promise') { callback("Object with given id is not a Promise"); return; } @@ -171,14 +171,16 @@ let InjectedScript = class InjectedScript return this._evaluateAndWrap(callFrame.evaluateWithScopeExtension, callFrame, expression, objectGroup, isEvalOnCallFrame, includeCommandLineAPI, returnByValue, generatePreview, saveResult); } - callFunctionOn(objectId, expression, args, returnByValue, generatePreview) + callFunctionOn(objectId, expression, args, returnByValue, generatePreview, awaitPromise, callback) { let parsedObjectId = this._parseObjectId(objectId); let object = this._objectForId(parsedObjectId); let objectGroupName = this._idToObjectGroupName[parsedObjectId.id]; - if (!isDefined(object)) - return "Could not find object with given id"; + if (!isDefined(object)) { + callback(this._createThrownValue("Could not find object with given id", objectGroupName)); + return ; + } let resolvedArgs = []; if (args) { @@ -187,22 +189,37 @@ let InjectedScript = class InjectedScript try { resolvedArgs[i] = this._resolveCallArgument(callArgs[i]); } catch (e) { - return String(e); + callback(this._createThrownValue(e, objectGroupName)); + return; } } } try { let func = InjectedScriptHost.evaluate("(" + expression + ")"); - if (typeof func !== "function") - return "Given expression does not evaluate to a function"; - - return { - wasThrown: false, - result: RemoteObject.create(func.apply(object, resolvedArgs), objectGroupName, returnByValue, generatePreview) - }; + if (typeof func !== "function") { + callback(this._createThrownValue("Given expression does not evaluate to a function", objectGroupName)); + return; + } + let result = func.apply(object, resolvedArgs); + if (awaitPromise && isDefined(result) && (InjectedScriptHost.internalConstructorName(result) === 'Promise')) { + result.then(value => { + callback({ + wasThrown: false, + result: RemoteObject.create(value, objectGroupName, returnByValue, generatePreview), + }); + }, reason => { + callback(this._createThrownValue(reason, objectGroupName)); + }); + } else { + callback({ + wasThrown: false, + result: RemoteObject.create(result, objectGroupName, returnByValue, generatePreview) + }); + } } catch (e) { - return this._createThrownValue(e, objectGroupName); + callback(this._createThrownValue(e, objectGroupName)); + return; } } diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp index 4895c5a70d6a4745597f77163bc92e0745594829..e4905e0d4e5ff88e479147c84e41359f9274b341 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp @@ -101,7 +101,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple m_dispatchers.set(domain, dispatcher); } -void BackendDispatcher::dispatch(const String& message) +void BackendDispatcher::dispatch(const String& message, Interceptor&& interceptor) { Ref protect(*this); @@ -146,6 +146,9 @@ void BackendDispatcher::dispatch(const String& message) requestId = *requestIdInt; } + if (interceptor && interceptor(messageObject) == InterceptionResult::Intercepted) + return; + { // We could be called re-entrantly from a nested run loop, so restore the previous id. SetForScope> scopedRequestId(m_currentRequestId, requestId); diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h index 37c4f9833d4981b47bcd8debd4a79109254641a2..1c82cc9783618234bef7024d91821ce509912526 100644 --- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h +++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h @@ -83,7 +83,10 @@ public: }; void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*); - void dispatch(const String& message); + + enum class InterceptionResult { Intercepted, Continue }; + using Interceptor = WTF::Function&)>; + void dispatch(const String& message, Interceptor&& interceptor = Interceptor()); // Note that 'unused' is a workaround so the compiler can pick the right sendResponse based on arity. // When is fixed or this class is renamed for the JSON::Object case, diff --git a/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp index d408d364f1986983161f9d44efbc8bc6f6898676..1375ce9990f0c63d7e6f33ee62930051d6cd44cb 100644 --- a/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp +++ b/Source/JavaScriptCore/inspector/InspectorFrontendRouter.cpp @@ -49,7 +49,7 @@ void FrontendRouter::connectFrontend(FrontendChannel& connection) void FrontendRouter::disconnectFrontend(FrontendChannel& connection) { if (!m_connections.contains(&connection)) { - ASSERT_NOT_REACHED(); + ASSERT(m_connections.isEmpty()); return; } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.cpp b/Source/JavaScriptCore/inspector/InspectorTarget.cpp index 0cc2127c9c12c2d82dea9550bad73f4ffb99ba24..8ca65cc042d435cbc0e05dcc5c5dfc958eb24f5a 100644 --- a/Source/JavaScriptCore/inspector/InspectorTarget.cpp +++ b/Source/JavaScriptCore/inspector/InspectorTarget.cpp @@ -44,6 +44,8 @@ void InspectorTarget::resume() ASSERT(m_isPaused); m_isPaused = false; + willResume(); + if (m_resumeCallback) { m_resumeCallback(); m_resumeCallback = nullptr; @@ -52,7 +54,6 @@ void InspectorTarget::resume() void InspectorTarget::setResumeCallback(WTF::Function&& callback) { - ASSERT(!m_resumeCallback); m_resumeCallback = WTFMove(callback); } diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h index 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/InspectorRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp index 76d72c7273f1bb2170485015d931b1fba92d3b5a..c0cf9588c04bfba0d6176c4d6af691bd56ca6cec 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp @@ -168,16 +168,15 @@ void InspectorRuntimeAgent::awaitPromise(const Protocol::Runtime::RemoteObjectId }); } -Protocol::ErrorStringOr, std::optional /* wasThrown */>> InspectorRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObjectId& objectId, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& /* emulateUserGesture */) +void InspectorRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObjectId& objectId, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& /* emulateUserGesture */, std::optional&& awaitPromise, Ref&& callback) { Protocol::ErrorString errorString; InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId); - if (injectedScript.hasNoValue()) - return makeUnexpected("Missing injected script for given objectId"_s); - - RefPtr result; - std::optional wasThrown; + if (injectedScript.hasNoValue()) { + callback->sendFailure("Missing injected script for given objectId"_s); + return; + } JSC::Debugger::TemporarilyDisableExceptionBreakpoints temporarilyDisableExceptionBreakpoints(m_debugger); @@ -187,15 +186,15 @@ Protocol::ErrorStringOr, std::op muteConsole(); } - injectedScript.callFunctionOn(errorString, objectId, functionDeclaration, arguments ? arguments->toJSONString() : nullString(), returnByValue.value_or(false), generatePreview.value_or(false), result, wasThrown); + injectedScript.callFunctionOn(objectId, functionDeclaration, arguments ? arguments->toJSONString() : nullString(), returnByValue.value_or(false), generatePreview.value_or(false), awaitPromise.value_or(false), [callback=WTFMove(callback)] (Protocol::ErrorString& errorString, RefPtr&& result, std::optional&& wasThrown, std::optional&&) { + if (!result) + callback->sendFailure(errorString); + else + callback->sendSuccess(result.releaseNonNull(), WTFMove(wasThrown)); + }); if (pauseAndMute) unmuteConsole(); - - if (!result) - return makeUnexpected(errorString); - - return { { result.releaseNonNull(), WTFMove(wasThrown) } }; } Protocol::ErrorStringOr> InspectorRuntimeAgent::getPreview(const Protocol::Runtime::RemoteObjectId& objectId) diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h index c4f6fa5b9de54317da07c2371a7126aae1c967aa..0d549faeb1f0f80c7a6e7c208c72c6ef9cf4dbd5 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h @@ -62,7 +62,7 @@ public: Protocol::ErrorStringOr>> parse(const String& expression) final; Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture) override; void awaitPromise(const Protocol::Runtime::RemoteObjectId&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, Ref&&) final; - Protocol::ErrorStringOr, std::optional /* wasThrown */>> callFunctionOn(const Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture) override; + void callFunctionOn(const Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture, std::optional&& awaitPromise, Ref&&) override; Protocol::ErrorStringOr releaseObject(const Protocol::Runtime::RemoteObjectId&) final; Protocol::ErrorStringOr> getPreview(const Protocol::Runtime::RemoteObjectId&) final; Protocol::ErrorStringOr>, RefPtr>>> getProperties(const Protocol::Runtime::RemoteObjectId&, std::optional&& ownProperties, std::optional&& fetchStart, std::optional&& fetchCount, std::optional&& generatePreview) final; diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp index 508eb02ec95c52408384a1e2b77648afd426dd9d..c0099a56794ae411fe9cdce1a65a95f1a7e37924 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp @@ -87,6 +87,34 @@ Protocol::ErrorStringOr InspectorTargetAgent::sendMessageToTarget(const St return { }; } +Protocol::ErrorStringOr InspectorTargetAgent::activate(const String& targetId) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) + return makeUnexpected("Missing target for given targetId"_s); + + String errorString; + target->activate(errorString); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + return { }; +} + +Protocol::ErrorStringOr InspectorTargetAgent::close(const String& targetId, std::optional&& runBeforeUnload) +{ + InspectorTarget* target = m_targets.get(targetId); + if (!target) + return makeUnexpected("Missing target for given targetId"_s); + + String errorString; + target->close(errorString, runBeforeUnload && *runBeforeUnload); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + return { }; +} + void InspectorTargetAgent::sendMessageFromTargetToFrontend(const String& targetId, const String& message) { ASSERT_WITH_MESSAGE(m_targets.get(targetId), "Sending a message from an untracked target to the frontend."); @@ -144,7 +172,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 +197,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 e81573fd0fffaaf6fd2af36635c78fcdf8608c69..4169e227b5fb5a3a7fb51396c4679100f495719c 100644 --- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h +++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h @@ -50,15 +50,21 @@ public: Protocol::ErrorStringOr setPauseOnStart(bool) final; Protocol::ErrorStringOr resume(const String& targetId) final; Protocol::ErrorStringOr sendMessageToTarget(const String& targetId, const String& message) final; + Protocol::ErrorStringOr activate(const String& targetId) override; + Protocol::ErrorStringOr close(const String& targetId, std::optional&& runBeforeUnload) override; // Target lifecycle. void 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 3a91ac6b57fad7f472daa2e2107b3b483de70165..ff51e75762818b0bb5070ddf8de10e66018d63b0 100644 --- a/Source/JavaScriptCore/inspector/protocol/DOM.json +++ b/Source/JavaScriptCore/inspector/protocol/DOM.json @@ -80,6 +80,16 @@ { "name": "value", "type": "string", "description": "The value that is resolved to with this data binding relationship." } ] }, + { + "id": "Rect", + "type": "object", + "properties": [ + { "name": "x", "type": "integer", "description": "X coordinate" }, + { "name": "y", "type": "integer", "description": "Y coordinate" }, + { "name": "width", "type": "integer", "description": "Rectangle width" }, + { "name": "height", "type": "integer", "description": "Rectangle height" } + ] + }, { "id": "EventListener", "type": "object", @@ -168,6 +178,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": [ @@ -532,7 +552,9 @@ "description": "Resolves JavaScript node object for given node id.", "targetTypes": ["page"], "parameters": [ - { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to resolve." }, + { "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Id of the node to resolve." }, + { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "Source element handle." }, + { "name": "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": [ @@ -599,6 +621,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..347a01b3fdd1a8277cb4104558e8bbfa63539374 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Emulation.json @@ -0,0 +1,51 @@ +{ + "domain": "Emulation", + "availability": ["web"], + "commands": [ + { + "name": "setDeviceMetricsOverride", + "description": "Overrides device metrics with provided values.", + "async": true, + "parameters": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" }, + { "name": "fixedLayout", "type": "boolean" }, + { "name": "deviceScaleFactor", "type": "number", "optional": true } + ] + }, + { + "name": "setJavaScriptEnabled", + "description": "Allows to disable script execution for the page.", + "parameters": [ + { "name": "enabled", "type": "boolean" } + ] + }, + { + "name": "setAuthCredentials", + "description": "Credentials to use during HTTP authentication.", + "parameters": [ + { "name": "username", "type": "string", "optional": true }, + { "name": "password", "type": "string", "optional": true } + ] + }, + { + "name": "setActiveAndFocused", + "description": "Makes page focused for test.", + "parameters": [ + { "name": "active", "type": "boolean", "optional": true } + ] + }, + { + "name": "grantPermissions", + "parameters": [ + { "name": "origin", "type": "string" }, + { "name": "permissions", "type": "array", "items": { "type": "string" } } + ], + "description": "Overrides the permissions." + }, + { + "name": "resetPermissions", + "description": "Clears permission overrides." + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Input.json b/Source/JavaScriptCore/inspector/protocol/Input.json new file mode 100644 index 0000000000000000000000000000000000000000..587287d52fde2735cbae34a27a0f673b7e38e1a7 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Input.json @@ -0,0 +1,188 @@ +{ + "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" + } + ] + }, + { + "name": "dispatchTapEvent", + "description": "Dispatches a tap event to the page.", + "async": true, + "parameters": [ + { + "name": "x", + "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels.", + "type": "integer" + }, + { + "name": "y", + "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to\nthe top of the viewport and Y increases as it proceeds towards the bottom of the viewport.", + "type": "integer" + }, + { + "name": "modifiers", + "description": "Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8\n(default: 0).", + "optional": true, + "type": "integer" + } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Network.json b/Source/JavaScriptCore/inspector/protocol/Network.json index 882a2d56befef0aba460cc8ff041969e0d2c1ed3..71d4bfc4a4bc5a43bd2b98aefa316b4e74e35b8f 100644 --- a/Source/JavaScriptCore/inspector/protocol/Network.json +++ b/Source/JavaScriptCore/inspector/protocol/Network.json @@ -192,6 +192,17 @@ { "name": "base64Encoded", "type": "boolean", "description": "True, if content was sent as base64." } ] }, + { + "name": "getInterceptedResponseBody", + "description": "Returns content served for the given request. Will wait for the request to finish loading.", + "async": true, + "parameters": [ + { "name": "requestId", "$ref": "RequestId", "description": "Identifier of the intercepted network response's request." } + ], + "returns": [ + { "name": "body", "type": "string", "description": "Base64 encoded response body." } + ] + }, { "name": "setResourceCachingDisabled", "description": "Toggles whether the resource cache may be used when loading resources in the inspected page. If true, the resource cache will not be used when loading resources.", @@ -324,6 +335,13 @@ { "name": "requestId", "$ref": "RequestId", "description": "Identifier for the intercepted Network request to fail." }, { "name": "errorType", "$ref": "ResourceErrorType", "description": "Deliver error reason for the request failure." } ] + }, + { + "name": "setEmulateOfflineState", + "description": "Emulate offline state overriding the actual state.", + "parameters": [ + { "name": "offline", "type": "boolean", "description": "True to emulate offline." } + ] } ], "events": [ diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json index db52479a72d459be23d4d8d080c0ed15ea9fc4c0..35b44b9fc9bbde387991155e6fa3d26a0fd368d5 100644 --- a/Source/JavaScriptCore/inspector/protocol/Page.json +++ b/Source/JavaScriptCore/inspector/protocol/Page.json @@ -21,13 +21,15 @@ "ShowDebugBorders", "ShowRepaintCounter", "WebRTCEncryptionEnabled", - "WebSecurityEnabled" + "WebSecurityEnabled", + "DeviceOrientationEventEnabled", + "SpeechRecognitionEnabled" ] }, { "id": "ResourceType", "type": "string", - "enum": ["Document", "StyleSheet", "Image", "Font", "Script", "XHR", "Fetch", "Ping", "Beacon", "WebSocket", "Other"], + "enum": ["Document", "StyleSheet", "Image", "Font", "Script", "XHR", "Fetch", "Ping", "Beacon", "WebSocket", "EventSource", "Other"], "description": "Resource type as it was perceived by the rendering engine." }, { @@ -49,6 +51,12 @@ "enum": ["Light", "Dark"], "description": "Page appearance name." }, + { + "id": "ReducedMotion", + "type": "string", + "enum": ["Reduce", "NoPreference"], + "description": "Page reduced-motion media query override." + }, { "id": "Frame", "type": "object", @@ -112,6 +120,51 @@ { "name": "secure", "type": "boolean", "description": "True if cookie is secure." }, { "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."} + ] + }, + { + "id": "Insets", + "type": "object", + "properties": [ + { "name": "top", "type": "number" }, + { "name": "right", "type": "number" }, + { "name": "bottom", "type": "number" }, + { "name": "left", "type": "number" } + ] } ], "commands": [ @@ -131,6 +184,14 @@ { "name": "revalidateAllResources", "type": "boolean", "optional": true, "description": "If true, all cached subresources will be revalidated when the main resource loads. Otherwise, only expired cached subresources will be revalidated (the default behavior for most WebKit clients)." } ] }, + { + "name": "goBack", + "description": "Goes back in the history." + }, + { + "name": "goForward", + "description": "Goes forward in the history." + }, { "name": "navigate", "description": "Navigates current page to the given URL.", @@ -204,7 +265,8 @@ "name": "setBootstrapScript", "targetTypes": ["page"], "parameters": [ - { "name": "source", "type": "string", "optional": true, "description": "If `source` is provided (and not empty), it will be injected into all future global objects as soon as they're created. Omitting `source` will stop this from happening." } + { "name": "source", "type": "string", "optional": true, "description": "If `source` is provided (and not empty), it will be injected into all future global objects as soon as they're created. Omitting `source` will stop this from happening." }, + { "name": "worldName", "type": "string", "optional": true, "description": "Isolated world name to evaluate the script in. If not specified main world will be used." } ] }, { @@ -270,6 +332,28 @@ { "name": "appearance", "$ref": "Appearance", "optional": true } ] }, + { + "name": "setForcedReducedMotion", + "description": "Forces the reduced-motion media query for the page.", + "targetTypes": ["page"], + "parameters": [ + { "name": "reducedMotion", "$ref": "ReducedMotion", "optional": true } + ] + }, + { + "name": "setTimeZone", + "description": "Enables time zone emulation.", + "parameters": [ + { "name": "timeZone", "type": "string", "optional": true } + ] + }, + { + "name": "setTouchEmulationEnabled", + "description": "Enables touch events on platforms that lack them.", + "parameters": [ + {"name": "enabled", "type": "boolean", "description": "Whether touch should be enabled."} + ] + }, { "name": "snapshotNode", "description": "Capture a snapshot of the specified node that does not include unrelated layers.", @@ -290,7 +374,8 @@ { "name": "y", "type": "integer", "description": "Y coordinate" }, { "name": "width", "type": "integer", "description": "Rectangle width" }, { "name": "height", "type": "integer", "description": "Rectangle height" }, - { "name": "coordinateSystem", "$ref": "CoordinateSystem", "description": "Indicates the coordinate system of the supplied rectangle." } + { "name": "coordinateSystem", "$ref": "CoordinateSystem", "description": "Indicates the coordinate system of the supplied rectangle." }, + { "name": "omitDeviceScaleFactor", "type": "boolean", "optional": true, "description": "By default, screenshot is inflated by device scale factor to avoid blurry image. This flag disables it." } ], "returns": [ { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." } @@ -308,12 +393,77 @@ { "name": "setScreenSizeOverride", "description": "Overrides screen size exposed to DOM and used in media queries for testing with provided values.", - "condition": "!(defined(WTF_PLATFORM_COCOA) && WTF_PLATFORM_COCOA)", "targetTypes": ["page"], "parameters": [ { "name": "width", "type": "integer", "description": "Screen width", "optional": true }, { "name": "height", "type": "integer", "description": "Screen height", "optional": true } ] + }, + { + "name": "insertText", + "description": "Insert text into the current selection of the page.", + "parameters": [ + { "name": "text", "type": "string", "description": "Text to insert." } + ] + }, + { + "name": "accessibilitySnapshot", + "description": "Serializes and returns all of the accessibility nodes of the page.", + "parameters": [ + { "name": "objectId", "type": "string", "optional": true, "description": "Object Id of a node to find in the accessibility tree."} + ], + "returns": [ + { "name": "axNode", "$ref": "AXNode", "description": "The root AXNode."} + ] + }, + { + "name": "setInterceptFileChooserDialog", + "description": "Intercepts file chooser dialog", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "True to enable." } + ] + }, + { + "name": "setDefaultBackgroundColorOverride", + "description": "Sets or clears an override of the default background color of the frame. This override is used if the content does not specify one.", + "parameters": [ + { "name": "color", "$ref": "DOM.RGBAColor", "optional": true, "description": "RGBA of the default background color. If not specified, any existing override will be cleared." } + ] + }, + { + "name": "createUserWorld", + "description": "Creates an user world for every loaded frame.", + "parameters": [ + { "name": "name", "type": "string", "description": "Isolated world name, will be used as an execution context name." } + ] + }, + { + "name": "setBypassCSP", + "description": "Enable page Content Security Policy by-passing.", + "parameters": [ + { "name": "enabled", "type": "boolean", "description": "Whether to bypass page CSP." } + ] + }, + { + "name": "crash", + "description": "Crashes the page process" + }, + { + "name": "setOrientationOverride", + "description": "Overrides window.orientation with provided value.", + "parameters": [ + { "name": "angle", "type": "integer", "optional": true } + ] + }, + { + "name": "setVisibleContentRects", + "targetTypes": ["page"], + "parameters": [ + { "name": "unobscuredContentRect", "$ref": "DOM.Rect", "optional": true }, + { "name": "contentInsets", "$ref": "Insets", "optional": true }, + { "name": "obscuredInsets", "$ref": "Insets", "optional": true }, + { "name": "unobscuredInsets", "$ref": "Insets", "optional": true } + ] } ], "events": [ @@ -321,14 +471,16 @@ "name": "domContentEventFired", "targetTypes": ["page"], "parameters": [ - { "name": "timestamp", "type": "number" } + { "name": "timestamp", "type": "number" }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has fired DOMContentLoaded event." } ] }, { "name": "loadEventFired", "targetTypes": ["page"], "parameters": [ - { "name": "timestamp", "type": "number" } + { "name": "timestamp", "type": "number" }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has fired load event." } ] }, { @@ -338,6 +490,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.", @@ -377,6 +537,22 @@ { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." } ] }, + { + "name": "navigatedWithinDocument", + "description": "Fired when same-document navigation happens, e.g. due to history API usage or anchor navigation.", + "parameters": [ + { + "name": "frameId", + "description": "Id of the frame.", + "$ref": "Network.FrameId" + }, + { + "name": "url", + "description": "Frame's new url.", + "type": "string" + } + ] + }, { "name": "defaultAppearanceDidChange", "description": "Fired when page's default appearance changes, even if there is a forced appearance.", @@ -385,6 +561,28 @@ "parameters": [ { "name": "appearance", "$ref": "Appearance", "description": "Name of the appearance that is active (not considering any forced appearance.)" } ] + }, + { + "name": "willRequestOpenWindow", + "description": "Fired when page tries to open a new window.", + "parameters": [ + { "name": "url", "type": "string" } + ] + }, + { + "name": "didRequestOpenWindow", + "description": "Fired after page did try to open a new window.", + "parameters": [ + { "name": "opened", "type": "boolean" } + ] + }, + { + "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..3aebbe625682094d0e8ac2f14ac33321dd475142 --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Playwright.json @@ -0,0 +1,289 @@ +{ + "domain": "Playwright", + "availability": ["web"], + "types": [ + { + "id": "ContextID", + "type": "string", + "description": "Id of Browser context." + }, + { + "id": "PageProxyID", + "type": "string", + "description": "Id of WebPageProxy." + }, + { + "id": "CookieSameSitePolicy", + "type": "string", + "enum": ["None", "Lax", "Strict"], + "description": "Same-Site policy of a cookie." + }, + { + "id": "Cookie", + "type": "object", + "description": "Cookie object", + "properties": [ + { "name": "name", "type": "string", "description": "Cookie name." }, + { "name": "value", "type": "string", "description": "Cookie value." }, + { "name": "domain", "type": "string", "description": "Cookie domain." }, + { "name": "path", "type": "string", "description": "Cookie path." }, + { "name": "expires", "type": "number", "description": "Cookie expires." }, + { "name": "httpOnly", "type": "boolean", "description": "True if cookie is http-only." }, + { "name": "secure", "type": "boolean", "description": "True if cookie is secure." }, + { "name": "session", "type": "boolean", "description": "True if cookie is session cookie." }, + { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." } + ] + }, + { + "id": "SetCookieParam", + "type": "object", + "description": "Cookie object", + "properties": [ + { "name": "name", "type": "string", "description": "Cookie name." }, + { "name": "value", "type": "string", "description": "Cookie value." }, + { "name": "domain", "type": "string", "description": "Cookie domain." }, + { "name": "path", "type": "string", "description": "Cookie path." }, + { "name": "expires", "type": "number", "optional": true, "description": "Cookie expires." }, + { "name": "httpOnly", "type": "boolean", "optional": true, "description": "True if cookie is http-only." }, + { "name": "secure", "type": "boolean", "optional": true, "description": "True if cookie is secure." }, + { "name": "session", "type": "boolean", "optional": true, "description": "True if cookie is session cookie." }, + { "name": "sameSite", "$ref": "CookieSameSitePolicy", "optional": true, "description": "Cookie Same-Site policy." } + ] + }, + { + "id": "NameValue", + "type": "object", + "description": "Name-value pair", + "properties": [ + { "name": "name", "type": "string" }, + { "name": "value", "type": "string" } + ] + }, + { + "id": "OriginStorage", + "type": "object", + "description": "Origin object", + "properties": [ + { "name": "origin", "type": "string", "description": "Origin." }, + { "name": "items", "type": "array", "items": { "$ref": "NameValue" }, "description": "Storage entries." } + ] + }, + { + "id": "Geolocation", + "type": "object", + "description": "Geolocation", + "properties": [ + { "name": "timestamp", "type": "number", "description": "Mock latitude" }, + { "name": "latitude", "type": "number", "description": "Mock latitude" }, + { "name": "longitude", "type": "number", "description": "Mock longitude" }, + { "name": "accuracy", "type": "number", "description": "Mock accuracy" } + ] + } + ], + "commands": [ + { + "name": "enable" + }, + { + "name": "disable" + }, + { + "name": "close", + "async": true, + "description": "Close browser." + }, + { + "name": "createContext", + "description": "Creates new ephemeral browser context.", + "parameters": [ + { "name": "proxyServer", "type": "string", "optional": true, "description": "Proxy server, similar to the one passed to --proxy-server" }, + { "name": "proxyBypassList", "type": "string", "optional": true, "description": "Proxy bypass list, similar to the one passed to --proxy-bypass-list" } + ], + "returns": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." } + ] + }, + { + "name": "deleteContext", + "async": true, + "description": "Deletes browser context previously created with createContect. The command will automatically close all pages that use the context.", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Identifier of the context to delete." } + ] + }, + { + "name": "createPage", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." } + ], + "returns": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." } + ] + }, + { + "name": "navigate", + "async": true, + "description": "Navigates current page to the given URL.", + "parameters": [ + { "name": "url", "type": "string", "description": "URL to navigate the page to." }, + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to navigate."}, + { "name": "referrer", "type": "string", "optional": true, "description": "Referrer URL." } + ], + "returns": [ + { "name": "loaderId", "$ref": "Network.LoaderId", "optional": true, "description": "Identifier of the loader associated with the navigation." } + ] + }, + { + "name": "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": "getLocalStorageData", + "description": "Returns all local storage data in the given browser context.", + "async": true, + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ], + "returns": [ + { "name": "origins", "type": "array", "items": { "$ref": "OriginStorage" }, "description": "Local storage data." } + ] + }, + { + "name": "setLocalStorageData", + "description": "Populates local storage data in the given browser context.", + "async": true, + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }, + { "name": "origins", "type": "array", "items": { "$ref": "OriginStorage" }, "description": "Local storage data." } + ] + }, + { + "name": "setGeolocationOverride", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }, + { "name": "geolocation", "$ref": "Geolocation", "optional": true, "description": "Geolocation to set, if missing emulates position unavailable." } + ], + "description": "Overrides the geolocation position or error." + }, + { + "name": "setLanguages", + "description": "Allows to set locale language for context.", + "parameters": [ + { "name": "languages", "type": "array", "items": { "type": "string" } }, + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ] + }, + { + "name": "setDownloadBehavior", + "description": "Allows to override download behavior.", + "parameters": [ + { "name": "behavior", "optional": true, "type": "string", "enum": ["allow", "deny"] }, + { "name": "downloadPath", "optional": true, "type": "string" }, + { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." } + ] + }, + { + "name": "cancelDownload", + "parameters": [ + { "name": "uuid", "type": "string" } + ], + "description": "Cancels a current running download." + } + ], + "events": [ + { + "name": "pageProxyCreated", + "parameters": [ + { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." }, + { "name": "pageProxyId", "$ref": "PageProxyID" }, + { "name": "openerId", "$ref": "PageProxyID", "optional": true, "description": "Unique identifier of the opening page. Only set for pages created by window.open()." } + ] + }, + { + "name": "pageProxyDestroyed", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID" } + ] + }, + { + "name": "provisionalLoadFailed", + "description": "Fired when provisional load fails.", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "loaderId", "$ref": "Network.LoaderId", "description": "Identifier of the loader associated with the navigation." }, + { "name": "error", "type": "string", "description": "Localized error string." } + ] + }, + { + "name": "windowOpen", + "description": "Fired when page opens a new window.", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "url", "type": "string" }, + { "name": "windowFeatures", "type": "array", "items": { "type": "string" } } + ] + }, + { + "name": "downloadCreated", + "parameters": [ + { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }, + { "name": "frameId", "$ref": "Network.FrameId", "description": "Unique identifier of the originating frame." }, + { "name": "uuid", "type": "string" }, + { "name": "url", "type": "string" } + ] + }, + { + "name": "downloadFilenameSuggested", + "parameters": [ + { "name": "uuid", "type": "string" }, + { "name": "suggestedFilename", "type": "string" } + ] + }, + { + "name": "downloadFinished", + "parameters": [ + { "name": "uuid", "type": "string" }, + { "name": "error", "type": "string" } + ] + }, + { + "name": "screencastFinished", + "parameters": [ + { "name": "screencastId", "$ref": "Screencast.ScreencastId", "description": "Unique identifier of the screencast." } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json index 274b01596d490fb81b48cf89bf668e0634e8b423..d08a9ddd745c748767ba8055907daa7beeffc219 100644 --- a/Source/JavaScriptCore/inspector/protocol/Runtime.json +++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json @@ -261,12 +261,14 @@ { "name": "doNotPauseOnExceptionsAndMuteConsole", "type": "boolean", "optional": true, "description": "Specifies whether function call should stop on exceptions and mute console. Overrides setPauseOnException state." }, { "name": "returnByValue", "type": "boolean", "optional": true, "description": "Whether the result is expected to be a JSON object which should be sent by value." }, { "name": "generatePreview", "type": "boolean", "optional": true, "description": "Whether preview should be generated for the result." }, - { "name": "emulateUserGesture", "type": "boolean", "optional": true, "description": "Whether the expression should be considered to be in a user gesture or not." } + { "name": "emulateUserGesture", "type": "boolean", "optional": true, "description": "Whether the expression should be considered to be in a user gesture or not." }, + { "name": "awaitPromise", "type": "boolean", "optional": true, "description": "Whether to automatically await returned promise." } ], "returns": [ { "name": "result", "$ref": "RemoteObject", "description": "Call result." }, { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." } - ] + ], + "async": true }, { "name": "getPreview", diff --git a/Source/JavaScriptCore/inspector/protocol/Screencast.json b/Source/JavaScriptCore/inspector/protocol/Screencast.json new file mode 100644 index 0000000000000000000000000000000000000000..f6c541d63c0b8251874eaf8818aabe0e0449401d --- /dev/null +++ b/Source/JavaScriptCore/inspector/protocol/Screencast.json @@ -0,0 +1,65 @@ +{ + "domain": "Screencast", + "availability": ["web"], + "types": [ + { + "id": "ScreencastId", + "type": "string", + "description": "Unique identifier of the screencast." + } + ], + "commands": [ + { + "name": "startVideo", + "description": "Starts recoring video to speified file.", + "parameters": [ + { "name": "file", "type": "string", "description": "Output file location." }, + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" }, + { "name": "toolbarHeight", "type": "integer" }, + { "name": "scale", "type": "number", "optional": true } + ], + "returns": [ + { "name": "screencastId", "$ref": "ScreencastId", "description": "Unique identifier of the screencast." } + ] + }, + { + "name": "stopVideo", + "async": true, + "description": "Stops recoding video. Returns after the file has been closed." + }, + { + "name": "startScreencast", + "description": "Starts screencast.", + "parameters": [ + { "name": "width", "type": "integer" }, + { "name": "height", "type": "integer" }, + { "name": "toolbarHeight", "type": "integer" }, + { "name": "quality", "type": "integer" } + ], + "returns": [ + { "name": "generation", "type": "integer", "description": "Screencast session generation." } + ] + }, + { + "name": "stopScreencast", + "description": "Stops screencast." + }, + { + "name": "screencastFrameAck", + "parameters": [ + { "name": "generation", "type": "integer", "description": "Screencast session generation" } + ] + } + ], + "events": [ + { + "name": "screencastFrame", + "parameters": [ + { "name": "data", "type": "string", "description": "Base64 data" }, + { "name": "deviceWidth", "type": "integer" }, + { "name": "deviceHeight", "type": "integer" } + ] + } + ] +} diff --git a/Source/JavaScriptCore/inspector/protocol/Target.json b/Source/JavaScriptCore/inspector/protocol/Target.json index 52920cded24a9c6b0ef6fb4e518664955db4f9fa..bbbabc4e7259088b9404e8cc07eecd6f45077da0 100644 --- a/Source/JavaScriptCore/inspector/protocol/Target.json +++ b/Source/JavaScriptCore/inspector/protocol/Target.json @@ -10,7 +10,7 @@ "properties": [ { "name": "targetId", "type": "string", "description": "Unique identifier for the target." }, { "name": "type", "type": "string", "enum": ["page", "service-worker", "worker"] }, - { "name": "isProvisional", "type": "boolean", "optional": true, "description": "Whether this is a provisional page target." }, + { "name": "isProvisional", "type": "boolean", "optional": true, "description": "True value indicates that this is a provisional page target i.e. Such target may be created when current page starts cross-origin navigation. Eventually each provisional target is either committed and swaps with the current target or gets destroyed, e.g. in case of load request failure." }, { "name": "isPaused", "type": "boolean", "optional": true, "description": "Whether the target is paused on start and has to be explicitely resumed by inspector." } ] } @@ -37,6 +37,21 @@ { "name": "targetId", "type": "string" }, { "name": "message", "type": "string", "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." } ] + }, + { + "name": "activate", + "description": "Reveals the target on screen.", + "parameters": [ + { "name": "targetId", "type": "string" } + ] + }, + { + "name": "close", + "description": "Closes the target.", + "parameters": [ + { "name": "targetId", "type": "string" }, + { "name": "runBeforeUnload", "type": "boolean", "optional": true } + ] } ], "events": [ @@ -49,7 +64,8 @@ { "name": "targetDestroyed", "parameters": [ - { "name": "targetId", "type": "string" } + { "name": "targetId", "type": "string" }, + { "name": "crashed", "type": "boolean" } ] }, { diff --git a/Source/JavaScriptCore/inspector/protocol/Worker.json b/Source/JavaScriptCore/inspector/protocol/Worker.json index 638612413466efc87b737e8a81042ed07ca12703..6f9e518ff0bfa2a6228675d25b6b785f1ed3022a 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", @@ -33,7 +33,8 @@ "parameters": [ { "name": "workerId", "type": "string" }, { "name": "url", "type": "string" }, - { "name": "name", "type": "string" } + { "name": "name", "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 2decf8a83c80e80ca8677f4c787bf79c6c2995fa..9010384a32f7c2ab69a8fb20eb19cd566fd9f434 100644 --- a/Source/JavaScriptCore/runtime/DateConversion.cpp +++ b/Source/JavaScriptCore/runtime/DateConversion.cpp @@ -97,6 +97,9 @@ String formatDateTime(const GregorianDateTime& t, DateTimeFormat format, bool as appendNumber<2>(builder, offset / 60); appendNumber<2>(builder, offset % 60); + if (!WTF::timeZoneDisplayNameForAutomation().isEmpty()) { + builder.append(" (", WTF::timeZoneDisplayNameForAutomation(), ')'); + } else { #if OS(WINDOWS) TIME_ZONE_INFORMATION timeZoneInformation; GetTimeZoneInformation(&timeZoneInformation); @@ -109,6 +112,7 @@ String formatDateTime(const GregorianDateTime& t, DateTimeFormat format, bool as #endif if (timeZoneName[0]) builder.append(" (", timeZoneName, ')'); + } } } diff --git a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp index 2729df9dd4d15e19b7b2019ca94dd7647c5a6706..a7fdc92d594a7930ca029f162cc385bbdb949597 100644 --- a/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp +++ b/Source/JavaScriptCore/runtime/IntlDateTimeFormat.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp index ea0bfb0d7a5a64c1570da5333199f99b552a5ff6..2ebe8c6c5ac4343e0b373ccc271e86a4080a98dc 100644 --- a/Source/JavaScriptCore/runtime/JSDateMath.cpp +++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp @@ -76,6 +76,7 @@ #include "VM.h" #include #include +#include #if U_ICU_VERSION_MAJOR_NUM >= 69 || (U_ICU_VERSION_MAJOR_NUM == 68 && USE(APPLE_INTERNAL_SDK)) #define HAVE_ICU_C_TIMEZONE_API 1 @@ -333,6 +334,10 @@ double DateCache::parseDate(JSGlobalObject* globalObject, VM& vm, const String& // https://tc39.es/ecma402/#sec-defaulttimezone String DateCache::defaultTimeZone() { + String tz = WTF::timeZoneForAutomation(); + if (!tz.isEmpty()) + return tz; + #if HAVE(ICU_C_TIMEZONE_API) auto& timeZone = *timeZoneCache(); Vector buffer; @@ -382,16 +387,29 @@ Ref DateCache::cachedDateInstanceData(double millisecondsFromE void DateCache::timeZoneCacheSlow() { ASSERT(!m_timeZoneCache); + + String override = WTF::timeZoneForAutomation(); #if HAVE(ICU_C_TIMEZONE_API) auto* cache = new OpaqueICUTimeZone; + // ucal_open checks that the status is success, so it has to be initialized here. + UErrorCode status = U_ZERO_ERROR; Vector timeZoneID; - auto status = callBufferProducingFunction(ucal_getHostTimeZone, timeZoneID); - ASSERT_UNUSED(status, U_SUCCESS(status)); + if (override.isEmpty()) { + status = callBufferProducingFunction(ucal_getHostTimeZone, timeZoneID); + ASSERT_UNUSED(status, U_SUCCESS(status)); + } else { + timeZoneID = override.charactersWithoutNullTermination(); + } cache->m_calendar = std::unique_ptr>(ucal_open(timeZoneID.data(), timeZoneID.size(), "", UCAL_DEFAULT, &status)); ASSERT_UNUSED(status, U_SUCCESS(status)); ucal_setGregorianChange(cache->m_calendar.get(), minECMAScriptTime, &status); // Ignore "unsupported" error. m_timeZoneCache = std::unique_ptr(cache); #else + if (!override.isEmpty()) { + auto* timezone = icu::TimeZone::createTimeZone(override.utf8().data()); + m_timeZoneCache = std::unique_ptr(bitwise_cast(timezone)); + return; + } // Do not use icu::TimeZone::createDefault. ICU internally has a cache for timezone and createDefault returns this cached value. m_timeZoneCache = std::unique_ptr(bitwise_cast(icu::TimeZone::detectHostTimeZone())); #endif diff --git a/Source/ThirdParty/libwebrtc/CMakeLists.txt b/Source/ThirdParty/libwebrtc/CMakeLists.txt index 4345be38811965680c7c8e80d64234e130b16548..d8ea7866e3df2d8dcc6adc7a0dd021c4b96d4249 100644 --- a/Source/ThirdParty/libwebrtc/CMakeLists.txt +++ b/Source/ThirdParty/libwebrtc/CMakeLists.txt @@ -292,6 +292,11 @@ set(webrtc_SOURCES Source/third_party/jsoncpp/source/src/lib_json/json_reader.cpp Source/third_party/jsoncpp/source/src/lib_json/json_value.cpp Source/third_party/jsoncpp/source/src/lib_json/json_writer.cpp +# Playwright begin + Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc + Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc + Source/third_party/libwebm/mkvmuxer/mkvwriter.cc +# Playwright end Source/third_party/libyuv/source/compare_common.cc Source/third_party/libyuv/source/compare_gcc.cc Source/third_party/libyuv/source/convert.cc @@ -1732,6 +1737,10 @@ set(webrtc_INCLUDE_DIRECTORIES PRIVATE Source/third_party/libsrtp/config Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include +# Playwright begin + Source/third_party/libwebm + Source/third_party/libvpx/source/libvpx +# Playwright end Source/third_party/libyuv/include Source/third_party/opus/src/celt Source/third_party/opus/src/include diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp index 09d3ccf527d7256f6c87d5c03a2e586590bec687..922af4fceee45d28bf9bb75458f05144477fdcb4 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.mac.exp @@ -324,3 +324,23 @@ __ZN6webrtc30PeerConnectionFactoryInterface20CreatePeerConnectionERKNS_23PeerCon __ZNK3rtc13SocketAddress4HashEv __ZNK3rtc13SocketAddresseqERKS0_ __ZNK3rtc9IPAddress5IsNilEv +__ZN8mkvmuxer11SegmentInfo15set_writing_appEPKc +__ZN8mkvmuxer11SegmentInfo4InitEv +__ZN8mkvmuxer7Segment10OutputCuesEb +__ZN8mkvmuxer7Segment13AddVideoTrackEiii +__ZN8mkvmuxer7Segment4InitEPNS_10IMkvWriterE +__ZN8mkvmuxer7Segment8AddFrameEPKhyyyb +__ZN8mkvmuxer7Segment8FinalizeEv +__ZN8mkvmuxer7SegmentC1Ev +__ZN8mkvmuxer7SegmentD1Ev +__ZN8mkvmuxer9MkvWriterC1EP7__sFILE +_ARGBToI420 +_vpx_codec_enc_config_default +_vpx_codec_enc_init_ver +_vpx_codec_encode +_vpx_codec_err_to_string +_vpx_codec_error +_vpx_codec_get_cx_data +_vpx_codec_iface_name +_vpx_codec_version_str +_vpx_codec_vp8_cx diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig index dd884b22250114627213c4827ca176c283ec2525..9927a937145f23d05e907083a01748dd8015eb98 100644 --- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig +++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.xcconfig @@ -43,7 +43,7 @@ DYLIB_INSTALL_NAME_BASE_WK_RELOCATABLE_FRAMEWORKS_ = $(DYLIB_INSTALL_NAME_BASE); DYLIB_INSTALL_NAME_BASE_WK_RELOCATABLE_FRAMEWORKS_YES = @loader_path/../../../; GCC_WARN_64_TO_32_BIT_CONVERSION = NO; -HEADER_SEARCH_PATHS = Source Source/third_party/jsoncpp/source/include Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/third_party/usrsctp Source/third_party/usrsctp/usrsctplib Source/third_party/usrsctp/usrsctplib/usrsctplib Source/webrtc/sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/third_party/usrsctp/usrsctplib/usrsctplib/netinet Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/sdk/objc Source/webrtc/sdk/objc/base Source/webrtc/sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/sdk/objc/Framework/Classes/Common Source/webrtc/sdk/objc/Framework/Classes/Video Source/webrtc/sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include; +HEADER_SEARCH_PATHS = Source Source/third_party/jsoncpp/source/include Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/third_party/usrsctp Source/third_party/usrsctp/usrsctplib Source/third_party/usrsctp/usrsctplib/usrsctplib Source/webrtc/sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/third_party/usrsctp/usrsctplib/usrsctplib/netinet Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/sdk/objc Source/webrtc/sdk/objc/base Source/webrtc/sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/sdk/objc/Framework/Classes/Common Source/webrtc/sdk/objc/Framework/Classes/Video Source/webrtc/sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include Source/third_party/libvpx/source/libvpx/third_party/libwebm; PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libwebrtc; USE_HEADERMAP = NO; diff --git a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj index d8677555342ee0168223a0bc3ef54603b1a23460..b9ee7198a702cbc0241de3a33b65a6940ad48bc6 100644 --- a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj +++ b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj @@ -3856,6 +3856,9 @@ CDFD2FCC24C4DAF70048DAC3 /* reader.h in Copy webm headers */ = {isa = PBXBuildFile; fileRef = CDEBB40524C0191A00ADBD44 /* reader.h */; }; CDFD2FCD24C4DAF70048DAC3 /* status.h in Copy webm headers */ = {isa = PBXBuildFile; fileRef = CDEBB40624C0191A00ADBD44 /* status.h */; }; CDFD2FCE24C4DAF70048DAC3 /* webm_parser.h in Copy webm headers */ = {isa = PBXBuildFile; fileRef = CDEBB40824C0191A00ADBD44 /* webm_parser.h */; }; + F3B7819924C7CC5200FCB122 /* mkvmuxerutil.cc in Sources */ = {isa = PBXBuildFile; fileRef = F3B7819624C7CC5100FCB122 /* mkvmuxerutil.cc */; }; + F3B7819A24C7CC5200FCB122 /* mkvmuxer.cc in Sources */ = {isa = PBXBuildFile; fileRef = F3B7819724C7CC5200FCB122 /* mkvmuxer.cc */; }; + F3B7819B24C7CC5200FCB122 /* mkvwriter.cc in Sources */ = {isa = PBXBuildFile; fileRef = F3B7819824C7CC5200FCB122 /* mkvwriter.cc */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ @@ -8318,6 +8321,9 @@ CDEBB49D24C0191A00ADBD44 /* master_parser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = master_parser.h; sourceTree = ""; }; CDFD2F9624C4B2F90048DAC3 /* vp9_header_parser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vp9_header_parser.h; sourceTree = ""; }; CDFD2F9A24C4B2F90048DAC3 /* vp9_header_parser.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vp9_header_parser.cc; sourceTree = ""; }; + F3B7819624C7CC5100FCB122 /* mkvmuxerutil.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mkvmuxerutil.cc; path = mkvmuxer/mkvmuxerutil.cc; sourceTree = ""; }; + F3B7819724C7CC5200FCB122 /* mkvmuxer.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mkvmuxer.cc; path = mkvmuxer/mkvmuxer.cc; sourceTree = ""; }; + F3B7819824C7CC5200FCB122 /* mkvwriter.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mkvwriter.cc; path = mkvmuxer/mkvwriter.cc; sourceTree = ""; }; FB39D0D11200F0E300088E69 /* libwebrtc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libwebrtc.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -15298,6 +15304,7 @@ isa = PBXGroup; children = ( CDFD2F9224C4B2F90048DAC3 /* common */, + F3B7819524C7CC1300FCB122 /* mkvmuxer */, CDEBB19224C0191800ADBD44 /* webm_parser */, ); path = libwebm; @@ -15432,6 +15439,16 @@ path = common; sourceTree = ""; }; + F3B7819524C7CC1300FCB122 /* mkvmuxer */ = { + isa = PBXGroup; + children = ( + F3B7819724C7CC5200FCB122 /* mkvmuxer.cc */, + F3B7819624C7CC5100FCB122 /* mkvmuxerutil.cc */, + F3B7819824C7CC5200FCB122 /* mkvwriter.cc */, + ); + name = mkvmuxer; + sourceTree = ""; + }; FB39D06E1200ED9200088E69 = { isa = PBXGroup; children = ( @@ -17491,7 +17508,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "PRIVATE_HEADERS_FOLDER_PATH=usr/local/include\n\nif [[ \"${DEPLOYMENT_LOCATION}\" == \"NO\" ]]; then\n PRIVATE_HEADERS_PATH=\"${TARGET_BUILD_DIR%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nelse\n PRIVATE_HEADERS_PATH=\"${DSTROOT}${INSTALL_PATH_PREFIX%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nfi;\n\nmkdir -p \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/webrtc\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/abseil-cpp/absl\" \"${PRIVATE_HEADERS_PATH}\"\n"; + shellScript = "PRIVATE_HEADERS_FOLDER_PATH=usr/local/include\n\nif [[ \"${DEPLOYMENT_LOCATION}\" == \"NO\" ]]; then\n PRIVATE_HEADERS_PATH=\"${TARGET_BUILD_DIR%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nelse\n PRIVATE_HEADERS_PATH=\"${DSTROOT}${INSTALL_PATH_PREFIX%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nfi;\n\nmkdir -p \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/webrtc\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/abseil-cpp/absl\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libyuv/include/\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --exclude \"src\" --exclude \"internal\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libvpx/source/libvpx/vpx\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libwebm/\" \"${PRIVATE_HEADERS_PATH}\"\n"; }; 5CD286461E6E154E0094FDC8 /* Check for Weak VTables and Externals */ = { isa = PBXShellScriptBuildPhase; @@ -18634,6 +18651,7 @@ 419C82F51FE20EB50040C30F /* audio_encoder_opus.cc in Sources */, 419C82F31FE20EB50040C30F /* audio_encoder_opus_config.cc in Sources */, 4140B8201E4E3383007409E6 /* audio_encoder_pcm.cc in Sources */, + F3B7819A24C7CC5200FCB122 /* mkvmuxer.cc in Sources */, 5CDD8FFE1E43CE3A00621E92 /* audio_encoder_pcm16b.cc in Sources */, 5CD285461E6A61D20094FDC8 /* audio_format.cc in Sources */, 41DDB26F212679D200296D47 /* audio_format_to_string.cc in Sources */, @@ -19071,6 +19089,7 @@ 417953DB216983910028266B /* metrics.cc in Sources */, 5CDD865E1E43B8B500621E92 /* min_max_operations.c in Sources */, 4189395B242A71F5007FDC41 /* min_video_bitrate_experiment.cc in Sources */, + F3B7819B24C7CC5200FCB122 /* mkvwriter.cc in Sources */, 4131C387234B957D0028A615 /* moving_average.cc in Sources */, 41FCBB1521B1F7AA00A5DF27 /* moving_average.cc in Sources */, 5CD286101E6A64C90094FDC8 /* moving_max.cc in Sources */, @@ -19303,6 +19322,7 @@ 4131C53B234C8B190028A615 /* rtc_event_rtp_packet_outgoing.cc in Sources */, 4131C552234C8B190028A615 /* rtc_event_video_receive_stream_config.cc in Sources */, 4131C554234C8B190028A615 /* rtc_event_video_send_stream_config.cc in Sources */, + F3B7819924C7CC5200FCB122 /* mkvmuxerutil.cc in Sources */, 4131C3CF234B98420028A615 /* rtc_stats.cc in Sources */, 41323A1D2665288B00B38623 /* packet_sequencer.cc in Sources */, 4131BF2D234B88200028A615 /* rtc_stats_collector.cc in Sources */, diff --git a/Source/WTF/Scripts/Preferences/WebPreferences.yaml b/Source/WTF/Scripts/Preferences/WebPreferences.yaml index e7331574bbfe695080432c506a393ed218d0e651..8333ecf890ba03175aa5fa9afe89217f6a377f4c 100644 --- a/Source/WTF/Scripts/Preferences/WebPreferences.yaml +++ b/Source/WTF/Scripts/Preferences/WebPreferences.yaml @@ -1010,7 +1010,7 @@ InspectorStartsAttached: exposed: [ WebKit ] defaultValue: WebKit: - default: true + default: false InspectorWindowFrame: type: String diff --git a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml index 9ecb7a3d6b39ca23ddd3258326a1fdc2f016ce30..743a455ad64684fd9fc35e4cd92056a9ba744e52 100644 --- a/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml +++ b/Source/WTF/Scripts/Preferences/WebPreferencesExperimental.yaml @@ -622,9 +622,9 @@ MaskWebGLStringsEnabled: WebKitLegacy: default: true WebKit: - default: true + default: false WebCore: - default: true + default: false # FIXME: This is on by default in WebKit2. Perhaps we should consider turning it on for WebKitLegacy as well. MediaCapabilitiesExtensionsEnabled: @@ -964,7 +964,7 @@ SpeechRecognitionEnabled: WebKitLegacy: default: false WebKit: - "HAVE(SPEECHRECOGNIZER) && ENABLE(MEDIA_STREAM)": true + "ENABLE(MEDIA_STREAM)": true default: false WebCore: default: false diff --git a/Source/WTF/wtf/DateMath.cpp b/Source/WTF/wtf/DateMath.cpp index ebd69a4c76cd7acb0a233be552071158ca2171ca..2ee388e94a56d3de9c9fb2506d2ddead2db1ef87 100644 --- a/Source/WTF/wtf/DateMath.cpp +++ b/Source/WTF/wtf/DateMath.cpp @@ -76,9 +76,14 @@ #include #include #include +#include #include #include +#include +#include +#include #include +#include #if OS(WINDOWS) #include @@ -92,6 +97,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" }; @@ -318,6 +335,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 @@ -1016,4 +1041,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 de0b45bd0a88eaba466b6e6c0ad66dc02f525741..81857a2be24fa3ff0a60ebbcd01130969456b31e 100644 --- a/Source/WTF/wtf/DateMath.h +++ b/Source/WTF/wtf/DateMath.h @@ -388,6 +388,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/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h index d10aa42b80a2b576c9e8c5c699a5d8b0ee2d8009..94ebea19af93d8282246c6af6e8d4a1e3e35fe40 100644 --- a/Source/WTF/wtf/PlatformEnable.h +++ b/Source/WTF/wtf/PlatformEnable.h @@ -413,7 +413,7 @@ #endif #if !defined(ENABLE_ORIENTATION_EVENTS) -#define ENABLE_ORIENTATION_EVENTS 0 +#define ENABLE_ORIENTATION_EVENTS 1 #endif #if OS(WINDOWS) @@ -478,7 +478,7 @@ #endif #if !defined(ENABLE_TOUCH_EVENTS) -#define ENABLE_TOUCH_EVENTS 0 +#define ENABLE_TOUCH_EVENTS 1 #endif #if !defined(ENABLE_TOUCH_ACTION_REGIONS) diff --git a/Source/WTF/wtf/PlatformGTK.cmake b/Source/WTF/wtf/PlatformGTK.cmake index 9bd5fde5bc38355e25bc09d05a045df31efaa259..3f3be653fef9930a7ac8a348c8b9f9a281eea363 100644 --- a/Source/WTF/wtf/PlatformGTK.cmake +++ b/Source/WTF/wtf/PlatformGTK.cmake @@ -73,6 +73,7 @@ list(APPEND WTF_LIBRARIES ${GLIB_LIBRARIES} Threads::Threads ZLIB::ZLIB + stdc++fs ) if (Systemd_FOUND) diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h index 1456b7717e8f75c28f841da6d728f9a7e2518b24..468ede9b8a2e14857281b456dd8832407fd09e12 100644 --- a/Source/WTF/wtf/PlatformHave.h +++ b/Source/WTF/wtf/PlatformHave.h @@ -391,7 +391,7 @@ #define HAVE_NSHTTPCOOKIESTORAGE__INITWITHIDENTIFIER_WITH_INACCURATE_NULLABILITY 1 #endif -#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(MACCATALYST) +#if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(MACCATALYST) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN) #define HAVE_OS_DARK_MODE_SUPPORT 1 #endif diff --git a/Source/WTF/wtf/PlatformWPE.cmake b/Source/WTF/wtf/PlatformWPE.cmake index a840a487ff03a3c827455cab67faa8f83d20bfa9..29dd6a14f17295f1611451e6f53866175c8748d8 100644 --- a/Source/WTF/wtf/PlatformWPE.cmake +++ b/Source/WTF/wtf/PlatformWPE.cmake @@ -47,6 +47,7 @@ list(APPEND WTF_LIBRARIES ${GLIB_LIBRARIES} Threads::Threads ZLIB::ZLIB + stdc++fs ) if (Systemd_FOUND) diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make index 6c1bb60d7681b205d1dc66409daf932c3ac51ff9..06d3d504a41e848781038fb01b4d99dd17848899 100644 --- a/Source/WebCore/DerivedSources.make +++ b/Source/WebCore/DerivedSources.make @@ -778,6 +778,10 @@ JS_BINDING_IDLS := \ $(WebCore)/dom/Slotable.idl \ $(WebCore)/dom/StaticRange.idl \ $(WebCore)/dom/StringCallback.idl \ + $(WebCore)/dom/Document+Touch.idl \ + $(WebCore)/dom/Touch.idl \ + $(WebCore)/dom/TouchEvent.idl \ + $(WebCore)/dom/TouchList.idl \ $(WebCore)/dom/Text.idl \ $(WebCore)/dom/TextDecoder.idl \ $(WebCore)/dom/TextDecoderStream.idl \ @@ -1307,9 +1311,6 @@ JS_BINDING_IDLS := \ ADDITIONAL_BINDING_IDLS = \ DocumentTouch.idl \ GestureEvent.idl \ - Touch.idl \ - TouchEvent.idl \ - TouchList.idl \ # vpath %.in $(WEBKITADDITIONS_HEADER_SEARCH_PATHS) diff --git a/Source/WebCore/Modules/geolocation/Geolocation.cpp b/Source/WebCore/Modules/geolocation/Geolocation.cpp index 7995d4dd461de036cd8691b3ff181aeaefb12d92..49207cd294acebb4bac53ecb28817baa827d389f 100644 --- a/Source/WebCore/Modules/geolocation/Geolocation.cpp +++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp @@ -358,8 +358,9 @@ bool Geolocation::shouldBlockGeolocationRequests() bool isSecure = SecurityOrigin::isSecure(document()->url()) || document()->isSecureContext(); bool hasMixedContent = !document()->foundMixedContent().isEmpty(); bool isLocalOrigin = securityOrigin()->isLocal(); + bool isPotentiallyTrustworthy = securityOrigin()->isPotentiallyTrustworthy(); if (securityOrigin()->canRequestGeolocation()) { - if (isLocalOrigin || (isSecure && !hasMixedContent) || isRequestFromIBooks()) + if (isLocalOrigin || isPotentiallyTrustworthy || (isSecure && !hasMixedContent) || isRequestFromIBooks()) return false; } diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm index f1b96958057d2fe6044d2c7b259db6c5ceb44efe..29e51dad380285fb16bd32ef04efde2ac4ed6479 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm @@ -202,6 +202,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available { + UNUSED_PARAM(speechRecognizer); ASSERT(isMainThread()); if (available || !_task) @@ -215,6 +216,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self sendSpeechStartIfNeeded]; @@ -223,6 +225,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self callbackWithTranscriptions:recognitionResult.transcriptions isFinal:YES]; @@ -234,6 +237,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task { + UNUSED_PARAM(task); ASSERT(isMainThread()); [self sendSpeechEndIfNeeded]; diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm index 66cec91542b74765a9c1ffbc2f28e1a5085c55e0..9a2a89a09279b3b7102282de6bfc4cc7e2b5925f 100644 --- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm +++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTaskMock.mm @@ -36,6 +36,9 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithIdentifier:(SpeechRecognitionConnectionClientIdentifier)identifier locale:(NSString*)localeIdentifier doMultipleRecognitions:(BOOL)continuous reportInterimResults:(BOOL)interimResults maxAlternatives:(unsigned long)alternatives delegateCallback:(void(^)(const SpeechRecognitionUpdate&))callback { + UNUSED_PARAM(localeIdentifier); + UNUSED_PARAM(interimResults); + UNUSED_PARAM(alternatives); if (!(self = [super init])) return nil; @@ -51,6 +54,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)audioSamplesAvailable:(CMSampleBufferRef)sampleBuffer { + UNUSED_PARAM(sampleBuffer); if (!_hasSentSpeechStart) { _hasSentSpeechStart = true; _delegateCallback(SpeechRecognitionUpdate::create(_identifier, SpeechRecognitionUpdateType::SpeechStart)); diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake index 9d4f3bd1ade02a378340961d617aae1c5e0776a3..17b2b6cfb52d94d8104b68b9250883c40f69f975 100644 --- a/Source/WebCore/PlatformWPE.cmake +++ b/Source/WebCore/PlatformWPE.cmake @@ -38,6 +38,7 @@ list(APPEND WebCore_PRIVATE_INCLUDE_DIRECTORIES list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/wayland/PlatformDisplayWayland.h platform/graphics/wayland/WlUniquePtr.h + platform/wpe/SelectionData.h ) list(APPEND WebCore_USER_AGENT_STYLE_SHEETS diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt index 682dbcc06ceae7d76c1e0e9a66abf427e1ccb49b..9548501875df91a2901d01cfcdf9c4c43170c026 100644 --- a/Source/WebCore/SourcesCocoa.txt +++ b/Source/WebCore/SourcesCocoa.txt @@ -620,3 +620,9 @@ platform/graphics/angle/TemporaryANGLESetting.cpp @no-unify // Derived Sources WHLSLStandardLibraryFunctionMap.cpp + +// Playwright begin +JSTouch.cpp +JSTouchEvent.cpp +JSTouchList.cpp +// Playwright end diff --git a/Source/WebCore/SourcesWPE.txt b/Source/WebCore/SourcesWPE.txt index b10c1ece52075b7535da51c2cc316dc9343fd081..8520d6b90ccb2aa2762d83fab0f63c1e7107aed3 100644 --- a/Source/WebCore/SourcesWPE.txt +++ b/Source/WebCore/SourcesWPE.txt @@ -44,6 +44,8 @@ editing/libwpe/EditorLibWPE.cpp loader/soup/ResourceLoaderSoup.cpp +page/wpe/DragControllerWPE.cpp + page/linux/ResourceUsageOverlayLinux.cpp page/linux/ResourceUsageThreadLinux.cpp @@ -86,8 +88,12 @@ platform/text/LocaleICU.cpp platform/unix/LoggingUnix.cpp +platform/wpe/DragDataWPE.cpp +platform/wpe/DragImageWPE.cpp platform/wpe/PlatformScreenWPE.cpp platform/xdg/MIMETypeRegistryXdg.cpp rendering/RenderThemeAdwaita.cpp + +platform/wpe/SelectionData.cpp diff --git a/Source/WebCore/WebCore.order b/Source/WebCore/WebCore.order index ef168b76819216d984b7a2d0f760005fb9d24de8..2d6cf51f3b45191ad84106429d4f108f85679123 100644 --- a/Source/WebCore/WebCore.order +++ b/Source/WebCore/WebCore.order @@ -3093,7 +3093,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 4400180f792059769c250476e0b1e5da164e6232..b03ad6d912bfbfc3e10d988832cecf62fecf2948 100644 --- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj @@ -5349,6 +5349,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, ); }; }; F12171F616A8CF0B000053CA /* WebVTTElement.h in Headers */ = {isa = PBXBuildFile; fileRef = F12171F416A8BC63000053CA /* WebVTTElement.h */; }; F32BDCD92363AACA0073B6AE /* UserGestureEmulationScope.h in Headers */ = {isa = PBXBuildFile; fileRef = F32BDCD72363AACA0073B6AE /* UserGestureEmulationScope.h */; }; F344C7141125B82C00F26EEE /* InspectorFrontendClient.h in Headers */ = {isa = PBXBuildFile; fileRef = F344C7121125B82C00F26EEE /* InspectorFrontendClient.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -16861,6 +16869,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 = ""; }; @@ -22481,7 +22497,12 @@ 93D6B7A62551D3ED0058DD3A /* DummySpeechRecognitionProvider.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 */, @@ -28199,6 +28220,8 @@ 29E4D8DF16B0940F00C84704 /* PlatformSpeechSynthesizer.h */, 1AD8F81A11CAB9E900E93E54 /* PlatformStrategies.cpp */, 1AD8F81911CAB9E900E93E54 /* PlatformStrategies.h */, + F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */, + F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */, 0FD7C21D23CE41E30096D102 /* PlatformWheelEvent.cpp */, 935C476A09AC4D4F00A6AAB4 /* PlatformWheelEvent.h */, BCBB8AB513F1AFB000734DF0 /* PODInterval.h */, @@ -30633,6 +30656,7 @@ BCCFBAE70B5152ED0001F1D7 /* DocumentParser.h */, AD6E71AA1668899D00320C13 /* DocumentSharedObjectPool.cpp */, AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */, + F050E17323AD6A800011CE47 /* DocumentTouch.cpp */, 6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */, 6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */, 7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */, @@ -31641,6 +31665,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 */, @@ -33677,6 +33702,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 */, @@ -35741,9 +35767,11 @@ B2C3DA3A0D006C1D00EF6F26 /* TextCodec.h in Headers */, 26E98A10130A9FCA008EB7B2 /* TextCodecASCIIFastPath.h in Headers */, DF95B14A24FDAFD300B1F4D7 /* TextCodecCJK.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 */, @@ -36705,6 +36733,7 @@ 1ABA76CA11D20E50004C201C /* CSSPropertyNames.cpp in Sources */, 2D22830323A8470700364B7E /* CursorMac.mm in Sources */, 5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */, + F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */, 6E72F54C229DCD0C00B3E151 /* ExtensionsGLANGLE.cpp in Sources */, 7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */, 5130F2F624AEA60A00E1D0A0 /* GameControllerSoftLink.mm in Sources */, @@ -36791,6 +36820,7 @@ 6E72F54F229DCD1300B3E151 /* TemporaryANGLESetting.cpp in Sources */, CE88EE262414467B007F29C2 /* TextAlternativeWithRange.mm in Sources */, 51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */, + F050E17123AD669F0011CE47 /* TouchEvent.cpp in Sources */, 538EC8031F96AF81004D22A8 /* UnifiedSource1-mm.mm in Sources */, 538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */, 538EC8051F96AF81004D22A8 /* UnifiedSource2-mm.mm in Sources */, @@ -36839,6 +36869,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 */, @@ -37371,6 +37402,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/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp index 4436fd8ca990af2e5cc147047fc39c2470104e64..9ebf2f8e499066a5e7461cfa1f8287f54a12e60c 100644 --- a/Source/WebCore/accessibility/AccessibilityObject.cpp +++ b/Source/WebCore/accessibility/AccessibilityObject.cpp @@ -59,6 +59,7 @@ #include "HTMLParserIdioms.h" #include "HTMLTextAreaElement.h" #include "HitTestResult.h" +#include "InspectorInstrumentation.h" #include "LocalizedStrings.h" #include "MathMLNames.h" #include "NodeList.h" @@ -3271,10 +3272,15 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const if (useParentData ? m_isIgnoredFromParentData.isPresentationalChildOfAriaRole : isPresentationalChildOfAriaRole()) return AccessibilityObjectInclusion::IgnoreObject; - - return accessibilityPlatformIncludesObject(); + + AccessibilityObjectInclusion platformBehavior = accessibilityPlatformIncludesObject(); + if (platformBehavior != AccessibilityObjectInclusion::DefaultBehavior) { + if (auto* page = this->page()) + InspectorInstrumentation::maybeOverrideDefaultObjectInclusion(*page, platformBehavior); + } + return platformBehavior; } - + bool AccessibilityObject::accessibilityIsIgnored() const { AXComputedObjectAttributeCache* attributeCache = nullptr; diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h index 7790e27189a050ff4a8c37e431b01632975d27a4..8660a68fcba1d3950305669a2cbb3f36771cc9c8 100644 --- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h +++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h @@ -88,6 +88,8 @@ namespace WebCore { macro(Database) \ macro(DataTransferItem) \ macro(DataTransferItemList) \ + macro(DeviceMotionEvent) \ + macro(DeviceOrientationEvent) \ macro(DocumentTimeline) \ macro(EnterPictureInPictureEvent) \ macro(ExtendableEvent) \ diff --git a/Source/WebCore/css/MediaQueryEvaluator.cpp b/Source/WebCore/css/MediaQueryEvaluator.cpp index a47b2fe549a89414a207864aabe897d07a59727c..53357bc9ce111bcb1241256647c3630ae767213d 100644 --- a/Source/WebCore/css/MediaQueryEvaluator.cpp +++ b/Source/WebCore/css/MediaQueryEvaluator.cpp @@ -844,7 +844,11 @@ static bool prefersContrastEvaluate(CSSValue* value, const CSSToLengthConversion static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConversionData&, Frame& frame, MediaFeaturePrefix) { bool userPrefersReducedMotion = false; - + + std::optional reducedMotionOverride = frame.page()->useReducedMotionOverride(); + if (reducedMotionOverride) + userPrefersReducedMotion = reducedMotionOverride.value(); + else { switch (frame.settings().forcedPrefersReducedMotionAccessibilityValue()) { case ForcedAccessibilityValue::On: userPrefersReducedMotion = true; @@ -857,6 +861,7 @@ static bool prefersReducedMotionEvaluate(CSSValue* value, const CSSToLengthConve #endif break; } + } if (!value) return userPrefersReducedMotion; diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp index 1deac4f41cf49f1f882dccefd48cf6a9732f3ed9..c691eeccd75fc76f5df367b9fb5b95435e92ab79 100644 --- a/Source/WebCore/dom/DataTransfer.cpp +++ b/Source/WebCore/dom/DataTransfer.cpp @@ -494,6 +494,14 @@ Ref DataTransfer::createForDrag(const Document& document) return adoptRef(*new DataTransfer(StoreMode::ReadWrite, Pasteboard::createForDragAndDrop(PagePasteboardContext::create(document.pageID())), Type::DragAndDropData)); } +#if PLATFORM(MAC) +Ref DataTransfer::createForDrag(const Document& document, const String& pasteboardName) +{ + return adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique(PagePasteboardContext::create(document.pageID()), pasteboardName), Type::DragAndDropData)); +} +#endif + + Ref DataTransfer::createForDragStartEvent(const Document& document) { auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique(), Type::DragAndDropData)); diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h index b084ee416512652220e43a6d4bcccaff7c666d5a..b250f3d0161817efef7e2634a16713b0a0f1fa71 100644 --- a/Source/WebCore/dom/DataTransfer.h +++ b/Source/WebCore/dom/DataTransfer.h @@ -90,6 +90,9 @@ public: #if ENABLE(DRAG_SUPPORT) static Ref createForDrag(const Document&); +#if PLATFORM(MAC) + static Ref createForDrag(const Document&, const String& pasteboardName); +#endif static Ref createForDragStartEvent(const Document&); static Ref createForDrop(const Document&, std::unique_ptr&&, OptionSet, bool draggingFiles); static Ref createForUpdatingDropTarget(const Document&, std::unique_ptr&&, OptionSet, bool draggingFiles); diff --git a/Source/WebCore/dom/DeviceMotionEvent.idl b/Source/WebCore/dom/DeviceMotionEvent.idl index cb64adcd7af56fb2977d2403b110ff3fb74c4408..ba037ac019ed8c47fd73df234a88cbef6f7254d8 100644 --- a/Source/WebCore/dom/DeviceMotionEvent.idl +++ b/Source/WebCore/dom/DeviceMotionEvent.idl @@ -25,6 +25,7 @@ [ Conditional=DEVICE_ORIENTATION, + EnabledBySetting=DeviceOrientationEvent, Exposed=Window ] interface DeviceMotionEvent : Event { readonly attribute Acceleration? acceleration; diff --git a/Source/WebCore/dom/DeviceOrientationEvent.idl b/Source/WebCore/dom/DeviceOrientationEvent.idl index 1c1cbc1f55089ea7c73c83f04db3caddc5a8b3b3..f1ccf42cf7f699747b31873ab9d96b3f7afc8fd3 100644 --- a/Source/WebCore/dom/DeviceOrientationEvent.idl +++ b/Source/WebCore/dom/DeviceOrientationEvent.idl @@ -25,6 +25,7 @@ [ Conditional=DEVICE_ORIENTATION, + EnabledBySetting=DeviceOrientationEvent, Exposed=Window ] interface DeviceOrientationEvent : Event { readonly attribute unrestricted double? alpha; diff --git a/Source/WebCore/dom/PointerEvent.cpp b/Source/WebCore/dom/PointerEvent.cpp index f21879fdfbc64e7d2f11ab084d46794a9e601110..151c9b72f0f552c2ff741305c4c0a8c7f51a92e3 100644 --- a/Source/WebCore/dom/PointerEvent.cpp +++ b/Source/WebCore/dom/PointerEvent.cpp @@ -114,4 +114,61 @@ EventInterface PointerEvent::eventInterface() const return PointerEventInterfaceType; } +#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) + +static const AtomString& pointerEventType(PlatformTouchPoint::State state) +{ + switch (state) { + case PlatformTouchPoint::State::TouchPressed: + return eventNames().pointerdownEvent; + case PlatformTouchPoint::State::TouchMoved: + return eventNames().pointermoveEvent; + case PlatformTouchPoint::State::TouchStationary: + return eventNames().pointermoveEvent; + case PlatformTouchPoint::State::TouchReleased: + return eventNames().pointerupEvent; + case PlatformTouchPoint::State::TouchCancelled: + return eventNames().pointercancelEvent; + case PlatformTouchPoint::State::TouchStateEnd: + break; + } + ASSERT_NOT_REACHED(); + return nullAtom(); +} + +static short buttonForType(const AtomString& type) +{ + return type == eventNames().pointermoveEvent ? -1 : 0; +} + +static unsigned short buttonsForType(const AtomString& type) +{ + // We have contact with the touch surface for most events except when we've released the touch or canceled it. + return (type == eventNames().pointerupEvent || type == eventNames().pointeroutEvent || type == eventNames().pointerleaveEvent || type == eventNames().pointercancelEvent) ? 0 : 1; +} + +Ref PointerEvent::create(const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref&& view) +{ + const auto& type = pointerEventType(event.touchPoints().at(index).state()); + return adoptRef(*new PointerEvent(type, event, typeIsCancelable(type), index, isPrimary, WTFMove(view))); +} + +Ref PointerEvent::create(const String& type, const PlatformTouchEvent& event, unsigned index, bool isPrimary, Ref&& view) +{ + return adoptRef(*new PointerEvent(type, event, typeIsCancelable(type), index, isPrimary, WTFMove(view))); +} + +PointerEvent::PointerEvent(const AtomString& type, const PlatformTouchEvent& event, IsCancelable isCancelable, unsigned index, bool isPrimary, Ref&& view) + : MouseEvent(type, typeCanBubble(type), isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTFMove(view), 0, event.touchPoints().at(index).pos(), event.touchPoints().at(index).pos(), { }, event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, 0, IsSimulated::No, IsTrusted::Yes) + , m_pointerId(2) + , m_width(2 * event.touchPoints().at(index).radiusX()) + , m_height(2 * event.touchPoints().at(index).radiusY()) + , m_pressure(event.touchPoints().at(index).force()) + , m_pointerType(touchPointerEventType()) + , m_isPrimary(isPrimary) +{ +} + +#endif // ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) + } // namespace WebCore diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h index 9d60b85152f378566118574663701c25b001df3d..9811ce9aa6f066c57acf65f629d2ab8155c090e1 100644 --- a/Source/WebCore/dom/PointerEvent.h +++ b/Source/WebCore/dom/PointerEvent.h @@ -33,6 +33,8 @@ #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) #include "PlatformTouchEventIOS.h" +#else +#include "PlatformTouchEvent.h" #endif namespace WebCore { @@ -81,7 +83,7 @@ public: static Ref create(const String& type, short button, const MouseEvent&, PointerID, const String& pointerType); static Ref create(const String& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No); -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +#if ENABLE(TOUCH_EVENTS) static Ref create(const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref&&); static Ref create(const String& type, const PlatformTouchEvent&, unsigned touchIndex, bool isPrimary, Ref&&); #endif @@ -121,7 +123,7 @@ private: PointerEvent(const AtomString&, Init&&); PointerEvent(const AtomString& type, short button, const MouseEvent&, PointerID, const String& pointerType); PointerEvent(const AtomString& type, PointerID, const String& pointerType, IsPrimary); -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +#if ENABLE(TOUCH_EVENTS) PointerEvent(const AtomString& type, const PlatformTouchEvent&, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref&&); #endif diff --git a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp index 9dd41d6366512fd385937a7608bd3fc9b5b90f60..d6bb529fb891a65c8f6dcc6cff1e718c7a40b8dd 100644 --- a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp +++ b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp @@ -33,6 +33,7 @@ #include "NotImplemented.h" #include "Pasteboard.h" #include "Settings.h" +#include "WebContentReader.h" #include "markup.h" namespace WebCore { @@ -91,6 +92,14 @@ void Editor::pasteWithPasteboard(Pasteboard* pasteboard, OptionSet pasteAsFragment(*fragment, canSmartReplaceWithPasteboard(*pasteboard), chosePlainText, options.contains(PasteOption::IgnoreMailBlockquote) ? MailBlockquoteHandling::IgnoreBlockquote : MailBlockquoteHandling::RespectBlockquote); } +RefPtr Editor::webContentFromPasteboard(Pasteboard& pasteboard, const SimpleRange& context, bool allowPlainText, bool& chosePlainText) +{ + WebContentReader reader(*m_document.frame(), context, allowPlainText); + pasteboard.read(reader); + chosePlainText = reader.madeFragmentFromPlainText; + return WTFMove(reader.fragment); +} + } // namespace WebCore #endif // USE(LIBWPE) diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp index 50fc3c950f53eca3355c9fa8bc45a73a279b2a07..45994eb21c5034f9efaddb5569473b55b493a36e 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 "MIMETypeRegistry.h" #include "RenderFileUploadControl.h" @@ -212,6 +213,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 c33bc989d95a21425d43643795190cf40f7e9684..d54965c544b8cac7ebc1e9e408db8ae08e25be61 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp @@ -374,8 +374,8 @@ void InspectorController::inspect(Node* node) if (!enabled()) return; - if (!hasRemoteFrontend()) - show(); + // HACK: Always attempt to show inspector even if there is a remote connection. + show(); ensureDOMAgent().inspect(node); } @@ -516,4 +516,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 784bf482fd68da68e1f38fd5cd6bcedc8971dfda..6cdf012453ff31120adbe5946ce23f075761ebef 100644 --- a/Source/WebCore/inspector/InspectorController.h +++ b/Source/WebCore/inspector/InspectorController.h @@ -101,6 +101,10 @@ public: WEBCORE_EXPORT void willComposite(Frame&); WEBCORE_EXPORT void didComposite(Frame&); + WEBCORE_EXPORT void pauseWhenShown(); + WEBCORE_EXPORT void resumeIfPausedInNewWindow(); + WEBCORE_EXPORT void didShowNewWindow(); + // Testing support. bool isUnderTest() const { return m_isUnderTest; } void setIsUnderTest(bool isUnderTest) { m_isUnderTest = isUnderTest; } @@ -152,6 +156,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 c121523071a026888cbd608031ad15dc85af1719..c8557a307178db00b79e7e1c4156242b242bc7d1 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -641,6 +641,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.enabledPageRuntimeAgent()) + pageRuntimeAgent->didReceiveMainResourceError(frame); +} + void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents) { if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) @@ -673,20 +679,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents& void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { - if (!frame.isMainFrame()) - return; - if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->domContentEventFired(); + pageAgent->domContentEventFired(frame); } void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, Frame* frame) { - if (!frame || !frame->isMainFrame()) + if (!frame) return; if (auto* pageAgent = instrumentingAgents.enabledPageAgent()) - pageAgent->loadEventFired(); + pageAgent->loadEventFired(*frame); } void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) @@ -767,12 +770,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins pageDOMDebuggerAgent->frameDocumentUpdated(frame); } -void InspectorInstrumentation::loaderDetachedFromFrameImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader& loader) -{ - if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) - inspectorPageAgent->loaderDetachedFromFrame(loader); -} - void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { if (frame.isMainFrame()) { @@ -809,6 +806,12 @@ void InspectorInstrumentation::frameClearedScheduledNavigationImpl(Instrumenting inspectorPageAgent->frameClearedScheduledNavigation(frame); } +void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) +{ + if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.enabledPageAgent()) + inspectorPageAgent->didNavigateWithinPage(frame); +} + #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents, bool useDarkAppearance) { @@ -861,6 +864,24 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru networkAgent->interceptResponse(response, identifier, WTFMove(handler)); } +void InspectorInstrumentation::interceptDidReceiveDataImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, const SharedBuffer& buffer) +{ + if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) + networkAgent->interceptDidReceiveData(identifier, buffer); +} + +void InspectorInstrumentation::interceptDidFinishResourceLoadImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier) +{ + if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) + networkAgent->interceptDidFinishResourceLoad(identifier); +} + +void InspectorInstrumentation::interceptDidFailResourceLoadImpl(InstrumentingAgents& instrumentingAgents, unsigned long identifier, const ResourceError& error) +{ + if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent()) + networkAgent->interceptDidFailResourceLoad(identifier, error); +} + // JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes. static bool isConsoleAssertMessage(MessageSource source, MessageType type) { @@ -1328,6 +1349,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins layerTreeAgent->renderLayerDestroyed(renderLayer); } +void InspectorInstrumentation::runOpenPanelImpl(InstrumentingAgents& instrumentingAgents, HTMLInputElement* element, bool* intercept) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->runOpenPanel(element, intercept); +} + +void InspectorInstrumentation::frameAttachedImpl(InstrumentingAgents& instrumentingAgents, Frame& frame) { + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->frameAttached(frame); +} + +bool InspectorInstrumentation::shouldBypassCSPImpl(InstrumentingAgents& instrumentingAgents) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + return pageAgent->shouldBypassCSP(); + return false; +} + +void InspectorInstrumentation::willCheckNewWindowPolicyImpl(InstrumentingAgents& instrumentingAgents, const URL& url) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->willCheckNewWindowPolicy(url); +} + +void InspectorInstrumentation::didCheckNewWindowPolicyImpl(InstrumentingAgents& instrumentingAgents, bool allowed) +{ + if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent()) + pageAgent->didCheckNewWindowPolicy(allowed); +} + InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(WorkerOrWorkletGlobalScope& globalScope) { return globalScope.inspectorController().m_instrumentingAgents; @@ -1339,6 +1390,13 @@ InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(Page& page) return page.inspectorController().m_instrumentingAgents.get(); } +void InspectorInstrumentation::maybeOverrideDefaultObjectInclusion(Page& page, AccessibilityObjectInclusion& inclusion) { + if (InspectorPageAgent* pageAgent = instrumentingAgents(page).enabledPageAgent()) { + if (pageAgent->doingAccessibilitySnapshot()) + inclusion = AccessibilityObjectInclusion::DefaultBehavior; + } +} + InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext& context) { if (is(context)) diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index 7d5e7d57bf911fddf90ed400a225afa083e6c871..f217152b91bdd208556d125ea3b013e9a30882a4 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -31,6 +31,7 @@ #pragma once +#include "AccessibilityObjectInterface.h" #include "CSSSelector.h" #include "CanvasBase.h" #include "CanvasRenderingContext.h" @@ -79,6 +80,7 @@ class DOMWrapperWorld; class Document; class DocumentLoader; class EventListener; +class HTMLInputElement; class HTTPHeaderMap; class InspectorTimelineAgent; class InstrumentingAgents; @@ -201,6 +203,7 @@ public: static void didReceiveData(Frame*, unsigned long identifier, const uint8_t* 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(WorkerOrWorkletGlobalScope&, unsigned long identifier, ResourceRequest&); static void didReceiveResourceResponse(WorkerOrWorkletGlobalScope&, unsigned long identifier, const ResourceResponse&); @@ -227,11 +230,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&); #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) static void defaultAppearanceDidChange(Page&, bool useDarkAppearance); #endif @@ -242,6 +245,9 @@ public: static bool shouldInterceptResponse(const Frame&, const ResourceResponse&); static void interceptRequest(ResourceLoader&, Function&&); static void interceptResponse(const Frame&, const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); + static void interceptDidReceiveData(const Frame&, unsigned long identifier, const SharedBuffer&); + static void interceptDidFinishResourceLoad(const Frame&, unsigned long identifier); + static void interceptDidFailResourceLoad(const Frame&, unsigned long identifier, const ResourceError& error); static void addMessageToConsole(Page&, std::unique_ptr); static void addMessageToConsole(WorkerOrWorkletGlobalScope&, std::unique_ptr); @@ -325,6 +331,12 @@ 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 void willCheckNewWindowPolicy(Frame&, const URL&); + static void didCheckNewWindowPolicy(Frame&, bool allowed); + static void frontendCreated(); static void frontendDeleted(); static bool hasFrontends() { return InspectorInstrumentationPublic::hasFrontends(); } @@ -341,6 +353,8 @@ public: static void registerInstrumentingAgents(InstrumentingAgents&); static void unregisterInstrumentingAgents(InstrumentingAgents&); + static void maybeOverrideDefaultObjectInclusion(Page&, AccessibilityObjectInclusion&); + private: static void didClearWindowObjectInWorldImpl(InstrumentingAgents&, Frame&, DOMWrapperWorld&); static bool isDebuggerPausedImpl(InstrumentingAgents&); @@ -429,6 +443,7 @@ private: static void didReceiveDataImpl(InstrumentingAgents&, unsigned long identifier, const uint8_t* 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); @@ -439,11 +454,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&); #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) static void defaultAppearanceDidChangeImpl(InstrumentingAgents&, bool useDarkAppearance); #endif @@ -454,6 +469,9 @@ private: static bool shouldInterceptResponseImpl(InstrumentingAgents&, const ResourceResponse&); static void interceptRequestImpl(InstrumentingAgents&, ResourceLoader&, Function&&); static void interceptResponseImpl(InstrumentingAgents&, const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); + static void interceptDidReceiveDataImpl(InstrumentingAgents&, unsigned long identifier, const SharedBuffer&); + static void interceptDidFinishResourceLoadImpl(InstrumentingAgents&, unsigned long identifier); + static void interceptDidFailResourceLoadImpl(InstrumentingAgents&, unsigned long identifier, const ResourceError& error); static void addMessageToConsoleImpl(InstrumentingAgents&, std::unique_ptr); @@ -533,6 +551,12 @@ 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 void willCheckNewWindowPolicyImpl(InstrumentingAgents&, const URL&); + static void didCheckNewWindowPolicyImpl(InstrumentingAgents&, bool allowed); + static InstrumentingAgents& instrumentingAgents(Page&); static InstrumentingAgents& instrumentingAgents(WorkerOrWorkletGlobalScope&); @@ -1134,6 +1158,13 @@ inline void InspectorInstrumentation::didFailLoading(Frame* frame, DocumentLoade didFailLoadingImpl(*agents, identifier, loader, error); } +inline void InspectorInstrumentation::didReceiveMainResourceError(Frame& frame, const ResourceError& error) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + didReceiveMainResourceErrorImpl(*agents, frame, error); +} + inline void InspectorInstrumentation::didFailLoading(WorkerOrWorkletGlobalScope& globalScope, unsigned long identifier, const ResourceError& error) { didFailLoadingImpl(instrumentingAgents(globalScope), identifier, nullptr, error); @@ -1229,13 +1260,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(Frame& frame) frameDocumentUpdatedImpl(*agents, frame); } -inline void InspectorInstrumentation::loaderDetachedFromFrame(Frame& frame, DocumentLoader& loader) -{ - FAST_RETURN_IF_NO_FRONTENDS(void()); - if (auto* agents = instrumentingAgents(frame)) - loaderDetachedFromFrameImpl(*agents, loader); -} - inline void InspectorInstrumentation::frameStartedLoading(Frame& frame) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1264,6 +1288,13 @@ inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& fra frameClearedScheduledNavigationImpl(*agents, frame); } +inline void InspectorInstrumentation::didNavigateWithinPage(Frame& frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + didNavigateWithinPageImpl(*agents, frame); +} + #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page, bool useDarkAppearance) { @@ -1316,6 +1347,22 @@ inline void InspectorInstrumentation::interceptResponse(const Frame& frame, cons interceptResponseImpl(*agents, response, identifier, WTFMove(handler)); } +inline void InspectorInstrumentation::interceptDidReceiveData(const Frame& frame, unsigned long identifier, const SharedBuffer& buffer) +{ + if (auto* agents = instrumentingAgents(frame)) + interceptDidReceiveDataImpl(*agents, identifier, buffer); +} +inline void InspectorInstrumentation::interceptDidFinishResourceLoad(const Frame& frame, unsigned long identifier) +{ + if (auto* agents = instrumentingAgents(frame)) + interceptDidFinishResourceLoadImpl(*agents, identifier); +} +inline void InspectorInstrumentation::interceptDidFailResourceLoad(const Frame& frame, unsigned long identifier, const ResourceError& error) +{ + if (auto* agents = instrumentingAgents(frame)) + interceptDidFailResourceLoadImpl(*agents, identifier, error); +} + inline void InspectorInstrumentation::didOpenDatabase(Database& database) { FAST_RETURN_IF_NO_FRONTENDS(void()); @@ -1731,6 +1778,42 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren renderLayerDestroyedImpl(*agents, renderLayer); } +inline void InspectorInstrumentation::runOpenPanel(Frame* frame, HTMLInputElement* element, bool* intercept) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(*frame)) + runOpenPanelImpl(*agents, element, intercept); +} + +inline void InspectorInstrumentation::frameAttached(Frame* frame) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + frameAttachedImpl(*agents, *frame); +} + +inline bool InspectorInstrumentation::shouldBypassCSP(ScriptExecutionContext* context) +{ + FAST_RETURN_IF_NO_FRONTENDS(false); + if (auto* agents = instrumentingAgents(context)) + return shouldBypassCSPImpl(*agents); + return false; +} + +inline void InspectorInstrumentation::willCheckNewWindowPolicy(Frame& frame, const URL& url) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + willCheckNewWindowPolicyImpl(*agents, url); +} + +inline void InspectorInstrumentation::didCheckNewWindowPolicy(Frame& frame, bool allowed) +{ + FAST_RETURN_IF_NO_FRONTENDS(void()); + if (auto* agents = instrumentingAgents(frame)) + didCheckNewWindowPolicyImpl(*agents, allowed); +} + inline InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext* context) { return context ? instrumentingAgents(*context) : nullptr; diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp index 73163278cca3998f4f0122d5cb0577da46a50747..85b9127228ea9c8d89b4b3fd028e0ec4a5b3f820 100644 --- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp @@ -50,4 +50,19 @@ void InspectorInstrumentationWebKit::interceptResponseInternal(const Frame& fram InspectorInstrumentation::interceptResponse(frame, response, identifier, WTFMove(handler)); } +void InspectorInstrumentationWebKit::interceptDidReceiveDataInternal(const Frame& frame, unsigned long identifier, const SharedBuffer& buffer) +{ + InspectorInstrumentation::interceptDidReceiveData(frame, identifier, buffer); +} + +void InspectorInstrumentationWebKit::interceptDidFinishResourceLoadInternal(const Frame& frame, unsigned long identifier) +{ + InspectorInstrumentation::interceptDidFinishResourceLoad(frame, identifier); +} + +void InspectorInstrumentationWebKit::interceptDidFailResourceLoadInternal(const Frame& frame, unsigned long identifier, const ResourceError& error) +{ + InspectorInstrumentation::interceptDidFailResourceLoad(frame, identifier, error); +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h index bffc870806476538115e80f20ddca4e8222e629b..aa56e1f1714b9b51486d9d130e18e29a70576e0f 100644 --- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h +++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h @@ -33,6 +33,7 @@ namespace WebCore { class Frame; +class ResourceError; class ResourceLoader; class ResourceRequest; class ResourceResponse; @@ -44,12 +45,18 @@ public: static bool shouldInterceptResponse(const Frame*, const ResourceResponse&); static void interceptRequest(ResourceLoader&, Function&&); static void interceptResponse(const Frame*, const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); + static void interceptDidReceiveData(const Frame*, unsigned long identifier, const SharedBuffer&); + static void interceptDidFinishResourceLoad(const Frame*, unsigned long identifier); + static void interceptDidFailResourceLoad(const Frame*, unsigned long identifier, const ResourceError& error); private: static bool shouldInterceptRequestInternal(const Frame&, const ResourceRequest&); static bool shouldInterceptResponseInternal(const Frame&, const ResourceResponse&); static void interceptRequestInternal(ResourceLoader&, Function&&); static void interceptResponseInternal(const Frame&, const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); + static void interceptDidReceiveDataInternal(const Frame&, unsigned long identifier, const SharedBuffer&); + static void interceptDidFinishResourceLoadInternal(const Frame&, unsigned long identifier); + static void interceptDidFailResourceLoadInternal(const Frame&, unsigned long identifier, const ResourceError& error); }; inline bool InspectorInstrumentationWebKit::shouldInterceptRequest(const Frame* frame, const ResourceRequest& request) @@ -82,4 +89,28 @@ inline void InspectorInstrumentationWebKit::interceptResponse(const Frame* frame interceptResponseInternal(*frame, response, identifier, WTFMove(handler)); } +inline void InspectorInstrumentationWebKit::interceptDidReceiveData(const Frame* frame, unsigned long identifier, const SharedBuffer& buffer) +{ + if (!frame) + return; + + interceptDidReceiveDataInternal(*frame, identifier, buffer); +} + +inline void InspectorInstrumentationWebKit::interceptDidFinishResourceLoad(const Frame* frame, unsigned long identifier) +{ + if (!frame) + return; + + interceptDidFinishResourceLoadInternal(*frame, identifier); +} + +inline void InspectorInstrumentationWebKit::interceptDidFailResourceLoad(const Frame* frame, unsigned long identifier, const ResourceError& error) +{ + if (!frame) + return; + + interceptDidFailResourceLoadInternal(*frame, identifier, error); +} + } diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp index dadfa3012201c0eb036a142bafa9eb528efb1c56..a6502edece9b79b070d8d611ed9572187d97c463 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp @@ -62,12 +62,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" @@ -94,11 +98,14 @@ #include "Pasteboard.h" #include "PseudoElement.h" #include "RenderGrid.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" @@ -131,7 +138,8 @@ using namespace HTMLNames; static const size_t maxTextSize = 10000; static const UChar ellipsisUChar[] = { 0x2026, 0 }; -static std::optional parseColor(RefPtr&& colorObject) +// static +std::optional InspectorDOMAgent::parseColor(RefPtr&& colorObject) { if (!colorObject) return std::nullopt; @@ -150,7 +158,7 @@ static std::optional parseColor(RefPtr&& colorObject) static Color parseConfigColor(const String& fieldName, JSON::Object& configObject) { - return parseColor(configObject.getObject(fieldName)).value_or(Color::transparentBlack); + return InspectorDOMAgent::parseColor(configObject.getObject(fieldName)).value_or(Color::transparentBlack); } static bool parseQuad(Ref&& quadArray, FloatQuad* quad) @@ -431,6 +439,20 @@ Node* InspectorDOMAgent::assertNode(Protocol::ErrorString& errorString, Protocol return node; } +Node* InspectorDOMAgent::assertNode(Protocol::ErrorString& errorString, std::optional&& nodeId, const String& objectId) +{ + Node* node = nullptr; + if (nodeId) { + node = assertNode(errorString, *nodeId); + } else if (!!objectId) { + node = nodeForObjectId(objectId); + if (!node) + errorString = "Missing node for given objectId"_s; + } else + errorString = "Either nodeId or objectId must be specified"_s; + return node; +} + Document* InspectorDOMAgent::assertDocument(Protocol::ErrorString& errorString, Protocol::DOM::NodeId nodeId) { Node* node = assertNode(errorString, nodeId); @@ -1384,16 +1406,7 @@ Protocol::ErrorStringOr InspectorDOMAgent::highlightSelector(Ref InspectorDOMAgent::highlightNode(Ref&& highlightInspectorObject, std::optional&& nodeId, const Protocol::Runtime::RemoteObjectId& objectId) { Protocol::ErrorString errorString; - - Node* node = nullptr; - if (nodeId) - node = assertNode(errorString, *nodeId); - else if (!!objectId) { - node = nodeForObjectId(objectId); - errorString = "Missing node for given objectId"_s; - } else - errorString = "Either nodeId or objectId must be specified"_s; - + Node* node = assertNode(errorString, WTFMove(nodeId), objectId); if (!node) return makeUnexpected(errorString); @@ -1595,15 +1608,136 @@ Protocol::ErrorStringOr InspectorDOMAgent::setInspectedNode(Protocol::DOM: return { }; } -Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(Protocol::DOM::NodeId nodeId, const String& objectGroup) +static FloatPoint contentsToRootView(FrameView& containingView, const FloatPoint& point) { - Protocol::ErrorString errorString; + return containingView.convertToRootView(point - toFloatSize(containingView.documentScrollPositionRelativeToViewOrigin())); +} - Node* node = assertNode(errorString, nodeId); +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 Ref buildObjectForQuad(const FloatQuad& quad) +{ + auto result = Inspector::Protocol::DOM::Quad::create(); + result->addItem(quad.p1().x()); + result->addItem(quad.p1().y()); + result->addItem(quad.p2().x()); + result->addItem(quad.p2().y()); + result->addItem(quad.p3().x()); + result->addItem(quad.p3().y()); + result->addItem(quad.p4().x()); + result->addItem(quad.p4().y()); + return result; +} + +static Ref> buildArrayOfQuads(const Vector& quads) +{ + auto result = JSON::ArrayOf::create(); + for (const auto& quad : quads) + result->addItem(buildObjectForQuad(quad)); + return result; +} + +Inspector::Protocol::ErrorStringOr> InspectorDOMAgent::describeNode(const String& objectId) +{ + Node* node = nodeForObjectId(objectId); + if (!node) + return makeUnexpected("Node not found"_s); + + auto* pageAgent = m_instrumentingAgents.enabledPageAgent(); + if (!pageAgent) + return makeUnexpected("Page agent must be enabled"_s); + + String ownerFrameId; + String frameId = pageAgent->frameId(node->document().frame()); + if (!frameId.isEmpty()) + ownerFrameId = frameId; + + String contentFrameId; + if (is(*node)) { + const auto& frameOwner = downcast(*node); + String frameId = pageAgent->frameId(frameOwner.contentFrame()); + if (!frameId.isEmpty()) + contentFrameId = frameId; + } + + return { { contentFrameId, ownerFrameId } }; +} + +Protocol::ErrorStringOr InspectorDOMAgent::scrollIntoViewIfNeeded(const String& objectId, RefPtr&& rect) +{ + Node* node = nodeForObjectId(objectId); + if (!node) + return makeUnexpected("Node not found"_s); + + m_inspectedPage.isolatedUpdateRendering(); + if (!node->isConnected()) + return makeUnexpected("Node is detached from document"_s); + + RenderObject* renderer = node->renderer(); + if (!renderer) + return makeUnexpected("Node does not have a layout object"_s); + + bool insideFixed; + LayoutRect absoluteBounds = renderer->absoluteBoundingBoxRect(true, &insideFixed); + if (rect) { + std::optional x = rect->getDouble("x"); + std::optional y = rect->getDouble("y"); + std::optional width = rect->getDouble("width"); + std::optional height = rect->getDouble("height"); + if (!x || !y || !width || !height) + return makeUnexpected("Malformed rect"_s); + + absoluteBounds.setX(absoluteBounds.x() + LayoutUnit(*x)); + absoluteBounds.setY(absoluteBounds.y() + LayoutUnit(*y)); + absoluteBounds.setWidth(LayoutUnit(std::max(*width, 1.0))); + absoluteBounds.setHeight(LayoutUnit(std::max(*height, 1.0))); + } + ScrollAlignment alignment = ScrollAlignment::alignCenterIfNeeded; + alignment.m_disableMinThreshold = true; // Disable RenderLayer minium horizontal scroll threshold. + renderer->scrollRectToVisible(absoluteBounds, insideFixed, { SelectionRevealMode::Reveal, alignment, alignment, ShouldAllowCrossOriginScrolling::Yes }); + return { }; +} + +Protocol::ErrorStringOr>> InspectorDOMAgent::getContentQuads(const String& objectId) +{ + Node* node = nodeForObjectId(objectId); + if (!node) + return makeUnexpected("Node not found"_s); + + RenderObject* renderer = node->renderer(); + if (!renderer) + return makeUnexpected("Node doesn't have renderer"_s); + + // Ensure quads are up to date. + m_inspectedPage.isolatedUpdateRendering(); + + Frame* containingFrame = renderer->document().frame(); + FrameView* containingView = containingFrame ? containingFrame->view() : nullptr; + if (!containingView) + return makeUnexpected("Internal error: no containing view"_s); + + Vector quads; + renderer->absoluteQuads(quads); + for (auto& quad : quads) + frameQuadToViewport(*containingView, quad, m_inspectedPage.pageScaleFactor()); + return buildArrayOfQuads(quads); +} + +Protocol::ErrorStringOr> InspectorDOMAgent::resolveNode(std::optional&& nodeId, const String& objectId, std::optional&& contextId, const String& objectGroup) +{ + Protocol::ErrorString errorString; + Node* node = assertNode(errorString, WTFMove(nodeId), objectId); if (!node) return makeUnexpected(errorString); - auto object = resolveNode(node, objectGroup); + auto object = resolveNode(node, objectGroup, WTFMove(contextId)); if (!object) return makeUnexpected("Missing injected script for given nodeId"_s); @@ -2837,7 +2971,7 @@ Protocol::ErrorStringOr InspectorDOMAgent::pushNodeByPath return makeUnexpected("Missing node for given path"_s); } -RefPtr InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup) +RefPtr InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup, std::optional&& contextId) { Document* document = &node->document(); if (auto* templateHost = document->templateDocumentHost()) @@ -2846,12 +2980,16 @@ RefPtr InspectorDOMAgent::resolveNode(Node* nod 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) @@ -2874,4 +3012,42 @@ Protocol::ErrorStringOr InspectorDOMAgent::setAllowEditingUserAgentShadowT return { }; } +Protocol::ErrorStringOr InspectorDOMAgent::setInputFiles(const String& objectId, Ref&& files) { + InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId); + if (injectedScript.hasNoValue()) + return makeUnexpected("Can not find element's context for given id"_s); + + Node* node = scriptValueAsNode(injectedScript.findObjectById(objectId)); + if (!node) + return makeUnexpected("Can not find element for given id"_s); + + if (node->nodeType() != Node::ELEMENT_NODE || node->nodeName() != "INPUT") + return makeUnexpected("Not an input node"_s); + + HTMLInputElement* element = static_cast(node); + Vector> fileObjects; + for (unsigned i = 0; i < files->length(); ++i) { + RefPtr item = files->get(i); + RefPtr obj = item->asObject(); + if (!obj) + return makeUnexpected("Invalid file payload format"_s); + + String name; + String type; + String data; + if (!obj->getString("name", name) || !obj->getString("type", type) || !obj->getString("data", data)) + return makeUnexpected("Invalid file payload format"_s); + + std::optional> buffer = base64Decode(data); + if (!buffer) + return makeUnexpected("Unable to decode given content"_s); + + ScriptExecutionContext* context = element->scriptExecutionContext(); + fileObjects.append(File::create(context, Blob::create(context, WTFMove(*buffer), type), name)); + } + RefPtr fileList = FileList::create(WTFMove(fileObjects)); + element->setFiles(WTFMove(fileList)); + return { }; +} + } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h index 4eb63b7985721ac6ea6003c884989179c78eda00..b0e628854f24c15a25fbad6aebab1c55a6568545 100644 --- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h @@ -57,6 +57,7 @@ namespace WebCore { class AXCoreObject; class CharacterData; +class Color; class DOMEditor; class Document; class Element; @@ -86,6 +87,7 @@ public: static String toErrorString(Exception&&); static String documentURLString(Document*); + static std::optional parseColor(RefPtr&&); // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. @@ -129,7 +131,7 @@ public: Inspector::Protocol::ErrorStringOr> performSearch(const String& query, RefPtr&& nodeIds, std::optional&& caseSensitive); Inspector::Protocol::ErrorStringOr>> getSearchResults(const String& searchId, int fromIndex, int toIndex); Inspector::Protocol::ErrorStringOr discardSearchResults(const String& searchId); - Inspector::Protocol::ErrorStringOr> resolveNode(Inspector::Protocol::DOM::NodeId, const String& objectGroup); + Inspector::Protocol::ErrorStringOr> resolveNode(std::optional&& nodeId, const String& objectId, std::optional&& contextId, const String& objectGroup); Inspector::Protocol::ErrorStringOr>> getAttributes(Inspector::Protocol::DOM::NodeId); #if PLATFORM(IOS_FAMILY) Inspector::Protocol::ErrorStringOr setInspectModeEnabled(bool, RefPtr&& highlightConfig); @@ -154,6 +156,10 @@ public: Inspector::Protocol::ErrorStringOr focus(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::ErrorStringOr setInspectedNode(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::ErrorStringOr setAllowEditingUserAgentShadowTrees(bool); + Inspector::Protocol::ErrorStringOr> describeNode(const String& objectId); + Inspector::Protocol::ErrorStringOr scrollIntoViewIfNeeded(const String& objectId, RefPtr&& rect); + Inspector::Protocol::ErrorStringOr>> getContentQuads(const String& objectId); + Inspector::Protocol::ErrorStringOr setInputFiles(const String& objectId, Ref&& files); // InspectorInstrumentation Inspector::Protocol::DOM::NodeId identifierForNode(Node&); @@ -191,7 +197,7 @@ public: Node* nodeForId(Inspector::Protocol::DOM::NodeId); Inspector::Protocol::DOM::NodeId boundNodeId(const Node*); - RefPtr resolveNode(Node*, const String& objectGroup); + RefPtr resolveNode(Node*, const String& objectGroup, std::optional&& contextId); bool handleMousePress(); void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); void inspect(Node*); @@ -202,12 +208,15 @@ public: void reset(); Node* assertNode(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); + Node* assertNode(Inspector::Protocol::ErrorString&, std::optional&& nodeId, const String& objectId); Element* assertElement(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); Document* assertDocument(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId); RefPtr breakpointForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture); Inspector::Protocol::DOM::EventListenerId idForEventListener(EventTarget&, const AtomString& eventType, EventListener&, bool capture); + Node* nodeForObjectId(const Inspector::Protocol::Runtime::RemoteObjectId&); + private: #if ENABLE(VIDEO) void mediaMetricsTimerFired(); @@ -236,7 +245,6 @@ private: void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf&); Node* nodeForPath(const String& path); - Node* nodeForObjectId(const Inspector::Protocol::Runtime::RemoteObjectId&); void discardBindings(); diff --git a/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.h b/Source/WebCore/inspector/agents/InspectorDOMStorageAgent.h index 3386cb879f1178c1b9635775c9a0e864f5b94c52..d2350182f5f061855e8ca172779ad60ee73b39fb 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 7948852dd9a6bc42b40116941ce0346c32e16f2d..2beb7e9bce93556cb6537b18a98649eceee6806c 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp @@ -45,6 +45,7 @@ #include "DocumentThreadableLoader.h" #include "FormData.h" #include "Frame.h" +#include "FormData.h" #include "FrameLoader.h" #include "HTTPHeaderMap.h" #include "HTTPHeaderNames.h" @@ -57,6 +58,7 @@ #include "MIMETypeRegistry.h" #include "MemoryCache.h" #include "NetworkResourcesData.h" +#include "NetworkStateNotifier.h" #include "Page.h" #include "PlatformStrategies.h" #include "ProgressTracker.h" @@ -91,6 +93,7 @@ #include typedef Inspector::NetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback; +using GetInterceptedResponseBodyCallback = Inspector::NetworkBackendDispatcherHandler::GetInterceptedResponseBodyCallback; namespace WebCore { @@ -305,8 +308,8 @@ static Ref buildObjectForResourceRequest(const Resou .setHeaders(buildObjectForHeaders(request.httpHeaderFields())) .release(); if (request.httpBody() && !request.httpBody()->isEmpty()) { - auto bytes = request.httpBody()->flatten(); - requestObject->setPostData(String::fromUTF8WithLatin1Fallback(bytes.data(), bytes.size())); + Vector bytes = request.httpBody()->flatten(); + requestObject->setPostData(base64EncodeToString(bytes)); } return requestObject; } @@ -351,6 +354,8 @@ RefPtr InspectorNetworkAgent::buildObjectForResourc .setSource(responseSource(response.source())) .release(); + responseObject->setRequestHeaders(buildObjectForHeaders(response.m_httpRequestHeaderFields)); + if (resourceLoader) { auto* metrics = response.deprecatedNetworkLoadMetricsOrNull(); responseObject->setTiming(buildObjectForTiming(metrics ? *metrics : NetworkLoadMetrics { }, *resourceLoader)); @@ -488,9 +493,15 @@ static InspectorPageAgent::ResourceType resourceTypeForLoadType(InspectorInstrum void InspectorNetworkAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse, const CachedResource* cachedResource) { - if (!cachedResource && loader) - cachedResource = InspectorPageAgent::cachedResource(loader->frame(), request.url()); - willSendRequest(identifier, loader, request, redirectResponse, resourceTypeForCachedResource(cachedResource)); + InspectorPageAgent::ResourceType resourceType; + if (request.initiatorIdentifier() == initiatorIdentifierForEventSource()) { + resourceType = InspectorPageAgent::EventSource; + } else { + if (!cachedResource && loader) + cachedResource = InspectorPageAgent::cachedResource(loader->frame(), request.url()); + resourceType = resourceTypeForCachedResource(cachedResource); + } + willSendRequest(identifier, loader, request, redirectResponse, resourceType); } void InspectorNetworkAgent::willSendRequestOfType(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, InspectorInstrumentation::LoadType loadType) @@ -950,6 +961,18 @@ Protocol::ErrorStringOr> InspectorN return makeUnexpected("Missing content of resource for given requestId"_s); } +void InspectorNetworkAgent::getInterceptedResponseBody(const Inspector::Protocol::Network::RequestId& requestId, Ref&& callback) +{ + auto pendingInterceptResponse = m_pendingInterceptResponses.get(requestId); + if (!pendingInterceptResponse) { + callback->sendFailure("Missing pending intercept response for given requestId"_s); + return; + } + pendingInterceptResponse->getReceivedData([callback = WTFMove(callback)] (const SharedBuffer& buffer) { + callback->sendSuccess(base64EncodeToString(buffer.data(), buffer.size())); + }); +} + Protocol::ErrorStringOr InspectorNetworkAgent::setResourceCachingDisabled(bool disabled) { setResourceCachingDisabledInternal(disabled); @@ -1104,8 +1127,7 @@ bool InspectorNetworkAgent::willIntercept(const ResourceRequest& request) if (!m_interceptionEnabled) return false; - return shouldIntercept(request.url(), Protocol::Network::NetworkStage::Request) - || shouldIntercept(request.url(), Protocol::Network::NetworkStage::Response); + return shouldIntercept(request.url(), Protocol::Network::NetworkStage::Response); } bool InspectorNetworkAgent::shouldInterceptRequest(const ResourceRequest& request) @@ -1159,6 +1181,33 @@ void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response, m_frontendDispatcher->responseIntercepted(requestId, resourceResponse.releaseNonNull()); } +void InspectorNetworkAgent::interceptDidReceiveData(unsigned long identifier, const SharedBuffer& buffer) +{ + String requestId = IdentifiersFactory::requestId(identifier); + auto* interceptedResponse = m_pendingInterceptResponses.get(requestId); + if (!interceptedResponse) { + ASSERT_NOT_REACHED(); + return; + } + interceptedResponse->didReceiveData(buffer); +} + +void InspectorNetworkAgent::interceptDidFinishResourceLoad(unsigned long identifier) +{ + String requestId = IdentifiersFactory::requestId(identifier); + auto* interceptedResponse = m_pendingInterceptResponses.get(requestId); + if (!interceptedResponse) { + ASSERT_NOT_REACHED(); + return; + } + interceptedResponse->didFinishLoading(); +} + +void InspectorNetworkAgent::interceptDidFailResourceLoad(unsigned long identifier, const ResourceError&) +{ + interceptDidFinishResourceLoad(identifier); +} + Protocol::ErrorStringOr InspectorNetworkAgent::interceptContinue(const Protocol::Network::RequestId& requestId, Protocol::Network::NetworkStage networkStage) { switch (networkStage) { @@ -1188,6 +1237,9 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptWithRequest(const return makeUnexpected("Missing pending intercept request for given requestId"_s); auto& loader = *pendingRequest->m_loader; + if (loader.reachedTerminalState()) + return makeUnexpected("Unable to intercept request, it has already been processed"_s); + ResourceRequest request = loader.request(); if (!!url) request.setURL(URL({ }, url)); @@ -1287,14 +1339,24 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptRequestWithRespons response.setHTTPStatusCode(status); response.setHTTPStatusText(statusText); HTTPHeaderMap explicitHeaders; + String setCookieValue; for (auto& header : headers.get()) { auto headerValue = header.value->asString(); if (!!headerValue) explicitHeaders.add(header.key, headerValue); + if (equalIgnoringASCIICase(header.key, "Set-Cookie")) + setCookieValue = headerValue; } response.setHTTPHeaderFields(WTFMove(explicitHeaders)); response.setHTTPHeaderField(HTTPHeaderName::ContentType, response.mimeType()); + + auto* frame = loader->frame(); + if (!setCookieValue.isEmpty() && frame && frame->page()) + frame->page()->cookieJar().setCookieFromResponse(*loader.get(), setCookieValue); + loader->didReceiveResponse(response, [loader, buffer = data.releaseNonNull()]() mutable { + if (loader->reachedTerminalState()) + return; if (buffer->size()) loader->didReceiveBuffer(WTFMove(buffer), buffer->size(), DataPayloadWholeResource); loader->didFinishLoading(NetworkLoadMetrics()); @@ -1335,6 +1397,12 @@ Protocol::ErrorStringOr InspectorNetworkAgent::interceptRequestWithError(c return { }; } +Inspector::Protocol::ErrorStringOr InspectorNetworkAgent::setEmulateOfflineState(bool offline) +{ + platformStrategies()->loaderStrategy()->setEmulateOfflineState(offline); + return { }; +} + bool InspectorNetworkAgent::shouldTreatAsText(const String& mimeType) { return startsWithLettersIgnoringASCIICase(mimeType, "text/") @@ -1376,6 +1444,12 @@ std::optional InspectorNetworkAgent::textContentForCachedResource(Cached return std::nullopt; } +// static +String InspectorNetworkAgent::initiatorIdentifierForEventSource() +{ + return "InspectorNetworkAgent: eventSource"_s; +} + bool InspectorNetworkAgent::cachedResourceContent(CachedResource& resource, String* result, bool* base64Encoded) { ASSERT(result); diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h index 7cdc5865e58e9a9a30ea25202692d4b9aa77b2d6..7c42be0cbadf9a594926cbe89ce510b0f0827397 100644 --- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h +++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h @@ -72,6 +72,7 @@ public: static Ref createTextDecoder(const String& mimeType, const String& textEncodingName); static std::optional textContentForCachedResource(CachedResource&); static bool cachedResourceContent(CachedResource&, String* result, bool* base64Encoded); + static String initiatorIdentifierForEventSource(); // InspectorAgentBase void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) final; @@ -82,6 +83,7 @@ public: Inspector::Protocol::ErrorStringOr disable() final; Inspector::Protocol::ErrorStringOr setExtraHTTPHeaders(Ref&&) final; Inspector::Protocol::ErrorStringOr> getResponseBody(const Inspector::Protocol::Network::RequestId&) final; + void getInterceptedResponseBody(const Inspector::Protocol::Network::RequestId&, Ref&&) final; Inspector::Protocol::ErrorStringOr setResourceCachingDisabled(bool) final; void loadResource(const Inspector::Protocol::Network::FrameId&, const String& url, Ref&&) final; Inspector::Protocol::ErrorStringOr getSerializedCertificate(const Inspector::Protocol::Network::RequestId&) final; @@ -94,6 +96,7 @@ public: Inspector::Protocol::ErrorStringOr interceptWithResponse(const Inspector::Protocol::Network::RequestId&, const String& content, bool base64Encoded, const String& mimeType, std::optional&& status, const String& statusText, RefPtr&& headers) final; Inspector::Protocol::ErrorStringOr interceptRequestWithResponse(const Inspector::Protocol::Network::RequestId&, const String& content, bool base64Encoded, const String& mimeType, int status, const String& statusText, Ref&& headers) final; Inspector::Protocol::ErrorStringOr interceptRequestWithError(const Inspector::Protocol::Network::RequestId&, Inspector::Protocol::Network::ResourceErrorType) final; + Inspector::Protocol::ErrorStringOr setEmulateOfflineState(bool offline) final; // InspectorInstrumentation void willRecalculateStyle(); @@ -125,6 +128,9 @@ public: bool shouldInterceptResponse(const ResourceResponse&); void interceptResponse(const ResourceResponse&, unsigned long identifier, CompletionHandler)>&&); void interceptRequest(ResourceLoader&, Function&&); + void interceptDidReceiveData(unsigned long identifier, const SharedBuffer&); + void interceptDidFinishResourceLoad(unsigned long identifier); + void interceptDidFailResourceLoad(unsigned long identifier, const ResourceError& error); void searchOtherRequests(const JSC::Yarr::RegularExpression&, Ref>&); void searchInRequest(Inspector::Protocol::ErrorString&, const Inspector::Protocol::Network::RequestId&, const String& query, bool caseSensitive, bool isRegex, RefPtr>&); @@ -188,6 +194,7 @@ private: PendingInterceptResponse(const ResourceResponse& originalResponse, CompletionHandler)>&& completionHandler) : m_originalResponse(originalResponse) , m_completionHandler(WTFMove(completionHandler)) + , m_receivedData(SharedBuffer::create()) { } ~PendingInterceptResponse() @@ -211,12 +218,44 @@ private: m_responded = true; m_completionHandler(response, data); + + m_receivedData->clear(); + notifyDataHandlers(); + } + + void didReceiveData(const SharedBuffer& buffer) + { + m_receivedData->append(buffer); + } + + void getReceivedData(CompletionHandler&& completionHandler) + { + if (m_finishedLoading || m_responded) { + completionHandler(m_receivedData.get()); + return; + } + m_receivedDataHandlers.append(WTFMove(completionHandler)); + } + + void didFinishLoading() { + m_finishedLoading = true; + notifyDataHandlers(); } private: + void notifyDataHandlers() + { + for (auto& handler : m_receivedDataHandlers) + handler(m_receivedData.get()); + m_receivedDataHandlers.clear(); + } + ResourceResponse m_originalResponse; CompletionHandler)> m_completionHandler; + Ref m_receivedData; + Vector> m_receivedDataHandlers; bool m_responded { false }; + bool m_finishedLoading { false }; }; std::unique_ptr m_frontendDispatcher; diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp index 64117425ba5c5b6a71d190dfc8f1eefb4ffc637c..3a63079e3bba97ef638224c476169e42752ccb97 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp @@ -32,19 +32,25 @@ #include "config.h" #include "InspectorPageAgent.h" +#include "AXObjectCache.h" +#include "BackForwardController.h" #include "CachedResource.h" #include "CachedResourceLoader.h" #include "Cookie.h" #include "CookieJar.h" +#include "CustomHeaderFields.h" #include "DOMWrapperWorld.h" #include "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" @@ -55,19 +61,28 @@ #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 @@ -80,11 +95,15 @@ #include "LegacyWebArchive.h" #endif - namespace WebCore { using namespace Inspector; +static HashMap>& createdUserWorlds() { + static NeverDestroyed>> nameToWorld; + return nameToWorld; +} + static bool decodeBuffer(const uint8_t* buffer, unsigned size, const String& textEncodingName, String* result) { if (buffer) { @@ -234,6 +253,8 @@ Protocol::Page::ResourceType InspectorPageAgent::resourceTypeJSON(InspectorPageA return Protocol::Page::ResourceType::Beacon; case WebSocketResource: return Protocol::Page::ResourceType::WebSocket; + case EventSource: + return Protocol::Page::ResourceType::EventSource; case OtherResource: return Protocol::Page::ResourceType::Other; #if ENABLE(APPLICATION_MANIFEST) @@ -321,6 +342,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) { @@ -352,12 +374,20 @@ Protocol::ErrorStringOr InspectorPageAgent::enable() defaultAppearanceDidChange(m_inspectedPage.defaultUseDarkAppearance()); #endif + if (!createdUserWorlds().isEmpty()) { + Vector worlds; + for (const auto& world : createdUserWorlds().values()) + worlds.append(world.ptr()); + ensureUserWorldsExistInAllFrames(worlds); + } return { }; } Protocol::ErrorStringOr InspectorPageAgent::disable() { m_instrumentingAgents.setEnabledPageAgent(nullptr); + m_interceptFileChooserDialog = false; + m_bypassCSP = false; setShowPaintRects(false); #if !PLATFORM(IOS_FAMILY) @@ -406,6 +436,22 @@ Protocol::ErrorStringOr InspectorPageAgent::reload(std::optional&& i return { }; } +Protocol::ErrorStringOr InspectorPageAgent::goBack() +{ + if (!m_inspectedPage.backForward().goBack()) + return makeUnexpected("Failed to go back"_s); + + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::goForward() +{ + if (!m_inspectedPage.backForward().goForward()) + return makeUnexpected("Failed to go forward"_s); + + return { }; +} + Protocol::ErrorStringOr InspectorPageAgent::navigate(const String& url) { UserGestureIndicator indicator { ProcessingUserGesture }; @@ -439,6 +485,10 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value); return { }; + case Protocol::Page::Setting::DeviceOrientationEventEnabled: + inspectedPageSettings.setDeviceOrientationEventEnabled(value.value_or(false)); + return { }; + case Protocol::Page::Setting::ICECandidateFilteringEnabled: inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value); return { }; @@ -476,6 +526,10 @@ Protocol::ErrorStringOr InspectorPageAgent::overrideSetting(Protocol::Page inspectedPageSettings.setShowRepaintCounterInspectorOverride(value); return { }; + case Protocol::Page::Setting::SpeechRecognitionEnabled: + inspectedPageSettings.setSpeechRecognitionEnabled(value.value_or(false)); + return { }; + case Protocol::Page::Setting::WebRTCEncryptionEnabled: inspectedPageSettings.setWebRTCEncryptionEnabledInspectorOverride(value); return { }; @@ -696,9 +750,13 @@ Protocol::ErrorStringOr> InspectorP return { { content, base64Encoded } }; } -Protocol::ErrorStringOr InspectorPageAgent::setBootstrapScript(const String& source) +Protocol::ErrorStringOr InspectorPageAgent::setBootstrapScript(const String& source, const String& worldName) { - m_bootstrapScript = source; + String key = worldName.isNull() ? emptyString() : worldName; + if (source.isEmpty()) + m_worldNameToBootstrapScript.remove(key); + else + m_worldNameToBootstrapScript.set(key, source); return { }; } @@ -801,15 +859,16 @@ Protocol::ErrorStringOr InspectorPageAgent::setShowPaintRects(bool show) return { }; } -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) @@ -817,13 +876,23 @@ void InspectorPageAgent::frameNavigated(Frame& frame) m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame)); } +String InspectorPageAgent::makeFrameID(ProcessIdentifier processID, FrameIdentifier frameID) +{ + return makeString(processID.toUInt64(), ".", frameID.toUInt64()); +} + +static String globalIDForFrame(Frame& frame) +{ + return InspectorPageAgent::makeFrameID(Process::identifier(), *frame.loader().client().frameID()); +} + 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 Protocol::Network::FrameId& frameId) @@ -835,20 +904,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, makeWeakPtr(frame)); - return identifier; - }).iterator->value; + + String identifier = globalIDForFrame(*frame); + m_identifierToFrame.set(identifier, makeWeakPtr(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(Protocol::ErrorString& errorString, const Protocol::Network::FrameId& frameId) @@ -859,11 +926,6 @@ Frame* InspectorPageAgent::assertFrame(Protocol::ErrorString& errorString, const return frame; } -void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader) -{ - m_loaderToIdentifier.remove(&loader); -} - void InspectorPageAgent::frameStartedLoading(Frame& frame) { m_frontendDispatcher->frameStartedLoading(frameId(&frame)); @@ -884,6 +946,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); +} + #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance) { @@ -893,13 +961,22 @@ void InspectorPageAgent::defaultAppearanceDidChange(bool useDarkAppearance) void InspectorPageAgent::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world) { - if (&world != &mainThreadNormalWorld()) + if (m_worldNameToBootstrapScript.isEmpty()) return; - if (m_bootstrapScript.isEmpty()) + if (world.name().isEmpty() && &world != &mainThreadNormalWorld()) + return; + + String worldName = world.name(); + // Null string cannot be used as a key. + if (worldName.isNull()) + worldName = emptyString(); + + if (!m_worldNameToBootstrapScript.contains(worldName)) return; - frame.script().evaluateIgnoringException(ScriptSourceCode(m_bootstrapScript, URL { URL(), "web-inspector://bootstrap.js"_s })); + String bootstrapScript = m_worldNameToBootstrapScript.get(worldName); + frame.script().evaluateInWorldIgnoringException(ScriptSourceCode(bootstrapScript, URL { URL(), "web-inspector://bootstrap.js"_s }), world); } void InspectorPageAgent::didPaint(RenderObject& renderer, const LayoutRect& rect) @@ -943,6 +1020,52 @@ 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; + + auto object = injectedScript.wrapObject(InspectorDOMAgent::nodeAsScriptValue(state, element), WTF::String()); + if (!object) + return; + + m_frontendDispatcher->fileChooserOpened(frameId(frame), object.releaseNonNull()); +} + +void InspectorPageAgent::frameAttached(Frame& frame) +{ + Frame* parent = frame.tree().parent(); + String parentFrameId = frameId(parent); + m_frontendDispatcher->frameAttached(frameId(&frame), parentFrameId); +} + +bool InspectorPageAgent::shouldBypassCSP() +{ + return m_bypassCSP; +} + +void InspectorPageAgent::willCheckNewWindowPolicy(const URL& url) +{ + m_frontendDispatcher->willRequestOpenWindow(url.string()); +} + +void InspectorPageAgent::didCheckNewWindowPolicy(bool allowed) +{ + m_frontendDispatcher->didRequestOpenWindow(allowed); +} + Ref InspectorPageAgent::buildObjectForFrame(Frame* frame) { ASSERT_ARG(frame, frame); @@ -1079,11 +1202,13 @@ Protocol::ErrorStringOr InspectorPageAgent::snapshotNode(Protocol::DOM:: return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } -Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Protocol::Page::CoordinateSystem coordinateSystem) +Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Protocol::Page::CoordinateSystem coordinateSystem, std::optional&& omitDeviceScaleFactor) { SnapshotOptions options { { }, PixelFormat::BGRA8, DestinationColorSpace::SRGB() }; if (coordinateSystem == Protocol::Page::CoordinateSystem::Viewport) options.flags.add(SnapshotFlags::InViewCoordinates); + if (omitDeviceScaleFactor.has_value() && *omitDeviceScaleFactor) + options.flags.add(SnapshotFlags::OmitDeviceScaleFactor); IntRect rectangle(x, y, width, height); auto snapshot = snapshotFrameRect(m_inspectedPage.mainFrame(), rectangle, WTFMove(options)); @@ -1094,6 +1219,47 @@ Protocol::ErrorStringOr InspectorPageAgent::snapshotRect(int x, int y, i return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes); } +Protocol::ErrorStringOr InspectorPageAgent::setForcedReducedMotion(std::optional&& reducedMotion) +{ + if (!reducedMotion) { + m_inspectedPage.setUseReducedMotionOverride(std::nullopt); + return { }; + } + + switch (*reducedMotion) { + case Protocol::Page::ReducedMotion::Reduce: + m_inspectedPage.setUseReducedMotionOverride(true); + return { }; + case Protocol::Page::ReducedMotion::NoPreference: + m_inspectedPage.setUseReducedMotionOverride(false); + return { }; + } + + ASSERT_NOT_REACHED(); + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::setTimeZone(const String& timeZone) +{ + bool success = WTF::setTimeZoneForAutomation(timeZone); + if (!success) + return makeUnexpected("Invalid time zone " + timeZone); + + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::setTouchEmulationEnabled(bool enabled) +{ +#if ENABLE(TOUCH_EVENTS) + RuntimeEnabledFeatures::sharedFeatures().setTouchEventsEnabled(enabled); + return { }; +#else + UNUSED_PARAM(enabled); + return makeUnexpected("Not supported"_s); +#endif +} + + #if ENABLE(WEB_ARCHIVE) && USE(CF) Protocol::ErrorStringOr InspectorPageAgent::archive() { @@ -1106,7 +1272,6 @@ Protocol::ErrorStringOr InspectorPageAgent::archive() } #endif -#if !PLATFORM(COCOA) Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::optional&& width, std::optional&& height) { if (width.has_value() != height.has_value()) @@ -1121,6 +1286,595 @@ Protocol::ErrorStringOr InspectorPageAgent::setScreenSizeOverride(std::opt m_inspectedPage.mainFrame().setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0))); return { }; } + +Protocol::ErrorStringOr InspectorPageAgent::insertText(const String& text) +{ + UserGestureIndicator indicator { ProcessingUserGesture }; + Document* focusedDocument = m_inspectedPage.focusController().focusedOrMainFrame().document(); + TypingCommand::insertText(*focusedDocument, text, 0); + return { }; +} + +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 Ref 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()) { + Ref> children = JSON::ArrayOf::create(); + for (auto& childObject : axObject->children()) + children->addItem(snapshotForAXObject(childObject, nodeToFind)); + axNode->setChildren(WTFMove(children)); + } + return axNode; +} + + +Protocol::ErrorStringOr> InspectorPageAgent::accessibilitySnapshot(const String& objectId) +{ + if (!WebCore::AXObjectCache::accessibilityEnabled()) + WebCore::AXObjectCache::enableAccessibility(); + auto document = makeRefPtr(m_inspectedPage.mainFrame().document()); + if (!document) + return makeUnexpected("No document for main frame"_s); + + AXObjectCache* axObjectCache = document->axObjectCache(); + if (!axObjectCache) + return makeUnexpected("No AXObjectCache for main document"_s); + + AXCoreObject* axObject = axObjectCache->rootObject(); + if (!axObject) + return makeUnexpected("No AXObject for main document"_s); + + Node* node = nullptr; + if (!objectId.isEmpty()) { + InspectorDOMAgent* domAgent = m_instrumentingAgents.persistentDOMAgent(); + ASSERT(domAgent); + node = domAgent->nodeForObjectId(objectId); + if (!node) + return makeUnexpected("No Node for objectId"_s); + } + + m_doingAccessibilitySnapshot = true; + Ref axNode = snapshotForAXObject(makeRefPtr(axObject), node); + m_doingAccessibilitySnapshot = false; + return axNode; +} + +Protocol::ErrorStringOr InspectorPageAgent::setInterceptFileChooserDialog(bool enabled) +{ + m_interceptFileChooserDialog = enabled; + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::setDefaultBackgroundColorOverride(RefPtr&& color) +{ + FrameView* view = m_inspectedPage.mainFrame().view(); + if (!view) + return makeUnexpected("Internal error: No frame view to set color two"_s); + + if (!color) { + view->updateBackgroundRecursively(std::optional()); + return { }; + } + + view->updateBackgroundRecursively(InspectorDOMAgent::parseColor(WTFMove(color))); + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::createUserWorld(const String& name) +{ + if (createdUserWorlds().contains(name)) + return makeUnexpected("World with the given name already exists"_s); + + Ref world = ScriptController::createWorld(name, ScriptController::WorldType::User); + ensureUserWorldsExistInAllFrames({world.ptr()}); + createdUserWorlds().set(name, WTFMove(world)); + return { }; +} + +void InspectorPageAgent::ensureUserWorldsExistInAllFrames(const Vector& worlds) +{ + for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) { + for (auto* world : worlds) + frame->windowProxy().jsWindowProxy(*world)->window(); + } +} + +Protocol::ErrorStringOr InspectorPageAgent::setBypassCSP(bool enabled) +{ + m_bypassCSP = enabled; + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::crash() +{ + CRASH(); + return { }; +} + +Protocol::ErrorStringOr InspectorPageAgent::setOrientationOverride(std::optional&& angle) +{ +#if ENABLE(ORIENTATION_EVENTS) + m_inspectedPage.setOverrideOrientation(WTFMove(angle)); + return { }; +#else + UNUSED_PARAM(angle); + return makeUnexpected("Orientation events are disabled in this build"); #endif +} + +static std::optional parseInsets(RefPtr&& insets) +{ + std::optional top = insets->getDouble("top"); + std::optional right = insets->getDouble("right"); + std::optional bottom = insets->getDouble("bottom"); + std::optional left = insets->getDouble("left"); + if (top && right && bottom && left) + return FloatBoxExtent(static_cast(*top), static_cast(*right), static_cast(*bottom), static_cast(*left)); + return std::optional(); +} + +static std::optional parseRect(RefPtr&& insets) +{ + std::optional x = insets->getDouble("x"); + std::optional y = insets->getDouble("y"); + std::optional width = insets->getDouble("width"); + std::optional height = insets->getDouble("height"); + if (x && y && width && height) + return FloatRect(static_cast(*x), static_cast(*y), static_cast(*width), static_cast(*height)); + return std::optional(); +} + +Protocol::ErrorStringOr InspectorPageAgent::setVisibleContentRects(RefPtr&& unobscuredContentRect, RefPtr&& contentInsets, RefPtr&& obscuredInsets, RefPtr&& unobscuredInsets) +{ + FrameView* view = m_inspectedPage.mainFrame().view(); + if (!view) + return makeUnexpected("Internal error: No frame view to set content rects for"_s); + + if (unobscuredContentRect) { + std::optional ucr = parseRect(WTFMove(unobscuredContentRect)); + if (!ucr) + return makeUnexpected("Invalid unobscured content rect"); + + view->setUnobscuredContentSize(FloatSize(ucr->width(), ucr->height())); + } + + if (contentInsets) { + std::optional ci = parseInsets(WTFMove(contentInsets)); + if (!ci) + return makeUnexpected("Invalid content insets"); + + m_inspectedPage.setContentInsets(*ci); + } + + if (obscuredInsets) { + std::optional oi = parseInsets(WTFMove(obscuredInsets)); + if (!oi) + return makeUnexpected("Invalid obscured insets"); + + m_inspectedPage.setObscuredInsets(*oi); + } + + if (unobscuredInsets) { + std::optional ui = parseInsets(WTFMove(unobscuredInsets)); + if (!ui) + return makeUnexpected("Invalid unobscured insets"); + + m_inspectedPage.setUnobscuredSafeAreaInsets(*ui); + } + return {}; +} } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h index b51addb1bd8f2cce69560799cd1d952d2de42838..2ad11ef1993ed5a223f63073c4b4464bfde93a34 100644 --- a/Source/WebCore/inspector/agents/InspectorPageAgent.h +++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h @@ -34,17 +34,23 @@ #include "CachedResource.h" #include "InspectorWebAgentBase.h" #include "LayoutRect.h" +#include "ProcessIdentifier.h" #include #include #include #include #include +namespace Inspector { +class InjectedScriptManager; +} + namespace WebCore { class DOMWrapperWorld; class DocumentLoader; class Frame; +class HTMLInputElement; class InspectorClient; class InspectorOverlay; class Page; @@ -69,12 +75,14 @@ public: PingResource, BeaconResource, WebSocketResource, + EventSource, #if ENABLE(APPLICATION_MANIFEST) ApplicationManifestResource, #endif OtherResource, }; + WEBCORE_EXPORT static String makeFrameID(ProcessIdentifier processID, FrameIdentifier frameID); static bool sharedBufferContent(RefPtr&&, const String& textEncodingName, bool withBase64Encode, String* result); static Vector cachedResourcesForFrame(Frame*); static void resourceContent(Inspector::Protocol::ErrorString&, Frame*, const URL&, String* result, bool* base64Encoded); @@ -95,6 +103,8 @@ public: Inspector::Protocol::ErrorStringOr enable(); Inspector::Protocol::ErrorStringOr disable(); Inspector::Protocol::ErrorStringOr reload(std::optional&& ignoreCache, std::optional&& revalidateAllResources); + Inspector::Protocol::ErrorStringOr goBack(); + Inspector::Protocol::ErrorStringOr goForward(); Inspector::Protocol::ErrorStringOr navigate(const String& url); Inspector::Protocol::ErrorStringOr overrideUserAgent(const String&); Inspector::Protocol::ErrorStringOr overrideSetting(Inspector::Protocol::Page::Setting, std::optional&& value); @@ -103,7 +113,7 @@ public: Inspector::Protocol::ErrorStringOr deleteCookie(const String& cookieName, const String& url); Inspector::Protocol::ErrorStringOr> getResourceTree(); Inspector::Protocol::ErrorStringOr> getResourceContent(const Inspector::Protocol::Network::FrameId&, const String& url); - Inspector::Protocol::ErrorStringOr setBootstrapScript(const String& source); + Inspector::Protocol::ErrorStringOr setBootstrapScript(const String& source, const String& worldName); Inspector::Protocol::ErrorStringOr>> searchInResource(const Inspector::Protocol::Network::FrameId&, const String& url, const String& query, std::optional&& caseSensitive, std::optional&& isRegex, const Inspector::Protocol::Network::RequestId&); Inspector::Protocol::ErrorStringOr>> searchInResources(const String&, std::optional&& caseSensitive, std::optional&& isRegex); #if !PLATFORM(IOS_FAMILY) @@ -114,25 +124,36 @@ public: #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) Inspector::Protocol::ErrorStringOr setForcedAppearance(std::optional&&); #endif + Inspector::Protocol::ErrorStringOr setForcedReducedMotion(std::optional&&); + Inspector::Protocol::ErrorStringOr setTimeZone(const String&); + Inspector::Protocol::ErrorStringOr setTouchEmulationEnabled(bool); Inspector::Protocol::ErrorStringOr snapshotNode(Inspector::Protocol::DOM::NodeId); - Inspector::Protocol::ErrorStringOr snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem); + Inspector::Protocol::ErrorStringOr snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem, std::optional&& omitDeviceScaleFactor); #if ENABLE(WEB_ARCHIVE) && USE(CF) Inspector::Protocol::ErrorStringOr archive(); #endif -#if !PLATFORM(COCOA) Inspector::Protocol::ErrorStringOr setScreenSizeOverride(std::optional&& width, std::optional&& height); -#endif + + Inspector::Protocol::ErrorStringOr insertText(const String& text); + Inspector::Protocol::ErrorStringOr> accessibilitySnapshot(const String& objectId); + Inspector::Protocol::ErrorStringOr setInterceptFileChooserDialog(bool enabled); + Inspector::Protocol::ErrorStringOr setDefaultBackgroundColorOverride(RefPtr&&); + Inspector::Protocol::ErrorStringOr createUserWorld(const String&); + Inspector::Protocol::ErrorStringOr setBypassCSP(bool); + Inspector::Protocol::ErrorStringOr crash(); + Inspector::Protocol::ErrorStringOr setOrientationOverride(std::optional&& angle); + Inspector::Protocol::ErrorStringOr setVisibleContentRects(RefPtr&& unobscuredContentRect, RefPtr&& contentInsets, RefPtr&& obscuredInsets, RefPtr&& unobscuredInsets); // 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&); #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT) void defaultAppearanceDidChange(bool useDarkAppearance); #endif @@ -143,6 +164,12 @@ public: void didLayout(); void didScroll(); void didRecalculateStyle(); + void runOpenPanel(HTMLInputElement* element, bool* intercept); + void frameAttached(Frame&); + bool shouldBypassCSP(); + void willCheckNewWindowPolicy(const URL&); + void didCheckNewWindowPolicy(bool allowed); + bool doingAccessibilitySnapshot() const { return m_doingAccessibilitySnapshot; }; Frame* frameForId(const Inspector::Protocol::Network::FrameId&); WEBCORE_EXPORT String frameId(Frame*); @@ -151,6 +178,7 @@ public: private: double timestamp(); + void ensureUserWorldsExistInAllFrames(const Vector&); static bool mainResourceContent(Frame*, bool withBase64Encode, String* result); static bool dataContent(const uint8_t* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result); @@ -162,18 +190,19 @@ private: RefPtr m_backendDispatcher; Page& m_inspectedPage; + Inspector::InjectedScriptManager& m_injectedScriptManager; InspectorClient* m_client { nullptr }; InspectorOverlay* m_overlay { nullptr }; - // FIXME: Make a WeakHashMap and use it for m_frameToIdentifier and m_loaderToIdentifier. - HashMap m_frameToIdentifier; HashMap> m_identifierToFrame; - HashMap m_loaderToIdentifier; + HashMap m_worldNameToBootstrapScript; String m_userAgentOverride; String m_emulatedMedia; - String m_bootstrapScript; bool m_isFirstLayoutAfterOnLoad { false }; bool m_showPaintRects { false }; + bool m_interceptFileChooserDialog { false }; + bool m_bypassCSP { false }; + bool m_doingAccessibilitySnapshot { false }; }; } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp b/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp index 33caa0aa2079ad4081cc29605a53537c24d66bef..4b74d397d4de9a7eba3d5530538443d8907726aa 100644 --- a/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp +++ b/Source/WebCore/inspector/agents/InspectorWorkerAgent.cpp @@ -161,7 +161,11 @@ void InspectorWorkerAgent::connectToWorkerInspectorProxy(WorkerInspectorProxy& p m_connectedProxies.set(proxy.identifier(), &proxy); - m_frontendDispatcher->workerCreated(proxy.identifier(), proxy.url().string(), proxy.name()); + ASSERT(is(proxy.scriptExecutionContext())); + Document& document = downcast(*proxy.scriptExecutionContext()); + auto* pageAgent = m_instrumentingAgents.enabledPageAgent(); + m_frontendDispatcher->workerCreated(proxy.identifier(), proxy.url().string(), proxy.name(), + 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 55d9518494195b96df165a94c1c2963adceb8395..98035b606587337e5fdacd31459a196fa7c28702 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 "PageDebugger.h" @@ -69,7 +70,11 @@ bool PageDebuggerAgent::enabled() const Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> PageDebuggerAgent::evaluateOnCallFrame(const Protocol::Debugger::CallFrameId& callFrameId, const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture) { - UserGestureEmulationScope userGestureScope(m_inspectedPage, emulateUserGesture && *emulateUserGesture); + 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, document); return WebDebuggerAgent::evaluateOnCallFrame(callFrameId, expression, objectGroup, WTFMove(includeCommandLineAPI), WTFMove(doNotPauseOnExceptionsAndMuteConsole), WTFMove(returnByValue), WTFMove(generatePreview), WTFMove(saveResult), WTFMove(emulateUserGesture)); } @@ -121,8 +126,9 @@ void PageDebuggerAgent::unmuteConsole() void PageDebuggerAgent::debuggerWillEvaluate(JSC::Debugger&, const JSC::Breakpoint::Action& action) { + // FIXME(playwright): we should pass proper Documnt instead of nullptr here. if (action.emulateUserGesture) - m_breakpointActionUserGestureEmulationScopeStack.append(makeUniqueRef(m_inspectedPage, true)); + m_breakpointActionUserGestureEmulationScopeStack.append(makeUniqueRef(m_inspectedPage, true, nullptr)); } void PageDebuggerAgent::debuggerDidEvaluate(JSC::Debugger&, const JSC::Breakpoint::Action& action) diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp index b32f3f699c2d2a377289760b245ac81784102458..48f0fab7f07bfc2b2408764e9adec252cc380705 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" @@ -103,6 +105,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(Protocol::ErrorString& errorString, std::optional&& executionContextId) { if (!executionContextId) { @@ -191,14 +202,24 @@ void PageRuntimeAgent::notifyContextCreated(const Protocol::Network::FrameId& fr Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> PageRuntimeAgent::evaluate(const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& executionContextId, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture) { - UserGestureEmulationScope userGestureScope(m_inspectedPage, emulateUserGesture && *emulateUserGesture); + String errorString; + InjectedScript injectedScript = injectedScriptForEval(errorString, std::optional(executionContextId)); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + JSC::JSGlobalObject* globalObject = injectedScript.globalObject(); + Document* document = globalObject ? activeDOMWindow(*globalObject).document() : nullptr; + UserGestureEmulationScope userGestureScope(m_inspectedPage, emulateUserGesture && *emulateUserGesture, document); return InspectorRuntimeAgent::evaluate(expression, objectGroup, WTFMove(includeCommandLineAPI), WTFMove(doNotPauseOnExceptionsAndMuteConsole), WTFMove(executionContextId), WTFMove(returnByValue), WTFMove(generatePreview), WTFMove(saveResult), WTFMove(emulateUserGesture)); } -Protocol::ErrorStringOr, std::optional /* wasThrown */>> PageRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObjectId& objectId, const String& expression, RefPtr&& optionalArguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture) +void PageRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObjectId& objectId, const String& expression, RefPtr&& optionalArguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture, std::optional&& awaitPromise, Ref&& callback) { - UserGestureEmulationScope userGestureScope(m_inspectedPage, emulateUserGesture && *emulateUserGesture); - return InspectorRuntimeAgent::callFunctionOn(objectId, expression, WTFMove(optionalArguments), WTFMove(doNotPauseOnExceptionsAndMuteConsole), WTFMove(returnByValue), WTFMove(generatePreview), WTFMove(emulateUserGesture)); + InjectedScript injectedScript = injectedScriptManager().injectedScriptForObjectId(objectId); + JSC::JSGlobalObject* globalObject = injectedScript.globalObject(); + Document* document = globalObject ? activeDOMWindow(*globalObject).document() : nullptr; + UserGestureEmulationScope userGestureScope(m_inspectedPage, emulateUserGesture && *emulateUserGesture, document); + return InspectorRuntimeAgent::callFunctionOn(objectId, expression, WTFMove(optionalArguments), WTFMove(doNotPauseOnExceptionsAndMuteConsole), WTFMove(returnByValue), WTFMove(generatePreview), WTFMove(emulateUserGesture), WTFMove(awaitPromise), WTFMove(callback)); } } // namespace WebCore diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h index 6aba3a2c6e8bbb7a0bca4f07824cf4de8ce36f8e..537e3b34d6405e412bf0e2350909c9afda06bed8 100644 --- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h +++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h @@ -54,25 +54,25 @@ public: ~PageRuntimeAgent(); // RuntimeBackendDispatcherHandler - Inspector::Protocol::ErrorStringOr enable(); - Inspector::Protocol::ErrorStringOr disable(); - Inspector::Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture); - Inspector::Protocol::ErrorStringOr, std::optional /* wasThrown */>> callFunctionOn(const Inspector::Protocol::Runtime::RemoteObjectId&, const String& expression, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture); + Inspector::Protocol::ErrorStringOr enable() override; + Inspector::Protocol::ErrorStringOr disable() override; + Inspector::Protocol::ErrorStringOr, std::optional /* wasThrown */, std::optional /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional&& includeCommandLineAPI, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&&, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& saveResult, std::optional&& emulateUserGesture) override; + void callFunctionOn(const Inspector::Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr&& arguments, std::optional&& doNotPauseOnExceptionsAndMuteConsole, std::optional&& returnByValue, std::optional&& generatePreview, std::optional&& emulateUserGesture, std::optional&& awaitPromise, Ref&&) override; // InspectorInstrumentation void frameNavigated(Frame&); void didClearWindowObjectInWorld(Frame&, DOMWrapperWorld&); + void didReceiveMainResourceError(Frame&); private: - Inspector::InjectedScript injectedScriptForEval(Inspector::Protocol::ErrorString&, std::optional&&); - void muteConsole(); - void unmuteConsole(); + Inspector::InjectedScript injectedScriptForEval(Inspector::Protocol::ErrorString&, std::optional&&) override; + void muteConsole() override; + void unmuteConsole() override; void reportExecutionContextCreation(); void notifyContextCreated(const Inspector::Protocol::Network::FrameId&, JSC::JSGlobalObject*, const DOMWrapperWorld&, SecurityOrigin* = nullptr); 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 8699436e3f962b465b47aebebd601ee90152ef83..35fbd46627f68d9ebac52500bc560d4fd9866166 100644 --- a/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.cpp +++ b/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.cpp @@ -38,9 +38,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 ? std::optional(ProcessingUserGesture) : std::nullopt) + , m_gestureIndicator(emulateUserGesture ? std::optional(ProcessingUserGesture) : std::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 16edb3bc689b8e2dde17597b642b706c1343e1f5..f363b2ca2410f22cff8d6ad908a88527970ab1d8 100644 --- a/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.h +++ b/Source/WebCore/inspector/agents/page/UserGestureEmulationScope.h @@ -38,12 +38,13 @@ namespace WebCore { class ChromeClient; class Page; +class Document; class UserGestureEmulationScope { WTF_MAKE_NONCOPYABLE(UserGestureEmulationScope); WTF_MAKE_FAST_ALLOCATED; public: - UserGestureEmulationScope(Page& inspectedPage, bool emulateUserGesture); + UserGestureEmulationScope(Page& inspectedPage, bool emulateUserGesture, Document* document); ~UserGestureEmulationScope(); private: diff --git a/Source/WebCore/layout/integration/LayoutIntegrationLineLayout.cpp b/Source/WebCore/layout/integration/LayoutIntegrationLineLayout.cpp index 7f9397a2aa7b8e611886c5bfa23019a578c1f354..18617fb37245d7087825fe3c94feda94b117a320 100644 --- a/Source/WebCore/layout/integration/LayoutIntegrationLineLayout.cpp +++ b/Source/WebCore/layout/integration/LayoutIntegrationLineLayout.cpp @@ -250,7 +250,7 @@ void LineLayout::prepareLayoutState() auto& rootGeometry = m_layoutState.ensureGeometryForBox(rootLayoutBox()); rootGeometry.setContentBoxWidth(flow().contentSize().width()); - rootGeometry.setPadding({ }); + rootGeometry.setPadding(Layout::Edges{}); rootGeometry.setBorder({ }); rootGeometry.setHorizontalMargin({ }); rootGeometry.setVerticalMargin({ }); diff --git a/Source/WebCore/loader/CookieJar.h b/Source/WebCore/loader/CookieJar.h index 982691dd2dfe2f65201370a12302b5086703c126..4af72beb3b1405ffac78e89e7fbb2b14d6647903 100644 --- a/Source/WebCore/loader/CookieJar.h +++ b/Source/WebCore/loader/CookieJar.h @@ -43,6 +43,7 @@ struct CookieRequestHeaderFieldProxy; class NetworkStorageSession; class StorageSessionProvider; struct SameSiteInfo; +class ResourceLoader; class WEBCORE_EXPORT CookieJar : public RefCounted { public: @@ -66,6 +67,9 @@ public: virtual void clearCache() { } virtual void clearCacheForHost(const String&) { } + // Playwright. + virtual void setCookieFromResponse(ResourceLoader&, const String&) { } + virtual ~CookieJar(); protected: static SameSiteInfo sameSiteInfo(const Document&, IsForDOMCookieAccess = IsForDOMCookieAccess::No); diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp index 367675741089a498870aa9e16a20b419bee0eef9..b15bf5fd318862fd50aa2f5cf26cd29d75618aa2 100644 --- a/Source/WebCore/loader/DocumentLoader.cpp +++ b/Source/WebCore/loader/DocumentLoader.cpp @@ -1408,8 +1408,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 e693532ebd64f5c042c7c37d839189597d6e6909..242829bb5200d6524978594cdc9061dc538c3cdd 100644 --- a/Source/WebCore/loader/DocumentLoader.h +++ b/Source/WebCore/loader/DocumentLoader.h @@ -166,9 +166,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 cf22e4f086a275725a943e4069e073e29067f16d..8d7bfb190c746a5dd0876ad4acd6571fe8f529ec 100644 --- a/Source/WebCore/loader/FrameLoader.cpp +++ b/Source/WebCore/loader/FrameLoader.cpp @@ -1153,6 +1153,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(); @@ -1471,6 +1472,7 @@ void FrameLoader::load(FrameLoadRequest&& request) void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, NavigationAction&& action, FrameLoadType type, RefPtr&& formState, AllowNavigationToInvalidURL allowNavigationToInvalidURL, CompletionHandler&& completionHandler) { + InspectorInstrumentation::frameScheduledNavigation(m_frame, Seconds(0)); FRAMELOADER_RELEASE_LOG(ResourceLoading, "loadWithNavigationAction: frame load started"); Ref loader = m_client->createDocumentLoader(request, defaultSubstituteDataForURL(request.url())); @@ -1574,6 +1576,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 }; @@ -3171,6 +3175,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) @@ -3932,9 +3938,6 @@ String FrameLoader::referrer() const void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() { - if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) - return; - Vector> worlds; ScriptController::getAllWorlds(worlds); for (auto& world : worlds) @@ -3943,13 +3946,13 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds() void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world) { - if (!m_frame.script().canExecuteScripts(NotAboutToExecuteScript) || !m_frame.windowProxy().existingJSWindowProxy(world)) - return; - - m_client->dispatchDidClearWindowObjectInWorld(world); + if (m_frame.windowProxy().existingJSWindowProxy(world)) { + if (m_frame.script().canExecuteScripts(NotAboutToExecuteScript)) + 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 b018af04d05ce3ac38bb57d8e50a7b063ee51733..6929c01318f509ed560276168d18e0112b116bc2 100644 --- a/Source/WebCore/loader/LoaderStrategy.h +++ b/Source/WebCore/loader/LoaderStrategy.h @@ -84,6 +84,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/PolicyChecker.cpp b/Source/WebCore/loader/PolicyChecker.cpp index c082a981526d40408c85bb16683ab14ef6dd6e88..2f8eb1b0cabb23b230ea37254e7a18077335bc30 100644 --- a/Source/WebCore/loader/PolicyChecker.cpp +++ b/Source/WebCore/loader/PolicyChecker.cpp @@ -46,6 +46,7 @@ #include "HTMLFormElement.h" #include "HTMLFrameOwnerElement.h" #include "HTMLPlugInElement.h" +#include "InspectorInstrumentation.h" #include "Logging.h" #include "ThreadableBlobRegistry.h" #include @@ -261,26 +262,32 @@ void FrameLoader::PolicyChecker::checkNewWindowPolicy(NavigationAction&& navigat auto blobURLLifetimeExtension = extendBlobURLLifetimeIfNecessary(request, nullptr); + InspectorInstrumentation::willCheckNewWindowPolicy(m_frame, request.url()); auto requestIdentifier = PolicyCheckIdentifier::create(); m_frame.loader().client().dispatchDecidePolicyForNewWindowAction(navigationAction, request, formState.get(), frameName, requestIdentifier, [frame = makeRef(m_frame), request, formState = WTFMove(formState), frameName, navigationAction, function = WTFMove(function), blobURLLifetimeExtension = WTFMove(blobURLLifetimeExtension), requestIdentifier] (PolicyAction policyAction, PolicyCheckIdentifier responseIdentifier) mutable { - if (!responseIdentifier.isValidFor(requestIdentifier)) + if (!responseIdentifier.isValidFor(requestIdentifier)) { + InspectorInstrumentation::didCheckNewWindowPolicy(frame.get(), false); return function({ }, nullptr, { }, { }, ShouldContinuePolicyCheck::No); + } switch (policyAction) { case PolicyAction::Download: frame->loader().client().startDownload(request); FALLTHROUGH; case PolicyAction::Ignore: + InspectorInstrumentation::didCheckNewWindowPolicy(frame.get(), false); function({ }, nullptr, { }, { }, ShouldContinuePolicyCheck::No); return; case PolicyAction::StopAllLoads: ASSERT_NOT_REACHED(); + InspectorInstrumentation::didCheckNewWindowPolicy(frame.get(), false); function({ }, nullptr, { }, { }, ShouldContinuePolicyCheck::No); return; case PolicyAction::Use: + InspectorInstrumentation::didCheckNewWindowPolicy(frame.get(), true); function(request, makeWeakPtr(formState.get()), frameName, navigationAction, ShouldContinuePolicyCheck::Yes); return; } diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp index 0dcb47556d04874878656e459c9bac9af64dcfbf..df57e9a47160bfbeb8188d80afd175c756e982f9 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/ChromeClient.h b/Source/WebCore/page/ChromeClient.h index a8968c944e4a1abacc8c2fd03b971fd3b3f8e72c..2775d7b9e6794293935bb621b4b6154c5118641d 100644 --- a/Source/WebCore/page/ChromeClient.h +++ b/Source/WebCore/page/ChromeClient.h @@ -306,7 +306,7 @@ public: #endif #if ENABLE(ORIENTATION_EVENTS) - virtual int deviceOrientation() const = 0; + virtual int deviceOrientation() const { return 0; } #endif #if ENABLE(INPUT_TYPE_COLOR) diff --git a/Source/WebCore/page/EventHandler.cpp b/Source/WebCore/page/EventHandler.cpp index 05cda6581924a26cf705c98295fd428e4364f73b..60288898598c45f30c81d95f234cd22bf6b296b3 100644 --- a/Source/WebCore/page/EventHandler.cpp +++ b/Source/WebCore/page/EventHandler.cpp @@ -126,6 +126,7 @@ #if ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS) #include "PlatformTouchEvent.h" +#include "PointerCaptureController.h" #endif #if ENABLE(MAC_GESTURE_EVENTS) @@ -785,9 +786,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; @@ -827,8 +826,6 @@ VisiblePosition EventHandler::selectionExtentRespectingEditingBoundary(const Vis return adjustedTarget->renderer()->positionForPoint(LayoutPoint(selectionEndPoint), nullptr); } -#if ENABLE(DRAG_SUPPORT) - #if !PLATFORM(IOS_FAMILY) bool EventHandler::supportsSelectionUpdatesOnMouseDrag() const @@ -850,8 +847,10 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e Ref protectedFrame(m_frame); +#if ENABLE(DRAG_SUPPORT) if (handleDrag(event, checkDragHysteresis)) return true; +#endif RefPtr targetNode = event.targetNode(); if (event.event().button() != LeftButton || !targetNode) @@ -872,7 +871,9 @@ bool EventHandler::handleMouseDraggedEvent(const MouseEventWithHitTestResults& e ASSERT(mouseDownMayStartSelect() || m_mouseDownMayStartAutoscroll); #endif +#if ENABLE(DRAG_SUPPORT) m_mouseDownMayStartDrag = false; +#endif if (m_mouseDownMayStartAutoscroll && !panScrollInProgress()) { m_autoscrollController->startAutoscrollForSelection(renderer); @@ -889,6 +890,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 @@ -920,6 +923,8 @@ bool EventHandler::eventMayStartDrag(const PlatformMouseEvent& event) const return targetElement && page->dragController().draggableElement(&m_frame, targetElement.get(), result.roundedPointInInnerNodeFrame(), state); } +#endif // ENABLE(DRAG_SUPPORT) + void EventHandler::updateSelectionForMouseDrag() { if (!supportsSelectionUpdatesOnMouseDrag()) @@ -1014,7 +1019,6 @@ void EventHandler::updateSelectionForMouseDrag(const HitTestResult& hitTestResul if (oldSelection != newSelection && HTMLElement::isImageOverlayText(newSelection.start().containerNode()) && HTMLElement::isImageOverlayText(newSelection.end().containerNode())) invalidateClick(); } -#endif // ENABLE(DRAG_SUPPORT) void EventHandler::lostMouseCapture() { @@ -1062,9 +1066,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; @@ -2030,10 +2032,8 @@ bool EventHandler::handleMouseMoveEvent(const PlatformMouseEvent& platformMouseE swallowEvent = !dispatchMouseEvent(eventNames().mousemoveEvent, mouseEvent.targetNode(), 0, platformMouseEvent, FireMouseOverOut::Yes); -#if ENABLE(DRAG_SUPPORT) if (!swallowEvent) swallowEvent = handleMouseDraggedEvent(mouseEvent); -#endif return swallowEvent; } @@ -4040,7 +4040,14 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr if (!m_frame.document()) return false; - dragState().dataTransfer = DataTransfer::createForDrag(*m_frame.document()); +#if PLATFORM(MAC) + auto* page = m_frame.page(); + if (page && !page->overrideDragPasteboardName().isEmpty()) + dragState().dataTransfer = DataTransfer::createForDrag(*m_frame.document(), page->overrideDragPasteboardName()); + else +#endif + dragState().dataTransfer = DataTransfer::createForDrag(*m_frame.document()); + auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No; if (dragState().shouldDispatchEvents) { @@ -4479,7 +4486,8 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) allTouchReleased = false; } - for (auto& point : points) { + for (unsigned index = 0; index < points.size(); index++) { + auto& point = points[index]; PlatformTouchPoint::State pointState = point.state(); LayoutPoint pagePoint = documentPointForWindowPoint(m_frame, point.pos()); @@ -4606,6 +4614,9 @@ bool EventHandler::handleTouchEvent(const PlatformTouchEvent& event) changedTouches[pointState].m_touches->append(WTFMove(touch)); changedTouches[pointState].m_targets.add(touchTarget); } + document.page()->pointerCaptureController().dispatchEventForTouchAtIndex( + *touchTarget, event, index, index == 0, *document.windowProxy()); + } m_touchPressed = touches->length() > 0; if (allTouchReleased) diff --git a/Source/WebCore/page/EventHandler.h b/Source/WebCore/page/EventHandler.h index a5af404614e6cf86d0bc5cc65024553032f8bb42..769570c304bce902ac17f130d139224f41bf1503 100644 --- a/Source/WebCore/page/EventHandler.h +++ b/Source/WebCore/page/EventHandler.h @@ -136,9 +136,7 @@ public: WEBCORE_EXPORT VisiblePosition selectionExtentRespectingEditingBoundary(const VisibleSelection&, const LayoutPoint&, Node*); -#if ENABLE(DRAG_SUPPORT) void updateSelectionForMouseDrag(); -#endif #if ENABLE(PAN_SCROLLING) void didPanScrollStart(); @@ -379,10 +377,8 @@ private: float scrollDistance(ScrollDirection, ScrollGranularity); bool handleKeyboardScrolling(KeyboardEvent&); -#if ENABLE(DRAG_SUPPORT) bool handleMouseDraggedEvent(const MouseEventWithHitTestResults&, CheckDragHysteresis = ShouldCheckDragHysteresis); bool shouldAllowMouseDownToStartDrag() const; -#endif WEBCORE_EXPORT bool handleMouseReleaseEvent(const MouseEventWithHitTestResults&); @@ -483,10 +479,8 @@ private: void defaultTabEventHandler(KeyboardEvent&); void defaultArrowEventHandler(FocusDirection, KeyboardEvent&); -#if ENABLE(DRAG_SUPPORT) OptionSet 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. @@ -494,9 +488,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); @@ -588,8 +583,8 @@ private: Timer m_autoHideCursorTimer; #endif -#if ENABLE(DRAG_SUPPORT) LayoutPoint m_dragStartPosition; +#if ENABLE(DRAG_SUPPORT) RefPtr m_dragTarget; bool m_mouseDownMayStartDrag { false }; bool m_dragMayStartSelectionInstead { false }; diff --git a/Source/WebCore/page/EventSource.cpp b/Source/WebCore/page/EventSource.cpp index 7b77e407ee5d08ab3784d0899cfa33f0177f0648..0060ebfb1128cc5eb28baa5ecf4538a203ba82e1 100644 --- a/Source/WebCore/page/EventSource.cpp +++ b/Source/WebCore/page/EventSource.cpp @@ -36,6 +36,7 @@ #include "CachedResourceRequestInitiators.h" #include "ContentSecurityPolicy.h" #include "EventNames.h" +#include "InspectorNetworkAgent.h" #include "MessageEvent.h" #include "ResourceError.h" #include "ResourceRequest.h" @@ -94,6 +95,7 @@ void EventSource::connect() ASSERT(!m_requestInFlight); ResourceRequest request { m_url }; + request.setInitiatorIdentifier(InspectorNetworkAgent::initiatorIdentifierForEventSource()); request.setHTTPMethod("GET"); request.setHTTPHeaderField(HTTPHeaderName::Accept, "text/event-stream"); request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache"); diff --git a/Source/WebCore/page/Frame.cpp b/Source/WebCore/page/Frame.cpp index 7054acc90214eb817bd784298ce77f76d32c5dee..658520b15acdd632aa01576fea1f49df3aa722f7 100644 --- a/Source/WebCore/page/Frame.cpp +++ b/Source/WebCore/page/Frame.cpp @@ -39,6 +39,7 @@ #include "CachedResourceLoader.h" #include "Chrome.h" #include "ChromeClient.h" +#include "ComposedTreeIterator.h" #include "DOMWindow.h" #include "DocumentTimeline.h" #include "DocumentType.h" @@ -71,6 +72,7 @@ #include "NavigationScheduler.h" #include "Navigator.h" #include "NodeList.h" +#include "NodeRenderStyle.h" #include "NodeTraversal.h" #include "Page.h" #include "ProcessWarming.h" @@ -183,6 +185,7 @@ Frame::Frame(Page& page, HTMLFrameOwnerElement* ownerElement, UniqueRefinit(); + InspectorInstrumentation::frameAttached(this); } Ref Frame::create(Page* page, HTMLFrameOwnerElement* ownerElement, UniqueRef&& client) @@ -368,7 +371,7 @@ void Frame::orientationChanged() int Frame::orientation() const { if (m_page) - return m_page->chrome().client().deviceOrientation(); + return m_page->orientation(); return 0; } #endif // ENABLE(ORIENTATION_EVENTS) @@ -1139,6 +1142,358 @@ DataDetectionResultsStorage& Frame::dataDetectionResults() #endif +void Frame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect) +{ + IntRect candidateRect; + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; + auto* candidate = nodeQualifierFunction(eventHandler().hitTestResultAtPoint(testPoint, hitType), failedNode, &candidateRect); + + // Bail if we have no candidate, or the candidate is already equal to our current best node, + // or our candidate is the avoidedNode and there is a current best node. + if (!candidate || candidate == best) + return; + + // The document should never be considered the best alternative. + if (candidate->isDocumentNode()) + return; + + if (best) { + IntRect bestIntersect = intersection(testRect, bestRect); + IntRect candidateIntersect = intersection(testRect, candidateRect); + // if the candidate intersection is smaller than the current best intersection, bail. + if (candidateIntersect.width() * candidateIntersect.height() <= bestIntersect.width() * bestIntersect.height()) + return; + } + + // At this point we either don't have a previous best, or our current candidate has a better intersection. + best = candidate; + bestPoint = testPoint; + bestRect = candidateRect; +} + +bool Frame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center) +{ + if (!m_doc || !m_doc->renderView()) + return false; + + FrameView* view = m_view.get(); + if (!view) + return false; + + center = view->windowToContents(roundedIntPoint(viewportLocation)); + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; + hitTestResult = eventHandler().hitTestResultAtPoint(center, hitType); + return true; +} + +Node* Frame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement) +{ + adjustedViewportLocation = viewportLocation; + + IntPoint testCenter; + HitTestResult candidateInfo; + if (!hitTestResultAtViewportLocation(viewportLocation, candidateInfo, testCenter)) + return nullptr; + + IntPoint bestPoint = testCenter; + + // We have the candidate node at the location, check whether it or one of its ancestors passes + // the qualifier function, which typically checks if the node responds to a particular event type. + Node* approximateNode = nodeQualifierFunction(candidateInfo, 0, 0); + + if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode && approximateNode->isContentEditable()) { + // If we are in editable content, we look for the root editable element. + approximateNode = approximateNode->rootEditableElement(); + // If we have a focusable node, there is no need to approximate. + if (approximateNode) + shouldApproximate = ShouldApproximate::No; + } + + float scale = page() ? page()->pageScaleFactor() : 1; +#if PLATFORM(IOS_FAMILY) + float ppiFactor = screenPPIFactor(); +#else + float ppiFactor = 326; // most popular iPhone PPI +#endif + + static const float unscaledSearchRadius = 15; + int searchRadius = static_cast(unscaledSearchRadius * ppiFactor / scale); + + if (approximateNode && shouldApproximate == ShouldApproximate::Yes) { + const float testOffsets[] = { + -.3f, -.3f, + -.6f, -.6f, + +.3f, +.3f, + -.9f, -.9f, + }; + + Node* originalApproximateNode = approximateNode; + for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) { + IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); + IntPoint testPoint = testCenter + testOffset; + + constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowChildFrameContent }; + auto candidateInfo = eventHandler().hitTestResultAtPoint(testPoint, hitType); + Node* candidateNode = nodeQualifierFunction(candidateInfo, 0, 0); + if (candidateNode && candidateNode->isDescendantOf(originalApproximateNode)) { + approximateNode = candidateNode; + bestPoint = testPoint; + break; + } + } + } else if (!approximateNode && shouldApproximate == ShouldApproximate::Yes) { + // Grab the closest parent element of our failed candidate node. + Node* candidate = candidateInfo.innerNode(); + Node* failedNode = candidate; + + while (candidate && !candidate->isElementNode()) + candidate = candidate->parentInComposedTree(); + + if (candidate) + failedNode = candidate; + + // The center point was tested earlier. + const float testOffsets[] = { + -.3f, -.3f, + +.3f, -.3f, + -.3f, +.3f, + +.3f, +.3f, + -.6f, -.6f, + +.6f, -.6f, + -.6f, +.6f, + +.6f, +.6f, + -1.f, 0, + +1.f, 0, + 0, +1.f, + 0, -1.f, + }; + IntRect bestFrame; + IntRect testRect(testCenter, IntSize()); + testRect.inflate(searchRadius); + int currentTestRadius = 0; + for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) { + IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); + IntPoint testPoint = testCenter + testOffset; + int testRadius = std::max(abs(testOffset.width()), abs(testOffset.height())); + if (testRadius > currentTestRadius) { + // Bail out with the best match within a radius + currentTestRadius = testRadius; + if (approximateNode) + break; + } + betterApproximateNode(testPoint, nodeQualifierFunction, approximateNode, failedNode, bestPoint, bestFrame, testRect); + } + } + + if (approximateNode) { + IntPoint p = m_view->contentsToWindow(bestPoint); + adjustedViewportLocation = p; + if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode->isContentEditable()) { + // When in editable content, look for the root editable node again, + // since this could be the node found with the approximation. + approximateNode = approximateNode->rootEditableElement(); + } + } + + return approximateNode; +} + +Node* Frame::deepestNodeAtLocation(const FloatPoint& viewportLocation) +{ + IntPoint center; + HitTestResult hitTestResult; + if (!hitTestResultAtViewportLocation(viewportLocation, hitTestResult, center)) + return nullptr; + + return hitTestResult.innerNode(); +} + +static bool nodeIsMouseFocusable(Node& node) +{ + if (!is(node)) + return false; + + auto& element = downcast(node); + if (element.isMouseFocusable()) + return true; + + if (auto shadowRoot = makeRefPtr(element.shadowRoot())) { + if (shadowRoot->delegatesFocus()) { + for (auto& node : composedTreeDescendants(element)) { + if (is(node) && downcast(node).isMouseFocusable()) + return true; + } + } + } + + return false; +} + +static bool nodeWillRespondToMouseEvents(Node& node) +{ + return node.willRespondToMouseClickEvents() || node.willRespondToMouseMoveEvents() || nodeIsMouseFocusable(node); +} + +Node* Frame::approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + // This function is only used for UIWebView. + auto&& ancestorRespondingToClickEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + bool bodyHasBeenReached = false; + bool pointerCursorStillValid = true; + + if (nodeBounds) + *nodeBounds = IntRect(); + + auto node = hitTestResult.innerNode(); + if (!node) + return nullptr; + + Node* pointerCursorNode = nullptr; + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + // We only accept pointer nodes before reaching the body tag. + if (node->hasTagName(HTMLNames::bodyTag)) { + // Make sure we cover the case of an empty editable body. + if (!pointerCursorNode && node->isContentEditable()) + pointerCursorNode = node; + bodyHasBeenReached = true; + pointerCursorStillValid = false; + } + + // If we already have a pointer, and we reach a table, don't accept it. + if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag))) + pointerCursorStillValid = false; + + // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor. + if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CursorType::Pointer) + pointerCursorNode = node; + else if (pointerCursorNode) { + // We want the lowest unbroken chain of pointer cursors. + pointerCursorStillValid = false; + } + + if (nodeWillRespondToMouseEvents(*node)) { + // If we're at the body or higher, use the pointer cursor node (which may be null). + if (bodyHasBeenReached) + node = pointerCursorNode; + + // If we are interested about the frame, use it. + if (nodeBounds) { + // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check. + if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is(*node)) + *nodeBounds = snappedIntRect(downcast(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer())); + else if (node && node->renderer()) + *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); + } + + return node; + } + } + + return nullptr; + }; + + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToClickEvents), ShouldApproximate::Yes); +} + +static inline NodeQualifier ancestorRespondingToClickEventsNodeQualifier(SecurityOrigin* securityOrigin = nullptr) +{ + return [securityOrigin](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) + *nodeBounds = IntRect(); + + auto node = hitTestResult.innerNode(); + if (!node || (securityOrigin && !securityOrigin->isSameOriginAs(node->document().securityOrigin()))) + return nullptr; + + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + if (nodeWillRespondToMouseEvents(*node)) { + // If we are interested about the frame, use it. + if (nodeBounds) { + // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check. + if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is(*node)) + *nodeBounds = snappedIntRect(downcast(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer())); + else if (node && node->renderer()) + *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); + } + + return node; + } + } + + return nullptr; + }; +} + +Node* Frame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin) +{ + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(securityOrigin), ShouldApproximate::Yes); +} + +Node* Frame::nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + auto&& ancestorRespondingToDoubleClickEvent = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) + *nodeBounds = IntRect(); + + auto* node = hitTestResult.innerNode(); + if (!node) + return nullptr; + + for (; node && node != terminationNode; node = node->parentInComposedTree()) { + if (!node->hasEventListeners(eventNames().dblclickEvent)) + continue; +#if ENABLE(TOUCH_EVENTS) + if (!node->allowsDoubleTapGesture()) + continue; +#endif + if (nodeBounds && node->renderer()) + *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); + return node; + } + return nullptr; + }; + + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes); +} + +Node* Frame::nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) +{ + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(), ShouldApproximate::Yes, ShouldFindRootEditableElement::No); +} + +Node* Frame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation) +{ + auto&& ancestorRespondingToScrollWheelEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { + if (nodeBounds) + *nodeBounds = IntRect(); + + Node* scrollingAncestor = nullptr; + for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) { + RenderObject* renderer = node->renderer(); + if (!renderer) + continue; + + if ((renderer->isTextField() || renderer->isTextArea()) && downcast(*renderer).canScroll()) { + scrollingAncestor = node; + continue; + } + + auto& style = renderer->style(); + + if (renderer->hasOverflowClip() + && (style.overflowY() == Overflow::Auto || style.overflowY() == Overflow::Scroll + || style.overflowX() == Overflow::Auto || style.overflowX() == Overflow::Scroll)) { + scrollingAncestor = node; + } + } + + return scrollingAncestor; + }; + + FloatPoint adjustedViewportLocation; + return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToScrollWheelEvents), ShouldApproximate::No); +} + } // namespace WebCore #undef FRAME_RELEASE_LOG_ERROR diff --git a/Source/WebCore/page/Frame.h b/Source/WebCore/page/Frame.h index f0743e939757f672a7276fabe3b6596e3179ae2b..f1863e330e7ff386bfbf664df1c798436c1dd57e 100644 --- a/Source/WebCore/page/Frame.h +++ b/Source/WebCore/page/Frame.h @@ -110,8 +110,8 @@ enum { }; enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll }; -using NodeQualifier = Function; #endif +using NodeQualifier = Function; enum { LayerTreeFlagsIncludeDebugInfo = 1 << 0, @@ -229,10 +229,6 @@ public: WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults(); #endif -#if PLATFORM(IOS_FAMILY) - const ViewportArguments& viewportArguments() const; - WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&); - WEBCORE_EXPORT Node* deepestNodeAtLocation(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* = nullptr); WEBCORE_EXPORT Node* nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); @@ -240,6 +236,10 @@ public: WEBCORE_EXPORT Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation); WEBCORE_EXPORT Node* approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation); +#if PLATFORM(IOS_FAMILY) + const ViewportArguments& viewportArguments() const; + WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&); + WEBCORE_EXPORT NSArray *wordsInCurrentParagraph() const; WEBCORE_EXPORT CGRect renderRectForPoint(CGPoint, bool* isReplaced, float* fontSize) const; @@ -311,6 +311,7 @@ public: WEBCORE_EXPORT FloatSize screenSize() const; void setOverrideScreenSize(FloatSize&&); + bool hasScreenSizeOverride() const { return !m_overrideScreenSize.isEmpty(); } void selfOnlyRef(); void selfOnlyDeref(); @@ -349,7 +350,6 @@ private: #if ENABLE(DATA_DETECTION) std::unique_ptr m_dataDetectionResults; #endif -#if PLATFORM(IOS_FAMILY) void betterApproximateNode(const IntPoint& testPoint, const NodeQualifier&, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect); bool hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult&, IntPoint& center); @@ -357,6 +357,7 @@ private: enum class ShouldFindRootEditableElement : bool { No, Yes }; Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier&, ShouldApproximate, ShouldFindRootEditableElement = ShouldFindRootEditableElement::Yes); +#if PLATFORM(IOS_FAMILY) void setTimersPausedInternal(bool); ViewportArguments m_viewportArguments; diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp index 8273a64fcdfb7d34eaa76f98ba7a2117eafbfbe6..8a2f97ac8f935a71fce96913f8b10551a85de563 100644 --- a/Source/WebCore/page/FrameSnapshotting.cpp +++ b/Source/WebCore/page/FrameSnapshotting.cpp @@ -103,7 +103,7 @@ RefPtr snapshotFrameRectWithClip(Frame& frame, const IntRect& image // Other paint behaviors are set by paintContentsForSnapshot. frame.view()->setPaintBehavior(paintBehavior); - float scaleFactor = frame.page()->deviceScaleFactor(); + float scaleFactor = options.flags.contains(SnapshotFlags::OmitDeviceScaleFactor) ? 1 : frame.page()->deviceScaleFactor(); if (frame.page()->delegatesScaling()) scaleFactor *= frame.page()->pageScaleFactor(); @@ -114,7 +114,12 @@ RefPtr snapshotFrameRectWithClip(Frame& frame, const IntRect& image auto buffer = ImageBuffer::create(imageRect.size(), RenderingMode::Unaccelerated, scaleFactor, options.colorSpace, options.pixelFormat); if (!buffer) return nullptr; +#if !PLATFORM(MAC) + buffer->context().scale(scaleFactor); +#endif 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 +128,10 @@ RefPtr snapshotFrameRectWithClip(Frame& frame, const IntRect& image 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/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h index 1b77026f51092001cda86e32480890395b145b2e..6026bc23508016454f331b06c9f071a88f55cccc 100644 --- a/Source/WebCore/page/FrameSnapshotting.h +++ b/Source/WebCore/page/FrameSnapshotting.h @@ -50,6 +50,7 @@ enum class SnapshotFlags : uint8_t { PaintSelectionAndBackgroundsOnly = 1 << 4, PaintEverythingExcludingSelection = 1 << 5, PaintWithIntegralScaleFactor = 1 << 6, + OmitDeviceScaleFactor = 1 << 7, }; struct SnapshotOptions { diff --git a/Source/WebCore/page/FrameView.cpp b/Source/WebCore/page/FrameView.cpp index a7e9f33ea6effcda12ab56bb8618c8eb5e2cda60..fab672e5ae8559348059e360dfc0614ff4813d4a 100644 --- a/Source/WebCore/page/FrameView.cpp +++ b/Source/WebCore/page/FrameView.cpp @@ -3026,7 +3026,7 @@ void FrameView::setBaseBackgroundColor(const Color& backgroundColor) void FrameView::updateBackgroundRecursively(const std::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.value_or(RenderTheme::singleton().systemColor(CSSValueAppleSystemControlBackground, styleColorOptions())); #else Color baseBackgroundColor = backgroundColor.value_or(Color::white); diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp index 28d1fc3242174a680711027877d4153923790220..058b5309eed081fcc1e4158f66e806421dcc9d56 100644 --- a/Source/WebCore/page/History.cpp +++ b/Source/WebCore/page/History.cpp @@ -33,6 +33,7 @@ #include "FrameLoaderClient.h" #include "HistoryController.h" #include "HistoryItem.h" +#include "InspectorInstrumentation.h" #include "Logging.h" #include "NavigationScheduler.h" #include "Page.h" @@ -260,6 +261,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 f2f01ac8074e7208218ac3f749a27394b3cd1ba0..c6e857d2daa0b0141de6629e571ca82256e760f2 100644 --- a/Source/WebCore/page/Page.cpp +++ b/Source/WebCore/page/Page.cpp @@ -448,6 +448,37 @@ void Page::setOverrideViewportArguments(const std::optional& document->updateViewportArguments(); } +FloatSize Page::screenSize() +{ + return m_overrideScreenSize.value_or(screenRect(mainFrame().view()).size()); +} + +void Page::setOverrideScreenSize(std::optional size) +{ + if (size == m_overrideScreenSize) + return; + + m_overrideScreenSize = size; + if (auto* document = mainFrame().document()) + document->updateViewportArguments(); +} + +#if ENABLE(ORIENTATION_EVENTS) +int Page::orientation() const +{ + return m_overrideOrientation.value_or(chrome().client().deviceOrientation()); +} + +void Page::setOverrideOrientation(std::optional orientation) +{ + if (orientation == m_overrideOrientation) + return; + + m_overrideOrientation = orientation; + mainFrame().orientationChanged(); +} +#endif + ScrollingCoordinator* Page::scrollingCoordinator() { if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) { @@ -1269,11 +1300,6 @@ void Page::didCommitLoad() #if ENABLE(EDITABLE_REGION) m_isEditableRegionEnabled = false; #endif - -#if HAVE(OS_DARK_MODE_SUPPORT) - setUseDarkAppearanceOverride(std::nullopt); -#endif - resetSeenPlugins(); resetSeenMediaEngines(); @@ -3251,6 +3277,16 @@ void Page::setUseDarkAppearanceOverride(std::optional valueOverride) #endif } +void Page::setUseReducedMotionOverride(std::optional valueOverride) +{ + if (valueOverride == m_useReducedMotionOverride) + return; + + m_useReducedMotionOverride = valueOverride; + + appearanceDidChange(); +} + void Page::setFullscreenInsets(const FloatBoxExtent& insets) { if (insets == m_fullscreenInsets) diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h index 2079c5a54bb1084eaec1b5553a6115103b097c80..daeaece6c1bed4d37e19df2471b25e6ae3517d72 100644 --- a/Source/WebCore/page/Page.h +++ b/Source/WebCore/page/Page.h @@ -256,6 +256,9 @@ public: const std::optional& overrideViewportArguments() const { return m_overrideViewportArguments; } WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional&); + WEBCORE_EXPORT FloatSize screenSize(); + void setOverrideScreenSize(std::optional size); + static void refreshPlugins(bool reload); WEBCORE_EXPORT PluginData& pluginData(); void clearPluginData(); @@ -302,6 +305,10 @@ public: DragCaretController& dragCaretController() const { return *m_dragCaretController; } #if ENABLE(DRAG_SUPPORT) DragController& dragController() const { return *m_dragController; } +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_overrideDragPasteboardName = pasteboardName; } + const String& overrideDragPasteboardName() { return m_overrideDragPasteboardName; } +#endif #endif FocusController& focusController() const { return *m_focusController; } #if ENABLE(CONTEXT_MENUS) @@ -460,6 +467,8 @@ public: WEBCORE_EXPORT void effectiveAppearanceDidChange(bool useDarkAppearance, bool useElevatedUserInterfaceLevel); bool defaultUseDarkAppearance() const { return m_useDarkAppearance; } void setUseDarkAppearanceOverride(std::optional); + std::optional useReducedMotionOverride() const { return m_useReducedMotionOverride; } + void setUseReducedMotionOverride(std::optional); #if ENABLE(TEXT_AUTOSIZING) float textAutosizingWidth() const { return m_textAutosizingWidth; } @@ -836,6 +845,11 @@ public: WEBCORE_EXPORT Vector> editableElementsInRect(const FloatRect&) const; +#if ENABLE(ORIENTATION_EVENTS) + int orientation() const; + void setOverrideOrientation(std::optional); +#endif + #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); } #endif @@ -921,6 +935,9 @@ private: #if ENABLE(DRAG_SUPPORT) const std::unique_ptr m_dragController; +#if PLATFORM(MAC) + String m_overrideDragPasteboardName; +#endif #endif const std::unique_ptr m_focusController; #if ENABLE(CONTEXT_MENUS) @@ -1000,6 +1017,7 @@ private: bool m_useElevatedUserInterfaceLevel { false }; bool m_useDarkAppearance { false }; std::optional m_useDarkAppearanceOverride; + std::optional m_useReducedMotionOverride; #if ENABLE(TEXT_AUTOSIZING) float m_textAutosizingWidth { 0 }; @@ -1160,6 +1178,11 @@ private: #endif std::optional m_overrideViewportArguments; + std::optional m_overrideScreenSize; + +#if ENABLE(ORIENTATION_EVENTS) + std::optional m_overrideOrientation; +#endif #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY) RefPtr m_deviceOrientationUpdateProvider; diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp index 2903e934ebf5cf0e755d817d778717fe01ae066b..8d644b579ebd02761a4f6ff7db5f526623bc376c 100644 --- a/Source/WebCore/page/PointerCaptureController.cpp +++ b/Source/WebCore/page/PointerCaptureController.cpp @@ -202,7 +202,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi return iterator != m_activePointerIdsToCapturingData.end() && iterator->value.preventsCompatibilityMouseEvents; } -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +#if ENABLE(TOUCH_EVENTS) static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName) { for (ContainerNode* curr = target; curr; curr = curr->parentInComposedTree()) { @@ -489,7 +489,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint capturingData.pendingTargetOverride = nullptr; capturingData.state = CapturingData::State::Cancelled; -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +#if ENABLE(TOUCH_EVENTS) capturingData.previousTarget = nullptr; #endif diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h index 27ee794779152f113b49391e4e59614cb5794764..cad99479d44588710bb87dd1a6c6c367149c515a 100644 --- a/Source/WebCore/page/PointerCaptureController.h +++ b/Source/WebCore/page/PointerCaptureController.h @@ -57,7 +57,7 @@ public: RefPtr pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType); -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +#if ENABLE(TOUCH_EVENTS) void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&); #endif @@ -72,7 +72,7 @@ private: struct CapturingData { RefPtr pendingTargetOverride; RefPtr targetOverride; -#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) +#if ENABLE(TOUCH_EVENTS) RefPtr previousTarget; #endif bool hasAnyElement() const { diff --git a/Source/WebCore/page/RuntimeEnabledFeatures.cpp b/Source/WebCore/page/RuntimeEnabledFeatures.cpp index 6b2bc1bdb38be0543f20d51d200944b3f547f6a9..68a1773c0f578ecf8d5d7aa15ec1d34d9ad7a0a2 100644 --- a/Source/WebCore/page/RuntimeEnabledFeatures.cpp +++ b/Source/WebCore/page/RuntimeEnabledFeatures.cpp @@ -56,7 +56,11 @@ RuntimeEnabledFeatures& RuntimeEnabledFeatures::sharedFeatures() #if ENABLE(TOUCH_EVENTS) bool RuntimeEnabledFeatures::touchEventsEnabled() const { - return m_touchEventsEnabled.value_or(screenHasTouchDevice()); + return m_touchEventsEnabled.value_or(platformScreenHasTouchDevice()); +} +bool RuntimeEnabledFeatures::isTouchPrimaryInputDevice() const +{ + return m_touchEventsEnabled.value_or(platformScreenIsTouchPrimaryInputDevice()); } #endif diff --git a/Source/WebCore/page/RuntimeEnabledFeatures.h b/Source/WebCore/page/RuntimeEnabledFeatures.h index e16cb5d15762186550f95baaa2fb4ee8ca36d6ce..4a73cc01fb8a51bfb6818343dbbfbd989cda6647 100644 --- a/Source/WebCore/page/RuntimeEnabledFeatures.h +++ b/Source/WebCore/page/RuntimeEnabledFeatures.h @@ -202,6 +202,7 @@ public: void setMouseEventsSimulationEnabled(bool isEnabled) { m_mouseEventsSimulationEnabled = isEnabled; } bool touchEventsEnabled() const; void setTouchEventsEnabled(bool isEnabled) { m_touchEventsEnabled = isEnabled; } + bool isTouchPrimaryInputDevice() const; #endif bool pageAtRuleSupportEnabled() const { return m_pageAtRuleSupportEnabled; } diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp index 7ac11c8289347e3a2f3e7316cf9e32932b9544ed..764b2d4fe36ac2e5588bd22595424ac11d42acd0 100644 --- a/Source/WebCore/page/Screen.cpp +++ b/Source/WebCore/page/Screen.cpp @@ -102,6 +102,8 @@ int Screen::availLeft() const return 0; if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailLeft); + if (frame->hasScreenSizeOverride()) + return 0; return static_cast(screenAvailableRect(frame->view()).x()); } @@ -112,6 +114,8 @@ int Screen::availTop() const return 0; if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailTop); + if (frame->hasScreenSizeOverride()) + return 0; return static_cast(screenAvailableRect(frame->view()).y()); } @@ -122,6 +126,8 @@ unsigned Screen::availHeight() const return 0; if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailHeight); + if (frame->hasScreenSizeOverride()) + return static_cast(frame->screenSize().height()); return static_cast(screenAvailableRect(frame->view()).height()); } @@ -132,6 +138,8 @@ unsigned Screen::availWidth() const return 0; if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled()) ResourceLoadObserver::shared().logScreenAPIAccessed(*frame->document(), ResourceLoadStatistics::ScreenAPI::AvailWidth); + if (frame->hasScreenSizeOverride()) + return static_cast(frame->screenSize().width()); return static_cast(screenAvailableRect(frame->view()).width()); } diff --git a/Source/WebCore/page/SocketProvider.cpp b/Source/WebCore/page/SocketProvider.cpp index 3bec0aef174336939838fb1069fffbcb9f3d5604..566ef3806be3c5ccf1bb951251c2a90dba7071a3 100644 --- a/Source/WebCore/page/SocketProvider.cpp +++ b/Source/WebCore/page/SocketProvider.cpp @@ -33,7 +33,7 @@ namespace WebCore { Ref SocketProvider::createSocketStreamHandle(const URL& url, SocketStreamHandleClient& client, WebSocketIdentifier, PAL::SessionID sessionID, const String& credentialPartition, const StorageSessionProvider* provider) { - return SocketStreamHandleImpl::create(url, client, sessionID, credentialPartition, { }, provider); + return SocketStreamHandleImpl::create(url, false, client, sessionID, credentialPartition, { }, provider); } RefPtr SocketProvider::createWebSocketChannel(Document&, WebSocketChannelClient&) diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp index fc85fffa9b20cf5d3a2cff89b7d38ecf84aa0ff6..1070a1973d0ea23c6781df4269fc43498ce18608 100644 --- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp +++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp @@ -281,6 +281,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) @@ -294,6 +296,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) { @@ -310,6 +314,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/page/ios/FrameIOS.mm b/Source/WebCore/page/ios/FrameIOS.mm index 12cc7336ae87b6d9d8ea83cf543d029914eaf1db..b97227e21bf9e7166980c20d2efdc24ea28058a2 100644 --- a/Source/WebCore/page/ios/FrameIOS.mm +++ b/Source/WebCore/page/ios/FrameIOS.mm @@ -226,354 +226,6 @@ CGRect Frame::renderRectForPoint(CGPoint point, bool* isReplaced, float* fontSiz return CGRectZero; } -void Frame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect) -{ - IntRect candidateRect; - constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; - auto* candidate = nodeQualifierFunction(eventHandler().hitTestResultAtPoint(testPoint, hitType), failedNode, &candidateRect); - - // Bail if we have no candidate, or the candidate is already equal to our current best node, - // or our candidate is the avoidedNode and there is a current best node. - if (!candidate || candidate == best) - return; - - // The document should never be considered the best alternative. - if (candidate->isDocumentNode()) - return; - - if (best) { - IntRect bestIntersect = intersection(testRect, bestRect); - IntRect candidateIntersect = intersection(testRect, candidateRect); - // if the candidate intersection is smaller than the current best intersection, bail. - if (candidateIntersect.width() * candidateIntersect.height() <= bestIntersect.width() * bestIntersect.height()) - return; - } - - // At this point we either don't have a previous best, or our current candidate has a better intersection. - best = candidate; - bestPoint = testPoint; - bestRect = candidateRect; -} - -bool Frame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center) -{ - if (!m_doc || !m_doc->renderView()) - return false; - - FrameView* view = m_view.get(); - if (!view) - return false; - - center = view->windowToContents(roundedIntPoint(viewportLocation)); - constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly }; - hitTestResult = eventHandler().hitTestResultAtPoint(center, hitType); - return true; -} - -Node* Frame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement) -{ - adjustedViewportLocation = viewportLocation; - - IntPoint testCenter; - HitTestResult candidateInfo; - if (!hitTestResultAtViewportLocation(viewportLocation, candidateInfo, testCenter)) - return nullptr; - - IntPoint bestPoint = testCenter; - - // We have the candidate node at the location, check whether it or one of its ancestors passes - // the qualifier function, which typically checks if the node responds to a particular event type. - Node* approximateNode = nodeQualifierFunction(candidateInfo, 0, 0); - - if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode && approximateNode->isContentEditable()) { - // If we are in editable content, we look for the root editable element. - approximateNode = approximateNode->rootEditableElement(); - // If we have a focusable node, there is no need to approximate. - if (approximateNode) - shouldApproximate = ShouldApproximate::No; - } - - float scale = page() ? page()->pageScaleFactor() : 1; - float ppiFactor = screenPPIFactor(); - - static const float unscaledSearchRadius = 15; - int searchRadius = static_cast(unscaledSearchRadius * ppiFactor / scale); - - if (approximateNode && shouldApproximate == ShouldApproximate::Yes) { - const float testOffsets[] = { - -.3f, -.3f, - -.6f, -.6f, - +.3f, +.3f, - -.9f, -.9f, - }; - - Node* originalApproximateNode = approximateNode; - for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) { - IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); - IntPoint testPoint = testCenter + testOffset; - - constexpr OptionSet hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowChildFrameContent }; - auto candidateInfo = eventHandler().hitTestResultAtPoint(testPoint, hitType); - Node* candidateNode = nodeQualifierFunction(candidateInfo, 0, 0); - if (candidateNode && candidateNode->isDescendantOf(originalApproximateNode)) { - approximateNode = candidateNode; - bestPoint = testPoint; - break; - } - } - } else if (!approximateNode && shouldApproximate == ShouldApproximate::Yes) { - // Grab the closest parent element of our failed candidate node. - Node* candidate = candidateInfo.innerNode(); - Node* failedNode = candidate; - - while (candidate && !candidate->isElementNode()) - candidate = candidate->parentInComposedTree(); - - if (candidate) - failedNode = candidate; - - // The center point was tested earlier. - const float testOffsets[] = { - -.3f, -.3f, - +.3f, -.3f, - -.3f, +.3f, - +.3f, +.3f, - -.6f, -.6f, - +.6f, -.6f, - -.6f, +.6f, - +.6f, +.6f, - -1.f, 0, - +1.f, 0, - 0, +1.f, - 0, -1.f, - }; - IntRect bestFrame; - IntRect testRect(testCenter, IntSize()); - testRect.inflate(searchRadius); - int currentTestRadius = 0; - for (unsigned n = 0; n < WTF_ARRAY_LENGTH(testOffsets); n += 2) { - IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius); - IntPoint testPoint = testCenter + testOffset; - int testRadius = std::max(abs(testOffset.width()), abs(testOffset.height())); - if (testRadius > currentTestRadius) { - // Bail out with the best match within a radius - currentTestRadius = testRadius; - if (approximateNode) - break; - } - betterApproximateNode(testPoint, nodeQualifierFunction, approximateNode, failedNode, bestPoint, bestFrame, testRect); - } - } - - if (approximateNode) { - IntPoint p = m_view->contentsToWindow(bestPoint); - adjustedViewportLocation = p; - if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode->isContentEditable()) { - // When in editable content, look for the root editable node again, - // since this could be the node found with the approximation. - approximateNode = approximateNode->rootEditableElement(); - } - } - - return approximateNode; -} - -Node* Frame::deepestNodeAtLocation(const FloatPoint& viewportLocation) -{ - IntPoint center; - HitTestResult hitTestResult; - if (!hitTestResultAtViewportLocation(viewportLocation, hitTestResult, center)) - return nullptr; - - return hitTestResult.innerNode(); -} - -static bool nodeIsMouseFocusable(Node& node) -{ - if (!is(node)) - return false; - - auto& element = downcast(node); - if (element.isMouseFocusable()) - return true; - - if (auto shadowRoot = makeRefPtr(element.shadowRoot())) { - if (shadowRoot->delegatesFocus()) { - for (auto& node : composedTreeDescendants(element)) { - if (is(node) && downcast(node).isMouseFocusable()) - return true; - } - } - } - - return false; -} - -static bool nodeWillRespondToMouseEvents(Node& node) -{ - return node.willRespondToMouseClickEvents() || node.willRespondToMouseMoveEvents() || nodeIsMouseFocusable(node); -} - -Node* Frame::approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) -{ - // This function is only used for UIWebView. - auto&& ancestorRespondingToClickEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { - bool bodyHasBeenReached = false; - bool pointerCursorStillValid = true; - - if (nodeBounds) - *nodeBounds = IntRect(); - - auto node = hitTestResult.innerNode(); - if (!node) - return nullptr; - - Node* pointerCursorNode = nullptr; - for (; node && node != terminationNode; node = node->parentInComposedTree()) { - // We only accept pointer nodes before reaching the body tag. - if (node->hasTagName(HTMLNames::bodyTag)) { - // Make sure we cover the case of an empty editable body. - if (!pointerCursorNode && node->isContentEditable()) - pointerCursorNode = node; - bodyHasBeenReached = true; - pointerCursorStillValid = false; - } - - // If we already have a pointer, and we reach a table, don't accept it. - if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag))) - pointerCursorStillValid = false; - - // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor. - if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CursorType::Pointer) - pointerCursorNode = node; - else if (pointerCursorNode) { - // We want the lowest unbroken chain of pointer cursors. - pointerCursorStillValid = false; - } - - if (nodeWillRespondToMouseEvents(*node)) { - // If we're at the body or higher, use the pointer cursor node (which may be null). - if (bodyHasBeenReached) - node = pointerCursorNode; - - // If we are interested about the frame, use it. - if (nodeBounds) { - // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check. - if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is(*node)) - *nodeBounds = snappedIntRect(downcast(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer())); - else if (node && node->renderer()) - *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); - } - - return node; - } - } - - return nullptr; - }; - - return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToClickEvents), ShouldApproximate::Yes); -} - -static inline NodeQualifier ancestorRespondingToClickEventsNodeQualifier(SecurityOrigin* securityOrigin = nullptr) -{ - return [securityOrigin](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { - if (nodeBounds) - *nodeBounds = IntRect(); - - auto node = hitTestResult.innerNode(); - if (!node || (securityOrigin && !securityOrigin->isSameOriginAs(node->document().securityOrigin()))) - return nullptr; - - for (; node && node != terminationNode; node = node->parentInComposedTree()) { - if (nodeWillRespondToMouseEvents(*node)) { - // If we are interested about the frame, use it. - if (nodeBounds) { - // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check. - if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is(*node)) - *nodeBounds = snappedIntRect(downcast(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer())); - else if (node && node->renderer()) - *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); - } - - return node; - } - } - - return nullptr; - }; -} - -Node* Frame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin) -{ - return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(securityOrigin), ShouldApproximate::Yes); -} - -Node* Frame::nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) -{ - auto&& ancestorRespondingToDoubleClickEvent = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { - if (nodeBounds) - *nodeBounds = IntRect(); - - auto* node = hitTestResult.innerNode(); - if (!node) - return nullptr; - - for (; node && node != terminationNode; node = node->parentInComposedTree()) { - if (!node->hasEventListeners(eventNames().dblclickEvent)) - continue; -#if ENABLE(TOUCH_EVENTS) - if (!node->allowsDoubleTapGesture()) - continue; -#endif - if (nodeBounds && node->renderer()) - *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true); - return node; - } - return nullptr; - }; - - return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes); -} - -Node* Frame::nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation) -{ - return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(), ShouldApproximate::Yes, ShouldFindRootEditableElement::No); -} - -Node* Frame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation) -{ - auto&& ancestorRespondingToScrollWheelEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* { - if (nodeBounds) - *nodeBounds = IntRect(); - - Node* scrollingAncestor = nullptr; - for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) { - RenderObject* renderer = node->renderer(); - if (!renderer) - continue; - - if ((renderer->isTextField() || renderer->isTextArea()) && downcast(*renderer).canScroll()) { - scrollingAncestor = node; - continue; - } - - auto& style = renderer->style(); - - if (renderer->hasOverflowClip() - && (style.overflowY() == Overflow::Auto || style.overflowY() == Overflow::Scroll - || style.overflowX() == Overflow::Auto || style.overflowX() == Overflow::Scroll)) { - scrollingAncestor = node; - } - } - - return scrollingAncestor; - }; - - FloatPoint adjustedViewportLocation; - return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToScrollWheelEvents), ShouldApproximate::No); -} - int Frame::preferredHeight() const { Document* document = this->document(); diff --git a/Source/WebCore/page/wpe/DragControllerWPE.cpp b/Source/WebCore/page/wpe/DragControllerWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dedfa855f990643e3e7bbe7754abca4e88a0f1c --- /dev/null +++ b/Source/WebCore/page/wpe/DragControllerWPE.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007-20 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DragController.h" + +#include "DataTransfer.h" +#include "Document.h" +#include "DragData.h" +#include "Editor.h" +#include "Element.h" +#include "Frame.h" +#include "Pasteboard.h" +#include "markup.h" + +namespace WebCore { + +// FIXME: These values are straight out of DragControllerMac, so probably have +// little correlation with Gdk standards... +const int DragController::MaxOriginalImageArea = 1500 * 1500; +const int DragController::DragIconRightInset = 7; +const int DragController::DragIconBottomInset = 3; + +const float DragController::DragImageAlpha = 0.75f; + +bool DragController::isCopyKeyDown(const DragData& dragData) +{ + return dragData.flags().contains(DragApplicationFlags::IsCopyKeyDown); +} + +std::optional DragController::dragOperation(const DragData& dragData) +{ + // FIXME: This logic is incomplete + if (dragData.containsURL()) + return DragOperation::Copy; + + return std::nullopt; +} + +const IntSize& DragController::maxDragImageSize() +{ + static const IntSize maxDragImageSize(200, 200); + return maxDragImageSize; +} + +void DragController::cleanupAfterSystemDrag() +{ +} + +void DragController::declareAndWriteDragImage(DataTransfer& dataTransfer, Element& element, const URL& url, const String& label) +{ + Frame* frame = element.document().frame(); + ASSERT(frame); + frame->editor().writeImageToPasteboard(dataTransfer.pasteboard(), element, url, label); +} + +} diff --git a/Source/WebCore/platform/Cairo.cmake b/Source/WebCore/platform/Cairo.cmake index 1fb0e9d5cee3b3df4ee1e96eb8d75016ad687fc5..497bd34cc97e2d20c9d6982a8d92d852451743cd 100644 --- a/Source/WebCore/platform/Cairo.cmake +++ b/Source/WebCore/platform/Cairo.cmake @@ -16,6 +16,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS platform/graphics/cairo/ImageBufferCairoBackend.h platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.h platform/graphics/cairo/ImageBufferCairoSurfaceBackend.h + platform/graphics/cairo/ImageBufferUtilitiesCairo.h platform/graphics/cairo/RefPtrCairo.h ) diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h index 6600dfa7b189e15fab7fb796f66ef1a79dcd22f3..4c0bc485ca92614efca23a5a2da871b77d5285d3 100644 --- a/Source/WebCore/platform/DragData.h +++ b/Source/WebCore/platform/DragData.h @@ -48,7 +48,7 @@ typedef void* DragDataRef; #elif PLATFORM(WIN) typedef struct IDataObject* DragDataRef; -#elif PLATFORM(GTK) +#elif PLATFORM(GTK) || PLATFORM(WPE) namespace WebCore { class SelectionData; } diff --git a/Source/WebCore/platform/DragImage.cpp b/Source/WebCore/platform/DragImage.cpp index 6dfe0dd3ea4da3a1f5f0f6c79d6d1a3bf00c3159..683c1bdb2cb33538af14dcc5dab89d07dcd34eff 100644 --- a/Source/WebCore/platform/DragImage.cpp +++ b/Source/WebCore/platform/DragImage.cpp @@ -279,7 +279,7 @@ DragImage::~DragImage() deleteDragImage(m_dragImageRef); } -#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN) +#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN) && !PLATFORM(WPE) IntSize dragImageSize(DragImageRef) { diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h index 7d247dcd1a16f342c1754c45c4a73529bf8f71b2..6903f0a0ab250526f533bcc69e1af11e578fb03d 100644 --- a/Source/WebCore/platform/Pasteboard.h +++ b/Source/WebCore/platform/Pasteboard.h @@ -44,7 +44,7 @@ OBJC_CLASS NSString; OBJC_CLASS NSArray; #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) #include "SelectionData.h" #endif @@ -91,16 +91,12 @@ struct PasteboardWebContent { Vector clientTypes; Vector> clientData; #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) String contentOrigin; bool canSmartCopyOrDelete; String text; String markup; #endif -#if USE(LIBWPE) - String text; - String markup; -#endif }; struct PasteboardURL { @@ -109,7 +105,7 @@ struct PasteboardURL { #if PLATFORM(MAC) String userVisibleForm; #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) String markup; #endif }; @@ -188,6 +184,11 @@ public: #endif #endif +#if PLATFORM(WPE) && ENABLE(DRAG_SUPPORT) + explicit Pasteboard(std::unique_ptr&&, SelectionData&); + explicit Pasteboard(std::unique_ptr&&, SelectionData&&); +#endif + #if PLATFORM(WIN) explicit Pasteboard(std::unique_ptr&&, IDataObject*); explicit Pasteboard(std::unique_ptr&&, WCDataObject*); @@ -253,6 +254,12 @@ public: static std::unique_ptr createForGlobalSelection(std::unique_ptr&&); #endif +#if PLATFORM(WPE) + const SelectionData& selectionData() const { + return *m_selectionData; + } +#endif + #if PLATFORM(IOS_FAMILY) explicit Pasteboard(std::unique_ptr&&, int64_t changeCount); explicit Pasteboard(std::unique_ptr&&, const String& pasteboardName); @@ -287,6 +294,7 @@ public: COMPtr dataObject() const { return m_dataObject; } void setExternalDataObject(IDataObject*); const DragDataMap& dragDataMap() const { return m_dragDataMap; } + WEBCORE_EXPORT DragDataMap createDragDataMap(); void writeURLToWritableDataObject(const URL&, const String&); COMPtr writableDataObject() const { return m_writableDataObject; } void writeImageToDataObject(Element&, const URL&); // FIXME: Layering violation. @@ -338,6 +346,10 @@ private: String m_name; #endif +#if PLATFORM(WPE) + std::optional m_selectionData; +#endif + #if PLATFORM(COCOA) String m_pasteboardName; int64_t m_changeCount; @@ -353,6 +365,7 @@ private: COMPtr m_dataObject; COMPtr m_writableDataObject; DragDataMap m_dragDataMap; + bool m_forDrag = false; #endif }; diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h index f90f1dad6b7b4e6703745c9cb97a32c872fa1aa8..9ad9c22488cc001cade2e8e8a6f4e9b8dc515cbd 100644 --- a/Source/WebCore/platform/PlatformKeyboardEvent.h +++ b/Source/WebCore/platform/PlatformKeyboardEvent.h @@ -134,6 +134,7 @@ namespace WebCore { static String keyCodeForHardwareKeyCode(unsigned); static String keyIdentifierForGdkKeyCode(unsigned); static int windowsKeyCodeForGdkKeyCode(unsigned); + static unsigned gdkKeyCodeForWindowsKeyCode(int); static String singleCharacterString(unsigned); static bool modifiersContainCapsLock(unsigned); #endif @@ -143,6 +144,7 @@ namespace WebCore { static String keyCodeForHardwareKeyCode(unsigned); static String keyIdentifierForWPEKeyCode(unsigned); static int windowsKeyCodeForWPEKeyCode(unsigned); + static unsigned WPEKeyCodeForWindowsKeyCode(int); static String singleCharacterString(unsigned); #endif diff --git a/Source/WebCore/platform/PlatformScreen.cpp b/Source/WebCore/platform/PlatformScreen.cpp index ba50b688ab6d0bae5d199fa0bac4b7e2004baf81..0b83a798b00835635a95a0db22173de094ba4035 100644 --- a/Source/WebCore/platform/PlatformScreen.cpp +++ b/Source/WebCore/platform/PlatformScreen.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "PlatformScreen.h" +#include "RuntimeEnabledFeatures.h" #if PLATFORM(COCOA) @@ -72,3 +73,16 @@ const ScreenData* screenData(PlatformDisplayID screenDisplayID) } // namespace WebCore #endif // PLATFORM(COCOA) + +#if ENABLE(TOUCH_EVENTS) +namespace WebCore { + +bool screenHasTouchDevice() { + return RuntimeEnabledFeatures::sharedFeatures().touchEventsEnabled(); +} +bool screenIsTouchPrimaryInputDevice() { + return RuntimeEnabledFeatures::sharedFeatures().isTouchPrimaryInputDevice(); +} + +} // namespace WebCore +#endif diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h index bb5411ad58c4ea427837dc7ffeb8687d51e79061..0bc31619d5f8ce268cfbe8b4ee54f8c5d7903aa5 100644 --- a/Source/WebCore/platform/PlatformScreen.h +++ b/Source/WebCore/platform/PlatformScreen.h @@ -146,12 +146,14 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr); #endif #if ENABLE(TOUCH_EVENTS) -#if PLATFORM(GTK) || PLATFORM(WPE) WEBCORE_EXPORT bool screenHasTouchDevice(); WEBCORE_EXPORT bool screenIsTouchPrimaryInputDevice(); +#if PLATFORM(GTK) || PLATFORM(WPE) +bool platformScreenHasTouchDevice(); +bool platformScreenIsTouchPrimaryInputDevice(); #else -constexpr bool screenHasTouchDevice() { return true; } -constexpr bool screenIsTouchPrimaryInputDevice() { return true; } +constexpr bool platformScreenHasTouchDevice() { return true; } +constexpr bool platformScreenIsTouchPrimaryInputDevice() { return true; } #endif #endif diff --git a/Source/WebCore/platform/ScrollableArea.h b/Source/WebCore/platform/ScrollableArea.h index fd39633380b947a2050a7b8680c57990f6d75cb6..a9e564cee2d4b8e72344f31491a1561971d7dcf9 100644 --- a/Source/WebCore/platform/ScrollableArea.h +++ b/Source/WebCore/platform/ScrollableArea.h @@ -101,7 +101,7 @@ public: void doPostThumbMoveSnapping(ScrollbarOrientation); #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/SourcesGLib.txt b/Source/WebCore/platform/SourcesGLib.txt index df273e58adfa61c6d25332b321f6f7d7775c6167..36befc1a01b6a06f2157d80a00d42ef56eee024f 100644 --- a/Source/WebCore/platform/SourcesGLib.txt +++ b/Source/WebCore/platform/SourcesGLib.txt @@ -29,6 +29,7 @@ platform/glib/KeyedEncoderGlib.cpp platform/glib/LowPowerModeNotifierGLib.cpp platform/glib/SharedBufferGlib.cpp platform/glib/UserAgentGLib.cpp +platform/glib/PlatformSpeechSynthesizerGLib.cpp platform/network/glib/DNSResolveQueueGLib.cpp platform/network/glib/NetworkStateNotifierGLib.cpp diff --git a/Source/WebCore/platform/glib/PlatformSpeechSynthesizerGLib.cpp b/Source/WebCore/platform/glib/PlatformSpeechSynthesizerGLib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0c3a183e5bc44bdfa4201e0db2067b41bf51580 --- /dev/null +++ b/Source/WebCore/platform/glib/PlatformSpeechSynthesizerGLib.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 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. + */ + +#import "config.h" +#import "PlatformSpeechSynthesizer.h" + +#if ENABLE(SPEECH_SYNTHESIS) + +namespace WebCore { + +PlatformSpeechSynthesizer::PlatformSpeechSynthesizer(PlatformSpeechSynthesizerClient* client) + : m_speechSynthesizerClient(client) +{ +} + +PlatformSpeechSynthesizer::~PlatformSpeechSynthesizer() +{ +} + +void PlatformSpeechSynthesizer::initializeVoiceList() +{ +} + +void PlatformSpeechSynthesizer::pause() +{ +} + +void PlatformSpeechSynthesizer::resume() +{ +} + +void PlatformSpeechSynthesizer::speak(RefPtr&& utterance) +{ +} + +void PlatformSpeechSynthesizer::cancel() +{ +} + +void PlatformSpeechSynthesizer::resetState() +{ +} + +} // namespace WebCore + +#endif // ENABLE(SPEECH_SYNTHESIS) diff --git a/Source/WebCore/platform/graphics/FontCascade.h b/Source/WebCore/platform/graphics/FontCascade.h index 6dade9146fe99078ac1a58b28cf0c5dd0c351095..16a641f4237a8a3a7a40461e3429551f7ca96203 100644 --- a/Source/WebCore/platform/graphics/FontCascade.h +++ b/Source/WebCore/platform/graphics/FontCascade.h @@ -283,7 +283,8 @@ private: return true; if (textRenderingMode == TextRenderingMode::OptimizeSpeed) return false; -#if PLATFORM(COCOA) || USE(FREETYPE) + // WIN: quick fix for https://bugs.webkit.org/show_bug.cgi?id=201213 +#if PLATFORM(COCOA) || USE(FREETYPE) || PLATFORM(WIN) return true; #else return false; diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp index 4db603a94f3af1b1bce94ab0f1ae36054c004fcc..c1820f48eb86348f8ca678fde636244e8c91267e 100644 --- a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp +++ b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp @@ -48,6 +48,13 @@ #include #endif +#if PLATFORM(WPE) || PLATFORM(WIN) +#include // Needed by jpeglib.h for FILE. +extern "C" { +#include "jpeglib.h" +} +#endif + namespace WebCore { #if !PLATFORM(GTK) @@ -65,8 +72,75 @@ static bool encodeImage(cairo_surface_t* image, const String& mimeType, Vector data(cairo_surface_t* image, const String& mimeType, std::optional) +static Vector encodeJpeg(cairo_surface_t* image, int quality) +{ + if (cairo_surface_get_type(image) != CAIRO_SURFACE_TYPE_IMAGE) { + fprintf(stderr, "Unexpected cairo surface type: %d\n", cairo_surface_get_type(image)); + return { }; + } + + if (cairo_image_surface_get_format(image) != CAIRO_FORMAT_ARGB32) { + fprintf(stderr, "Unexpected surface image format: %d\n", cairo_image_surface_get_format(image)); + return { }; + } + + struct jpeg_compress_struct info; + struct jpeg_error_mgr error; + info.err = jpeg_std_error(&error); + jpeg_create_compress(&info); + + unsigned char* bufferPtr = nullptr; + unsigned long bufferSize; + jpeg_mem_dest(&info, &bufferPtr, &bufferSize); + info.image_width = cairo_image_surface_get_width(image); + info.image_height = cairo_image_surface_get_height(image); + +#ifndef LIBJPEG_TURBO_VERSION + COMPILE_ASSERT(false, only_libjpeg_turbo_is_supported); +#endif + +#if CPU(LITTLE_ENDIAN) + info.in_color_space = JCS_EXT_BGRA; +#else + info.in_color_space = JCS_EXT_ARGB; +#endif + // # of color components in input image + info.input_components = 4; + + jpeg_set_defaults(&info); + jpeg_set_quality(&info, quality, true); + + jpeg_start_compress(&info, true); + + while (info.next_scanline < info.image_height) + { + JSAMPROW row = cairo_image_surface_get_data(image) + (info.next_scanline * cairo_image_surface_get_stride(image)); + if (jpeg_write_scanlines(&info, &row, 1) != 1) { + fprintf(stderr, "JPEG library failed to encode line\n"); + break; + } + } + + jpeg_finish_compress(&info); + jpeg_destroy_compress(&info); + + Vector output; + output.append(bufferPtr, bufferSize); + // Cannot use unique_ptr as bufferPtr changes during compression. GUniquePtr would work + // but it's under GLib and won't work on Windows. + free(bufferPtr); + return output; +} + +Vector data(cairo_surface_t* image, const String& mimeType, std::optional quality) { + if (mimeType == "image/jpeg") { + int qualityPercent = 100; + if (quality) + qualityPercent = static_cast(*quality * 100.0 + 0.5); + return encodeJpeg(image, qualityPercent); + } + Vector encodedImage; if (!image || !encodeImage(image, mimeType, &encodedImage)) return { }; diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h index eac8346d3e177f87792fb0a8fc9dd0fb3b2f6efc..2ddd1dc810033a7f60f17ba555813f1b529d71f7 100644 --- a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h +++ b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h @@ -36,10 +36,10 @@ class PixelBuffer; WEBCORE_EXPORT uint8_t verifyImageBufferIsBigEnough(const void* buffer, size_t bufferSize); -CFStringRef jpegUTI(); +WEBCORE_EXPORT CFStringRef jpegUTI(); RetainPtr utiFromImageBufferMIMEType(const String&); -Vector data(CGImageRef, CFStringRef destinationUTI, std::optional quality); +WEBCORE_EXPORT Vector data(CGImageRef, CFStringRef destinationUTI, std::optional quality); Vector data(const PixelBuffer&, const String& mimeType, std::optional quality); String dataURL(CGImageRef, CFStringRef destinationUTI, const String& mimeType, std::optional quality); diff --git a/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp b/Source/WebCore/platform/graphics/opengl/GraphicsContextGLOpenGLBase.cpp index 2e46b61536c835dfcacf9f79e10e6d59ae7a3836..fa0c72d80d83c58a8407e78988de010fe97d7c38 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(WEBGL) && USE(OPENGL) +#if !PLATFORM(WIN) && ENABLE(WEBGL) && USE(OPENGL) #include "ExtensionsGLOpenGL.h" #include "IntRect.h" diff --git a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp index 774a52a28693bc51dde10a0875ea379afb06fd3c..cd714a7298fe4f5d2c9b580697a5c4cd22d25870 100644 --- a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp +++ b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp @@ -172,6 +172,33 @@ static Vector stringIndicesFromClusters(const Vector& clusters, return stringIndices; } +static int compactScriptItemsIfNeeded(const UChar* cp, unsigned stringLength, Vector& items, int numItems, const Font* font) +{ + // https://bugs.webkit.org/show_bug.cgi?id=201214 + // Uniscribe is overly aggressive in separating the runs. It'll split "3d_rotation" into "3", "d", "_" and "rotation" and we + // will ScriptShape them separately. As a result, a ligature for "3d_rotation" in the Material icon set + // (https://www.materialui.co/icon/3d-rotation) will not be used. A quick and dirty hack is to glue them back here, only making + // this apply to the readable characters, digits and _. + + if (!numItems) + return numItems; + + if (font->platformData().isSystemFont() || font->platformData().hasVariations()) + return numItems; + + bool allGoodCharacters = true; + for (unsigned i = 0; allGoodCharacters && i < stringLength; ++i) { + const UChar c = cp[i]; + allGoodCharacters = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_'; + } + if (!allGoodCharacters) + return numItems; + + // Consume entire string into a single run. |items| is at least numItems + 1 long. + items[1] = items[numItems]; + return 1; +} + void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, unsigned stringLength, unsigned stringLocation, const Font* font) { if (!font) { @@ -201,6 +228,8 @@ void ComplexTextController::collectComplexTextRunsForCharacters(const UChar* cp, } items.resize(numItems + 1); + numItems = compactScriptItemsIfNeeded(cp, stringLength, items, numItems, font); + for (int i = 0; i < numItems; i++) { // Determine the string for this item. const UChar* str = cp + items[i].iCharPos; diff --git a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp index 0516e70973e0078de6ad0216375d34dd9ef51a8d..ffd9a02deb5518e0c8c77b156815c11eb4b16829 100644 --- a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp @@ -37,8 +37,10 @@ #include "WindowsKeyboardCodes.h" #include #include +#include #include #include +#include namespace WebCore { @@ -1294,6 +1296,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/gtk/PlatformScreenGtk.cpp b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp index 7a3b4723f48c179864b2dd6d5b1ed8d27492358e..a741751acad01f11d7da0f6896eeb0023b9a3fcc 100644 --- a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp +++ b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp @@ -224,7 +224,7 @@ bool screenSupportsExtendedColor(Widget*) } #if ENABLE(TOUCH_EVENTS) -bool screenHasTouchDevice() +bool platformScreenHasTouchDevice() { auto* display = gdk_display_get_default(); if (!display) @@ -234,7 +234,7 @@ bool screenHasTouchDevice() return seat ? gdk_seat_get_capabilities(seat) & GDK_SEAT_CAPABILITY_TOUCH : true; } -bool screenIsTouchPrimaryInputDevice() +bool platformScreenIsTouchPrimaryInputDevice() { auto* display = gdk_display_get_default(); if (!display) diff --git a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp index f4c905dc15a2183629b0e9817dc24135e0ff7fe5..e9925e7a9fc3cbf5fefffaf38f409fbeec189cb0 100644 --- a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp +++ b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp @@ -32,6 +32,10 @@ #include "PasteboardStrategy.h" #include "PlatformStrategies.h" +#if ENABLE(DRAG_SUPPORT) +#include "DragData.h" +#endif + namespace WebCore { std::unique_ptr Pasteboard::createForCopyAndPaste(std::unique_ptr&& context) @@ -73,6 +77,16 @@ String Pasteboard::readOrigin() String Pasteboard::readString(const String& type) { + if (m_selectionData) { + if (type == "text/plain") + return m_selectionData->text();; + if (type == "text/html") + return m_selectionData->markup(); + if (type == "Files" || type == "text/uri-list") + return m_selectionData->uriList(); + return { }; + } + return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(0, type, name(), context()); } @@ -84,6 +98,15 @@ String Pasteboard::readStringInCustomData(const String&) void Pasteboard::writeString(const String& type, const String& text) { + if (m_selectionData) { + if (type == "Files" || type == "text/uri-list") + m_selectionData->setURIList(text); + else if (type == "text/html") + m_selectionData->setMarkup(text); + else if (type == "text/plain") + m_selectionData->setText(text); + return; + } platformStrategies()->pasteboardStrategy()->writeToPasteboard(type, text); } @@ -111,7 +134,12 @@ void Pasteboard::read(PasteboardFileReader&, std::optional) void Pasteboard::write(const PasteboardURL& url) { - platformStrategies()->pasteboardStrategy()->writeToPasteboard("text/plain;charset=utf-8", url.url.string()); + if (m_selectionData) { + m_selectionData->clearAll(); + m_selectionData->setURL(url.url, url.title); + } else { + platformStrategies()->pasteboardStrategy()->writeToPasteboard("text/plain;charset=utf-8", url.url.string()); + } } void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) @@ -119,13 +147,28 @@ void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&) notImplemented(); } -void Pasteboard::write(const PasteboardImage&) +void Pasteboard::write(const PasteboardImage& pasteboardImage) { + if (m_selectionData) { + m_selectionData->clearAll(); + if (!pasteboardImage.url.url.isEmpty()) { + m_selectionData->setURL(pasteboardImage.url.url, pasteboardImage.url.title); + m_selectionData->setMarkup(pasteboardImage.url.markup); + } + m_selectionData->setImage(pasteboardImage.image.get()); + } } void Pasteboard::write(const PasteboardWebContent& content) { - platformStrategies()->pasteboardStrategy()->writeToPasteboard(content); + if (m_selectionData) { + m_selectionData->clearAll(); + m_selectionData->setText(content.text); + m_selectionData->setMarkup(content.markup); + m_selectionData->setCanSmartReplace(content.canSmartCopyOrDelete); + } else { + platformStrategies()->pasteboardStrategy()->writeToPasteboard(content); + } } Pasteboard::FileContentState Pasteboard::fileContentState() @@ -156,6 +199,35 @@ void Pasteboard::write(const Color&) { } +#if ENABLE(DRAG_SUPPORT) + +Pasteboard::Pasteboard(std::unique_ptr&& context, SelectionData&& selectionData) + : m_context(WTFMove(context)) + , m_selectionData(WTFMove(selectionData)) +{ +} + +Pasteboard::Pasteboard(std::unique_ptr&& context, SelectionData& selectionData) + : m_context(WTFMove(context)) + , m_selectionData(selectionData) +{ +} + +std::unique_ptr Pasteboard::createForDragAndDrop(std::unique_ptr&& context) +{ + return makeUnique(WTFMove(context), SelectionData()); +} + +std::unique_ptr Pasteboard::create(const DragData& dragData) +{ + RELEASE_ASSERT(dragData.platformData()); + return makeUnique(dragData.createPasteboardContext(), *dragData.platformData()); +} +void Pasteboard::setDragImage(DragImage, const IntPoint&) +{ +} +#endif + } // namespace WebCore #endif // USE(LIBWPE) diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp index 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/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp index 39cb560e54bf9efd2dad6e1fb60dd0f609daf6bf..91c132460d4b466f61a8c579f70329fdde3b130f 100644 --- a/Source/WebCore/platform/network/HTTPHeaderMap.cpp +++ b/Source/WebCore/platform/network/HTTPHeaderMap.cpp @@ -205,8 +205,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value) auto index = m_commonHeaders.findMatching([&](auto& header) { return header.key == name; }); + // Align with Chromium and Firefox, but just for SetCookies where it is critical: + // https://bit.ly/2HCa0iq + String separator = name == HTTPHeaderName::SetCookie ? "\n " : ", "; if (index != notFound) - m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, ", ", value); + m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, separator, value); else m_commonHeaders.append(CommonHeader { name, value }); } diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h index f5c0970b031a2e9e2a176af81e6cf510ace4cb4a..713ade70c5bec341613bb0b5997c5c64382f41e3 100644 --- a/Source/WebCore/platform/network/ResourceResponseBase.h +++ b/Source/WebCore/platform/network/ResourceResponseBase.h @@ -217,6 +217,8 @@ public: WEBCORE_EXPORT static ResourceResponse dataURLResponse(const URL&, const DataURLDecoder::Result&); + HTTPHeaderMap m_httpRequestHeaderFields; + protected: enum InitLevel { Uninitialized, @@ -299,6 +301,7 @@ void ResourceResponseBase::encode(Encoder& encoder) const encoder << m_httpStatusText; encoder << m_httpVersion; encoder << m_httpHeaderFields; + encoder << m_httpRequestHeaderFields; // We don't want to put the networkLoadMetrics info // into the disk cache, because we will never use the old info. @@ -371,6 +374,12 @@ bool ResourceResponseBase::decode(Decoder& decoder, ResourceResponseBase& respon return false; response.m_httpHeaderFields = WTFMove(*httpHeaderFields); + std::optional httpRequestHeaderFields; + decoder >> httpRequestHeaderFields; + if (!httpRequestHeaderFields) + return false; + response.m_httpRequestHeaderFields = WTFMove(*httpRequestHeaderFields); + // The networkLoadMetrics info is only send over IPC and not stored in disk cache. if constexpr (Decoder::isIPCDecoder) { std::optional> networkLoadMetrics; diff --git a/Source/WebCore/platform/network/cf/SocketStreamHandleImpl.h b/Source/WebCore/platform/network/cf/SocketStreamHandleImpl.h index 7330aa933924791f1292c0847921e3b367493d96..a5238a748d1fb4bfa5b3e0882fe62f4029f84e5f 100644 --- a/Source/WebCore/platform/network/cf/SocketStreamHandleImpl.h +++ b/Source/WebCore/platform/network/cf/SocketStreamHandleImpl.h @@ -47,7 +47,7 @@ class SocketStreamHandleClient; class SocketStreamHandleImpl : public SocketStreamHandle { public: - static Ref create(const URL& url, SocketStreamHandleClient& client, PAL::SessionID sessionID, const String& credentialPartition, SourceApplicationAuditToken&& auditData, const StorageSessionProvider* provider) { return adoptRef(*new SocketStreamHandleImpl(url, client, sessionID, credentialPartition, WTFMove(auditData), provider)); } + static Ref create(const URL& url, bool ignoreCertificateErrors, SocketStreamHandleClient& client, PAL::SessionID sessionID, const String& credentialPartition, SourceApplicationAuditToken&& auditData, const StorageSessionProvider* provider) { return adoptRef(*new SocketStreamHandleImpl(url, ignoreCertificateErrors, client, sessionID, credentialPartition, WTFMove(auditData), provider)); } virtual ~SocketStreamHandleImpl(); @@ -61,7 +61,7 @@ private: std::optional platformSendInternal(const uint8_t*, size_t); bool sendPendingData(); - WEBCORE_EXPORT SocketStreamHandleImpl(const URL&, SocketStreamHandleClient&, PAL::SessionID, const String& credentialPartition, SourceApplicationAuditToken&&, const StorageSessionProvider*); + WEBCORE_EXPORT SocketStreamHandleImpl(const URL&, bool ignoreCertificateErrors, SocketStreamHandleClient&, PAL::SessionID, const String& credentialPartition, SourceApplicationAuditToken&&, const StorageSessionProvider*); void createStreams(); void scheduleStreams(); void chooseProxy(); @@ -106,6 +106,7 @@ private: String m_credentialPartition; SourceApplicationAuditToken m_auditData; RefPtr m_storageSessionProvider; + bool m_ignoreCertificateErrors { false }; StreamBuffer m_buffer; static const unsigned maxBufferSize = 100 * 1024 * 1024; diff --git a/Source/WebCore/platform/network/cf/SocketStreamHandleImplCFNet.cpp b/Source/WebCore/platform/network/cf/SocketStreamHandleImplCFNet.cpp index 55b9f1ed4a0d325a6b16a114389f39c7ded36ca6..2279824540b85405ec3ccac709026a381063bac8 100644 --- a/Source/WebCore/platform/network/cf/SocketStreamHandleImplCFNet.cpp +++ b/Source/WebCore/platform/network/cf/SocketStreamHandleImplCFNet.cpp @@ -96,7 +96,7 @@ static inline auto callbacksRunLoopMode() #endif } -SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandleClient& client, PAL::SessionID sessionID, const String& credentialPartition, SourceApplicationAuditToken&& auditData, const StorageSessionProvider* provider) +SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, bool ignoreCertificateErrors, SocketStreamHandleClient& client, PAL::SessionID sessionID, const String& credentialPartition, SourceApplicationAuditToken&& auditData, const StorageSessionProvider* provider) : SocketStreamHandle(url, client) , m_connectingSubstate(New) , m_connectionType(Unknown) @@ -104,6 +104,7 @@ SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandl , m_credentialPartition(credentialPartition) , m_auditData(WTFMove(auditData)) , m_storageSessionProvider(provider) + , m_ignoreCertificateErrors(ignoreCertificateErrors) { LOG(Network, "SocketStreamHandle %p new client %p", this, &m_client); @@ -360,7 +361,7 @@ void SocketStreamHandleImpl::createStreams() } if (shouldUseSSL()) { - CFBooleanRef validateCertificateChain = DeprecatedGlobalSettings::allowsAnySSLCertificate() ? kCFBooleanFalse : kCFBooleanTrue; + CFBooleanRef validateCertificateChain = m_ignoreCertificateErrors || DeprecatedGlobalSettings::allowsAnySSLCertificate() ? kCFBooleanFalse : kCFBooleanTrue; const void* keys[] = { kCFStreamSSLPeerName, kCFStreamSSLLevel, diff --git a/Source/WebCore/platform/network/curl/CookieJarDB.h b/Source/WebCore/platform/network/curl/CookieJarDB.h index c4eb67d6f7c334076b32b798dcea40b570681e6f..ce86ab28225aa466350671441294f2ace8851bbd 100644 --- a/Source/WebCore/platform/network/curl/CookieJarDB.h +++ b/Source/WebCore/platform/network/curl/CookieJarDB.h @@ -72,7 +72,7 @@ public: WEBCORE_EXPORT ~CookieJarDB(); private: - CookieAcceptPolicy m_acceptPolicy { CookieAcceptPolicy::Always }; + CookieAcceptPolicy m_acceptPolicy { CookieAcceptPolicy::OnlyFromMainDocumentDomain }; String m_databasePath; bool m_detectedDatabaseCorruption { false }; diff --git a/Source/WebCore/platform/network/curl/CurlStream.cpp b/Source/WebCore/platform/network/curl/CurlStream.cpp index 29190c7898913eb4081a5bf82eaba3201d0446f5..92be0ba24fefb403587136dddb8cfe42cfac892b 100644 --- a/Source/WebCore/platform/network/curl/CurlStream.cpp +++ b/Source/WebCore/platform/network/curl/CurlStream.cpp @@ -33,7 +33,7 @@ namespace WebCore { -CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, URL&& url) +CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, bool ignoreCertificateErrors, URL&& url) : m_scheduler(scheduler) , m_streamID(streamID) { @@ -45,6 +45,9 @@ CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, UR m_curlHandle->setUrl(WTFMove(url)); m_curlHandle->enableConnectionOnly(); + if (ignoreCertificateErrors) + m_curlHandle->disableServerTrustEvaluation(); + auto errorCode = m_curlHandle->perform(); if (errorCode != CURLE_OK) { diff --git a/Source/WebCore/platform/network/curl/CurlStream.h b/Source/WebCore/platform/network/curl/CurlStream.h index e64629fc22a2097a2af0b0c0139b23d7908cf3dc..920a8c12c6c69afc5aec6de12e9f5fba312237a0 100644 --- a/Source/WebCore/platform/network/curl/CurlStream.h +++ b/Source/WebCore/platform/network/curl/CurlStream.h @@ -50,12 +50,12 @@ public: virtual void didFail(CurlStreamID, CURLcode) = 0; }; - static std::unique_ptr create(CurlStreamScheduler& scheduler, CurlStreamID streamID, URL&& url) + static std::unique_ptr create(CurlStreamScheduler& scheduler, CurlStreamID streamID, bool ignoreCertificateErrors, URL&& url) { - return WTF::makeUnique(scheduler, streamID, WTFMove(url)); + return WTF::makeUnique(scheduler, streamID, ignoreCertificateErrors, WTFMove(url)); } - CurlStream(CurlStreamScheduler&, CurlStreamID, URL&&); + CurlStream(CurlStreamScheduler&, CurlStreamID, bool ignoreCertificateErrors, URL&&); virtual ~CurlStream(); void send(UniqueArray&&, size_t); diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp b/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp index b4a9abd45307e14b1b0080c5fd8490acaf7bb599..d750af7d2e6e25b9df9fada78ae1fe3767066fbb 100644 --- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp +++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp @@ -40,7 +40,7 @@ CurlStreamScheduler::~CurlStreamScheduler() ASSERT(isMainThread()); } -CurlStreamID CurlStreamScheduler::createStream(const URL& url, CurlStream::Client& client) +CurlStreamID CurlStreamScheduler::createStream(const URL& url, bool ignoreCertificateErrors, CurlStream::Client& client) { ASSERT(isMainThread()); @@ -51,8 +51,8 @@ CurlStreamID CurlStreamScheduler::createStream(const URL& url, CurlStream::Clien auto streamID = m_currentStreamID; m_clientList.add(streamID, &client); - callOnWorkerThread([this, streamID, url = url.isolatedCopy()]() mutable { - m_streamList.add(streamID, CurlStream::create(*this, streamID, WTFMove(url))); + callOnWorkerThread([this, streamID, ignoreCertificateErrors, url = url.isolatedCopy()]() mutable { + m_streamList.add(streamID, CurlStream::create(*this, streamID, ignoreCertificateErrors, WTFMove(url))); }); return streamID; diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h index 7d881206c9689f433227969c9b7f9ff268bdaaed..2e8118f11f87fa5f32adcedc165aec8220b36d58 100644 --- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h +++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h @@ -38,7 +38,7 @@ public: CurlStreamScheduler(); virtual ~CurlStreamScheduler(); - CurlStreamID createStream(const URL&, CurlStream::Client&); + CurlStreamID createStream(const URL&, bool ignoreCertificateErrors, CurlStream::Client&); void destroyStream(CurlStreamID); void send(CurlStreamID, UniqueArray&&, size_t); diff --git a/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h b/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h index b804fde0973bbfb28331cf7c3a1f20b043e74fe8..af3005261593b5fa91484c98c43d021227716231 100644 --- a/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h +++ b/Source/WebCore/platform/network/curl/SocketStreamHandleImpl.h @@ -44,7 +44,7 @@ class StorageSessionProvider; class SocketStreamHandleImpl : public SocketStreamHandle, public CurlStream::Client { public: - static Ref create(const URL& url, SocketStreamHandleClient& client, PAL::SessionID, const String&, SourceApplicationAuditToken&&, const StorageSessionProvider* provider) { return adoptRef(*new SocketStreamHandleImpl(url, client, provider)); } + static Ref create(const URL& url, bool ignoreCertificateErrors, SocketStreamHandleClient& client, PAL::SessionID, const String&, SourceApplicationAuditToken&&, const StorageSessionProvider* provider) { return adoptRef(*new SocketStreamHandleImpl(url, ignoreCertificateErrors, client, provider)); } virtual ~SocketStreamHandleImpl(); @@ -53,7 +53,7 @@ public: WEBCORE_EXPORT void platformClose() final; private: - WEBCORE_EXPORT SocketStreamHandleImpl(const URL&, SocketStreamHandleClient&, const StorageSessionProvider*); + WEBCORE_EXPORT SocketStreamHandleImpl(const URL&, bool ignoreCertificateErrors, SocketStreamHandleClient&, const StorageSessionProvider*); size_t bufferedAmount() final; std::optional platformSendInternal(const uint8_t*, size_t); diff --git a/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp b/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp index 4b9491c11543f2b60f12d36e9e6a0cbaae34a72e..e907fc00a2a426384ce1e471847911c9ba1739af 100644 --- a/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp +++ b/Source/WebCore/platform/network/curl/SocketStreamHandleImplCurl.cpp @@ -43,7 +43,7 @@ namespace WebCore { -SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandleClient& client, const StorageSessionProvider* provider) +SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, bool ignoreCertificateErrors, SocketStreamHandleClient& client, const StorageSessionProvider* provider) : SocketStreamHandle(url, client) , m_storageSessionProvider(provider) , m_scheduler(CurlContext::singleton().streamScheduler()) @@ -52,7 +52,7 @@ SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandl if (m_url.protocolIs("wss") && DeprecatedGlobalSettings::allowsAnySSLCertificate()) CurlContext::singleton().sslHandle().setIgnoreSSLErrors(true); - m_streamID = m_scheduler.createStream(m_url, *this); + m_streamID = m_scheduler.createStream(m_url, ignoreCertificateErrors, *this); } SocketStreamHandleImpl::~SocketStreamHandleImpl() diff --git a/Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h b/Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h index 88df3748e980a22e71bd835864caf24b6b7ea50b..f83c7f2535fd1abae7b1cccca946254b9407f86f 100644 --- a/Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h +++ b/Source/WebCore/platform/network/soup/SocketStreamHandleImpl.h @@ -47,7 +47,7 @@ class StorageSessionProvider; class SocketStreamHandleImpl final : public SocketStreamHandle { public: - static Ref create(const URL&, SocketStreamHandleClient&, PAL::SessionID, const String&, SourceApplicationAuditToken&&, const StorageSessionProvider*) + static Ref create(const URL&, bool, SocketStreamHandleClient&, PAL::SessionID, const String&, SourceApplicationAuditToken&&, const StorageSessionProvider*) { RELEASE_ASSERT_NOT_REACHED(); } diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp index 3e97e804e115e0e37814ddf670e9e3ba4b3bbc73..86a1b22913c9ed6563f0d56c7ebd74c16dc829b9 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp @@ -38,6 +38,7 @@ #include #include #include +#include "Pasteboard.h" #if USE(CF) #include @@ -724,7 +725,10 @@ template void getStringData(IDataObject* data, FORMATETC* format, Ve STGMEDIUM store; if (FAILED(data->GetData(format, &store))) return; - dataStrings.append(String(static_cast(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T))); + // The string here should be null terminated, but it could come from another app so lets lock it + // to the size to prevent an overflow. + String rawString = String(static_cast(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T)); + dataStrings.append(String::fromUTF8(rawString.utf8().data())); GlobalUnlock(store.hGlobal); ReleaseStgMedium(&store); } diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.h b/Source/WebCore/platform/win/ClipboardUtilitiesWin.h index c50799b63e05adbe32bae3535d786c7d268f980f..9cf1cc7ec4eaae22947f80ba272dfae272167bd6 100644 --- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.h +++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.h @@ -34,6 +34,7 @@ namespace WebCore { class Document; class DocumentFragment; +class Pasteboard; HGLOBAL createGlobalData(const String&); HGLOBAL createGlobalData(const Vector&); diff --git a/Source/WebCore/platform/win/DragDataWin.cpp b/Source/WebCore/platform/win/DragDataWin.cpp index 579a112579af39fc12ef024979d81fc55af36c2b..82c566c9d2ced02a92902a90e7ff97c142fa1903 100644 --- a/Source/WebCore/platform/win/DragDataWin.cpp +++ b/Source/WebCore/platform/win/DragDataWin.cpp @@ -48,6 +48,7 @@ DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, cons , m_applicationFlags(flags) , m_pageID(pageID) , m_dragDataMap(data) + , m_dragDestinationActionMask(anyDragDestinationAction()) { } diff --git a/Source/WebCore/platform/win/KeyEventWin.cpp b/Source/WebCore/platform/win/KeyEventWin.cpp index aae6c99dd052985a43718846b68536454050c234..7e2e5d0c1de90f1454f7fdb71a40ab71228dcbe9 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/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp index b94ee27baae83c0285533fc1c6abb4229816eda0..a242d40c5fc2fccdd0273f58287a3fcd85cbd01d 100644 --- a/Source/WebCore/platform/win/PasteboardWin.cpp +++ b/Source/WebCore/platform/win/PasteboardWin.cpp @@ -1134,7 +1134,21 @@ void Pasteboard::writeCustomData(const Vector& data) } clear(); + if (m_dataObject) { + const auto& customData = data.first(); + customData.forEachPlatformString([&](auto& type, auto& string) { + writeString(type, string); + }); + if (customData.hasSameOriginCustomData() || !customData.origin().isEmpty()) { + customData.forEachCustomString([&](auto& type, auto& string) { + writeString(type, string); + }); + } + return; + } + + // this is the real real clipboard. Prbaobly need to be doing drag data stuff. if (::OpenClipboard(m_owner)) { const auto& customData = data.first(); customData.forEachPlatformStringOrBuffer([](auto& type, auto& stringOrBuffer) { @@ -1173,4 +1187,25 @@ void Pasteboard::write(const Color&) { } +DragDataMap Pasteboard::createDragDataMap() { + DragDataMap dragDataMap; + auto dragObject = dataObject(); + if (!dragObject) + return dragDataMap; + // Enumerate clipboard content and load it in the map. + COMPtr itr; + + if (FAILED(dragObject->EnumFormatEtc(DATADIR_GET, &itr)) || !itr) + return dragDataMap; + + FORMATETC dataFormat; + while (itr->Next(1, &dataFormat, 0) == S_OK) { + Vector dataStrings; + getClipboardData(dragObject.get(), &dataFormat, dataStrings); + if (!dataStrings.isEmpty()) + dragDataMap.set(dataFormat.cfFormat, dataStrings); + } + return dragDataMap; +} + } // namespace WebCore diff --git a/Source/WebCore/platform/wpe/DragDataWPE.cpp b/Source/WebCore/platform/wpe/DragDataWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..07fb260a5203167fdf94a552949394bb73ca8c61 --- /dev/null +++ b/Source/WebCore/platform/wpe/DragDataWPE.cpp @@ -0,0 +1,87 @@ +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DragData.h" +#include "SelectionData.h" + +namespace WebCore { + +bool DragData::canSmartReplace() const +{ + return false; +} + +bool DragData::containsColor() const +{ + return false; +} + +bool DragData::containsFiles() const +{ + return m_platformDragData->hasFilenames(); +} + +unsigned DragData::numberOfFiles() const +{ + return m_platformDragData->filenames().size(); +} + +Vector DragData::asFilenames() const +{ + return m_platformDragData->filenames(); +} + +bool DragData::containsPlainText() const +{ + return m_platformDragData->hasText(); +} + +String DragData::asPlainText() const +{ + return m_platformDragData->text(); +} + +Color DragData::asColor() const +{ + return Color(); +} + +bool DragData::containsCompatibleContent(DraggingPurpose) const +{ + return containsPlainText() || containsURL() || containsColor() || containsFiles(); +} + +bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const +{ + return !asURL(filenamePolicy).isEmpty(); +} + +String DragData::asURL(FilenameConversionPolicy filenamePolicy, String* title) const +{ + if (!m_platformDragData->hasURL()) + return String(); + if (filenamePolicy != ConvertFilenames) { + if (m_platformDragData->url().isLocalFile()) + return { }; + } + + if (title) + *title = m_platformDragData->urlLabel(); + return m_platformDragData->url().string(); +} + +} diff --git a/Source/WebCore/platform/wpe/DragImageWPE.cpp b/Source/WebCore/platform/wpe/DragImageWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c684ea504c0c93895ab75a880b4d2febc946813 --- /dev/null +++ b/Source/WebCore/platform/wpe/DragImageWPE.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010,2017 Igalia S.L. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "DragImage.h" +#include "NotImplemented.h" + +#include "Image.h" + +namespace WebCore { + +IntSize dragImageSize(DragImageRef) +{ + notImplemented(); + return { 0, 0 }; +} + +void deleteDragImage(DragImageRef) +{ + notImplemented(); +} + +DragImageRef scaleDragImage(DragImageRef, FloatSize) +{ + notImplemented(); + return nullptr; +} + +DragImageRef dissolveDragImageToFraction(DragImageRef image, float) +{ + notImplemented(); + return image; +} + +DragImageRef createDragImageFromImage(Image* image, ImageOrientation) +{ + return image->nativeImageForCurrentFrame()->platformImage(); +} + + +DragImageRef createDragImageIconForCachedImageFilename(const String&) +{ + notImplemented(); + return nullptr; +} + +DragImageRef createDragImageForLink(Element&, URL&, const String&, TextIndicatorData&, FontRenderingMode, float) +{ + notImplemented(); + return nullptr; +} + +} diff --git a/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp b/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp index bbdd1ce76241d933ada9c43fabae4912cbfa64e1..e6ae01a77350c519b203f6ed2910f63871b9b829 100644 --- a/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp +++ b/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp @@ -93,12 +93,12 @@ bool screenSupportsExtendedColor(Widget*) } #if ENABLE(TOUCH_EVENTS) -bool screenHasTouchDevice() +bool platformScreenHasTouchDevice() { return true; } -bool screenIsTouchPrimaryInputDevice() +bool platformScreenIsTouchPrimaryInputDevice() { return true; } diff --git a/Source/WebCore/platform/wpe/SelectionData.cpp b/Source/WebCore/platform/wpe/SelectionData.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f181fdfe507ad5b7a47b5c58295cf4f2725e7d8 --- /dev/null +++ b/Source/WebCore/platform/wpe/SelectionData.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2009, Martin Robinson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "SelectionData.h" + +#include +#include +#include + +namespace WebCore { + +static void replaceNonBreakingSpaceWithSpace(String& str) +{ + static const UChar NonBreakingSpaceCharacter = 0xA0; + static const UChar SpaceCharacter = ' '; + str.replace(NonBreakingSpaceCharacter, SpaceCharacter); +} + +void SelectionData::setText(const String& newText) +{ + m_text = newText; + replaceNonBreakingSpaceWithSpace(m_text); +} + +void SelectionData::setURIList(const String& uriListString) +{ + m_uriList = uriListString; + + // This code is originally from: platform/chromium/ChromiumDataObject.cpp. + // FIXME: We should make this code cross-platform eventually. + + // Line separator is \r\n per RFC 2483 - however, for compatibility + // reasons we also allow just \n here. + + // Process the input and copy the first valid URL into the url member. + // In case no URLs can be found, subsequent calls to getData("URL") + // will get an empty string. This is in line with the HTML5 spec (see + // "The DragEvent and DataTransfer interfaces"). Also extract all filenames + // from the URI list. + bool setURL = hasURL(); + for (auto& line : uriListString.split('\n')) { + line = line.stripWhiteSpace(); + if (line.isEmpty()) + continue; + if (line[0] == '#') + continue; + + URL url = URL(URL(), line); + if (url.isValid()) { + if (!setURL) { + m_url = url; + setURL = true; + } + + GUniqueOutPtr error; + GUniquePtr filename(g_filename_from_uri(line.utf8().data(), 0, &error.outPtr())); + if (!error && filename) + m_filenames.append(String::fromUTF8(filename.get())); + } + } +} + +void SelectionData::setURL(const URL& url, const String& label) +{ + m_url = url; + if (m_uriList.isEmpty()) + m_uriList = url.string(); + + if (!hasText()) + setText(url.string()); + + if (hasMarkup()) + return; + + String actualLabel(label); + if (actualLabel.isEmpty()) + actualLabel = url.string(); + + StringBuilder markup; + markup.append(""); + GUniquePtr escaped(g_markup_escape_text(actualLabel.utf8().data(), -1)); + markup.append(String::fromUTF8(escaped.get())); + markup.append(""); + setMarkup(markup.toString()); +} + +const String& SelectionData::urlLabel() const +{ + if (hasText()) + return text(); + + if (hasURL()) + return url().string(); + + return emptyString(); +} + +void SelectionData::clearAllExceptFilenames() +{ + clearText(); + clearMarkup(); + clearURIList(); + clearURL(); + clearImage(); + clearCustomData(); + + m_canSmartReplace = false; +} + +void SelectionData::clearAll() +{ + clearAllExceptFilenames(); + m_filenames.clear(); +} + +} // namespace WebCore diff --git a/Source/WebCore/platform/wpe/SelectionData.h b/Source/WebCore/platform/wpe/SelectionData.h new file mode 100644 index 0000000000000000000000000000000000000000..cf2b51f6f02837a1106f4d999f2f130e2580986a --- /dev/null +++ b/Source/WebCore/platform/wpe/SelectionData.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009, Martin Robinson + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#include "Image.h" +#include "SharedBuffer.h" +#include +#include +#include + +namespace WebCore { + +class SelectionData { + WTF_MAKE_FAST_ALLOCATED; +public: + void setText(const String&); + const String& text() const { return m_text; } + bool hasText() const { return !m_text.isEmpty(); } + void clearText() { m_text = emptyString(); } + + void setMarkup(const String& newMarkup) { m_markup = newMarkup; } + const String& markup() const { return m_markup; } + bool hasMarkup() const { return !m_markup.isEmpty(); } + void clearMarkup() { m_markup = emptyString(); } + + void setURL(const URL&, const String&); + const URL& url() const { return m_url; } + const String& urlLabel() const; + bool hasURL() const { return !m_url.isEmpty() && m_url.isValid(); } + void clearURL() { m_url = URL(); } + + void setURIList(const String&); + const String& uriList() const { return m_uriList; } + const Vector& filenames() const { return m_filenames; } + bool hasURIList() const { return !m_uriList.isEmpty(); } + bool hasFilenames() const { return !m_filenames.isEmpty(); } + void clearURIList() { m_uriList = emptyString(); } + + void setImage(Image* newImage) { m_image = newImage; } + Image* image() const { return m_image.get(); } + bool hasImage() const { return m_image; } + void clearImage() { m_image = nullptr; } + + void setCanSmartReplace(bool canSmartReplace) { m_canSmartReplace = canSmartReplace; } + bool canSmartReplace() const { return m_canSmartReplace; } + + void setCustomData(Ref&& buffer) { m_customData = WTFMove(buffer); } + SharedBuffer* customData() const { return m_customData.get(); } + bool hasCustomData() const { return !!m_customData; } + void clearCustomData() { m_customData = nullptr; } + + void clearAll(); + void clearAllExceptFilenames(); + +private: + String m_text; + String m_markup; + URL m_url; + String m_uriList; + Vector m_filenames; + RefPtr m_image; + bool m_canSmartReplace { false }; + RefPtr m_customData; +}; + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 161c262f05e26e89808f90d90ff210d1f6199063..59d90ad0dd32b7a0948c3f6ed15c9ce16a9ae655 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -2560,7 +2560,7 @@ LayoutRect RenderLayer::getRectToExpose(const LayoutRect& visibleRect, const Lay ScrollAlignment::Behavior scrollX; LayoutRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height()); LayoutUnit intersectWidth = intersection(visibleRect, exposeRectX).width(); - if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL) + if (intersectWidth == exposeRect.width() || (intersectWidth >= MIN_INTERSECT_FOR_REVEAL && !alignX.m_disableMinThreshold)) // If the rectangle is fully visible, use the specified visible behavior. // If the rectangle is partially visible, but over a certain threshold, // then treat it as fully visible to avoid unnecessary horizontal scrolling diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index 242aca3a06b91574a748b13ecefa80c6172b9c59..4dcd61750471013be4455b0270a8a21a7b489d47 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -207,13 +207,13 @@ void RenderTextControl::layoutExcludedChildren(bool relayoutChildren) } } -#if PLATFORM(IOS_FAMILY) bool RenderTextControl::canScroll() const { auto innerText = innerTextElement(); return innerText && innerText->renderer() && innerText->renderer()->hasOverflowClip(); } +#if PLATFORM(IOS_FAMILY) int RenderTextControl::innerLineHeight() const { auto innerText = innerTextElement(); diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h index 2e90534ffd8da83b7dc54d46fa7def16319bbb43..2493c00d58957751c65c37eb409fa8d675efd5ca 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -36,9 +36,9 @@ public: WEBCORE_EXPORT HTMLTextFormControlElement& textFormControlElement() const; -#if PLATFORM(IOS_FAMILY) bool canScroll() const; +#if PLATFORM(IOS_FAMILY) // Returns the line height of the inner renderer. int innerLineHeight() const override; #endif diff --git a/Source/WebCore/rendering/ScrollAlignment.h b/Source/WebCore/rendering/ScrollAlignment.h index 694008e0451edc5770142a0a6d9eed52b04ded80..ec93869f9486bdf7bd3bb56478c62469d2fa58b6 100644 --- a/Source/WebCore/rendering/ScrollAlignment.h +++ b/Source/WebCore/rendering/ScrollAlignment.h @@ -78,6 +78,7 @@ struct ScrollAlignment { Behavior m_rectVisible; Behavior m_rectHidden; Behavior m_rectPartial; + bool m_disableMinThreshold = false; }; WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, ScrollAlignment::Behavior); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp index 14fc0e0634d2d91505d6ff1eb78153ff15bbc891..5dacbd695125d26aa0acd36cb32e9e2a02721789 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp @@ -74,6 +74,11 @@ #include #include +#if PLATFORM(COCOA) +#include "NetworkDataTaskCocoa.h" +#include "NetworkSessionCocoa.h" +#endif + #if ENABLE(APPLE_PAY_REMOTE_UI) #include "WebPaymentCoordinatorProxyMessages.h" #endif @@ -903,6 +908,15 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID) #endif } +void NetworkConnectionToWebProcess::setCookieFromResponse(NetworkResourceLoadParameters&& parameters, const URL& mainDocumentURL, const String& setCookieValue) +{ + if (auto* session = networkSession()) { +#if PLATFORM(COCOA) + NetworkDataTaskCocoa::setCookieFromResponse(*static_cast(session), WTFMove(parameters), mainDocumentURL, setCookieValue); +#endif + } +} + #if ENABLE(RESOURCE_LOAD_STATISTICS) void NetworkConnectionToWebProcess::removeStorageAccessForFrame(FrameIdentifier frameID, PageIdentifier pageID) { diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h index 1a5444be7b47e5dc121d58f80baadba18d3ccc3c..8ae9c0ba78b0f9d5d27215a207ec7b320e50739e 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h @@ -283,6 +283,8 @@ private: void clearPageSpecificData(WebCore::PageIdentifier); + void setCookieFromResponse(NetworkResourceLoadParameters&&, const URL& mainDocumentURL, const String& setCookieValue); + #if ENABLE(RESOURCE_LOAD_STATISTICS) void removeStorageAccessForFrame(WebCore::FrameIdentifier, WebCore::PageIdentifier); diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in index 9b32896810619ba19dc5bf437b368a7ca7fa431b..a026b8ae7024f914e78f3f5137bc20314908de2e 100644 --- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in @@ -64,6 +64,8 @@ messages -> NetworkConnectionToWebProcess LegacyReceiver { ClearPageSpecificData(WebCore::PageIdentifier pageID); + SetCookieFromResponse(WebKit::NetworkResourceLoadParameters parameters, URL mainDocumentURL, String setCookieValue); + #if ENABLE(RESOURCE_LOAD_STATISTICS) RemoveStorageAccessForFrame(WebCore::FrameIdentifier frameID, WebCore::PageIdentifier pageID); LogUserInteraction(WebCore::RegistrableDomain domain) diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp index 0374f5c47a819d6a68f76207db2f03ad8c21f48d..9ebc13d8c0854192e5de2a8e1ab3fe51b1170a32 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" @@ -558,6 +557,59 @@ void NetworkProcess::destroySession(PAL::SessionID sessionID) server->close(); } +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); +} + +void NetworkProcess::getLocalStorageData(PAL::SessionID sessionID, CompletionHandler>>&&)>&& completionHandler) +{ + if (m_storageManagerSet->contains(sessionID)) { + m_storageManagerSet->getLocalStorageData(sessionID, WTFMove(completionHandler)); + return; + } + completionHandler(Vector>>()); +} + +void NetworkProcess::setLocalStorageData(PAL::SessionID sessionID, WebKit::StorageNamespaceIdentifier storageNamespaceID, Vector>>&& origins, CompletionHandler&& completionHandler) +{ + if (m_storageManagerSet->contains(sessionID)) { + m_storageManagerSet->setLocalStorageData(sessionID, storageNamespaceID, WTFMove(origins), WTFMove(completionHandler)); + return; + } + completionHandler("Cannot find storage manager for given session id"); +} + +void NetworkProcess::setIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignore) +{ + if (auto* networkSession = this->networkSession(sessionID)) + networkSession->setIgnoreCertificateErrors(ignore); +} + #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 08da56f19779bc74d8f4a28d58a167ec89a02e4e..75068b7bfd10a580c1e1c242f4cb60f9a36dab8d 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.h +++ b/Source/WebKit/NetworkProcess/NetworkProcess.h @@ -34,6 +34,7 @@ #include "NetworkContentRuleListManager.h" #include "RTCDataChannelRemoteManagerProxy.h" #include "SandboxExtension.h" +#include "StorageNamespaceIdentifier.h" #include "WebIDBServer.h" #include "WebPageProxyIdentifier.h" #include "WebResourceLoadStatisticsStore.h" @@ -79,6 +80,7 @@ class SessionID; namespace WebCore { class CertificateInfo; +struct Cookie; class CurlProxySettings; class ProtectionSpace; class StorageQuotaManager; @@ -209,6 +211,14 @@ public: void addWebsiteDataStore(WebsiteDataStoreParameters&&); + void getAllCookies(PAL::SessionID, CompletionHandler&&)>&&); + void setCookies(PAL::SessionID, Vector, CompletionHandler&&); + void deleteAllCookies(PAL::SessionID, CompletionHandler&&); + void setIgnoreCertificateErrors(PAL::SessionID, bool); + + void getLocalStorageData(PAL::SessionID sessionID, CompletionHandler>>&&)>&&); + void setLocalStorageData(PAL::SessionID sessionID, WebKit::StorageNamespaceIdentifier storageNamespaceID, Vector>>&& origins, CompletionHandler&&); + #if ENABLE(RESOURCE_LOAD_STATISTICS) void clearPrevalentResource(PAL::SessionID, const RegistrableDomain&, CompletionHandler&&); void clearUserInteraction(PAL::SessionID, const RegistrableDomain&, CompletionHandler&&); diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in index ae15ff0e12ca545178907d972a09ce6d2321a2d4..4ee782cbb1e4ce8228785f63fa1ca868276a2be9 100644 --- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in +++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in @@ -79,6 +79,14 @@ messages -> NetworkProcess LegacyReceiver { PreconnectTo(PAL::SessionID sessionID, WebKit::WebPageProxyIdentifier webPageProxyID, WebCore::PageIdentifier webPageID, URL url, String userAgent, enum:uint8_t WebCore::StoredCredentialsPolicy storedCredentialsPolicy, enum:bool std::optional isNavigatingToAppBoundDomain, enum:bool WebKit::LastNavigationWasAppBound lastNavigationWasAppBound); + GetAllCookies(PAL::SessionID sessionID) -> (Vector cookies) Async + SetCookies(PAL::SessionID sessionID, Vector cookies) -> (bool success) Async + DeleteAllCookies(PAL::SessionID sessionID) -> (bool success) Async + SetIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignoreTLSErrors) + + GetLocalStorageData(PAL::SessionID sessionID) -> (Vector>> origins) Async + SetLocalStorageData(PAL::SessionID sessionID, WebKit::StorageNamespaceIdentifier storageNamespaceID, Vector>> origins) -> (String error) 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/NetworkSession.h b/Source/WebKit/NetworkProcess/NetworkSession.h index 2bff182280c428e81b6c3684f5aaf928db897932..ba3b95d3863362e3926de2b8aa6b14e6fb668467 100644 --- a/Source/WebKit/NetworkProcess/NetworkSession.h +++ b/Source/WebKit/NetworkProcess/NetworkSession.h @@ -153,6 +153,9 @@ public: bool isStaleWhileRevalidateEnabled() const { return m_isStaleWhileRevalidateEnabled; } + void setIgnoreCertificateErrors(bool ignore) { m_ignoreCertificateErrors = ignore; } + bool ignoreCertificateErrors() { return m_ignoreCertificateErrors; } + #if ENABLE(SERVICE_WORKER) void addSoftUpdateLoader(std::unique_ptr&& loader) { m_softUpdateLoaders.add(WTFMove(loader)); } void removeSoftUpdateLoader(ServiceWorkerSoftUpdateLoader* loader) { m_softUpdateLoaders.remove(loader); } @@ -201,6 +204,7 @@ protected: #endif bool m_isStaleWhileRevalidateEnabled { false }; std::unique_ptr m_privateClickMeasurement; + bool m_ignoreCertificateErrors { false }; HashSet> m_keptAliveLoads; diff --git a/Source/WebKit/NetworkProcess/NetworkSocketStream.cpp b/Source/WebKit/NetworkProcess/NetworkSocketStream.cpp index 52eb5b08f16cba232149028cdaa8150ad04e4a9f..1f541ccfbe183ee152cea69108b80ffd3b1ff34f 100644 --- a/Source/WebKit/NetworkProcess/NetworkSocketStream.cpp +++ b/Source/WebKit/NetworkProcess/NetworkSocketStream.cpp @@ -43,7 +43,7 @@ Ref NetworkSocketStream::create(NetworkProcess& networkProc NetworkSocketStream::NetworkSocketStream(NetworkProcess& networkProcess, URL&& url, PAL::SessionID sessionID, const String& credentialPartition, WebSocketIdentifier identifier, IPC::Connection& connection, SourceApplicationAuditToken&& auditData) : m_identifier(identifier) , m_connection(connection) - , m_impl(SocketStreamHandleImpl::create(url, *this, sessionID, credentialPartition, WTFMove(auditData), NetworkStorageSessionProvider::create(networkProcess, sessionID).ptr())) + , m_impl(SocketStreamHandleImpl::create(url, networkProcess.networkSession(sessionID)->ignoreCertificateErrors(), *this, sessionID, credentialPartition, WTFMove(auditData), NetworkStorageSessionProvider::create(networkProcess, sessionID).ptr())) , m_delayFailTimer(*this, &NetworkSocketStream::sendDelayedFailMessage) { } diff --git a/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.cpp b/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.cpp index 60153bf7d6b07f58e0ea1595a14fc8c81353c149..5c0907b31551b576aeed1e9d26f4f5bcce055ec2 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.cpp +++ b/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.cpp @@ -29,6 +29,7 @@ #include "StorageArea.h" #include "StorageManager.h" #include +#include namespace WebKit { @@ -103,4 +104,11 @@ Vector LocalStorageNamespace::storageAreaIdentifiers() co return identifiers; } +void LocalStorageNamespace::forEachStorageArea(Function callback) const +{ + ASSERT(!RunLoop::isMain()); + for (auto& storageArea : m_storageAreaMap.values()) + callback(*storageArea); +} + } // namespace WebKit diff --git a/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.h b/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.h index adca9f4a255f58e2106dd6a4eceaddfff2451ac3..81f6c0bde82ea58ed5abc5e3653bb64a3377f531 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.h +++ b/Source/WebKit/NetworkProcess/WebStorage/LocalStorageNamespace.h @@ -28,7 +28,7 @@ #include "StorageAreaIdentifier.h" #include "StorageNamespaceIdentifier.h" #include -#include +#include #include #include #include @@ -59,6 +59,8 @@ public: Vector storageAreaIdentifiers() const; + void forEachStorageArea(Function) const; + private: StorageManager& m_storageManager; unsigned m_quotaInBytes { 0 }; diff --git a/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp b/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp index 83194b05fb4ee11777ddf10aed278f60c0b9982c..9c9357eb7466b82379f394aee3ff383784483ee1 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp +++ b/Source/WebKit/NetworkProcess/WebStorage/StorageArea.cpp @@ -111,6 +111,18 @@ void StorageArea::setItem(IPC::Connection::UniqueID sourceConnection, StorageAre dispatchEvents(sourceConnection, storageAreaImplID, key, oldValue, value, urlString); } +void StorageArea::setItems(const HashMap& items, bool& quotaException) { + ASSERT(!RunLoop::isMain()); + + for (const auto& item : items) { + String oldValue; + if (isEphemeral()) + m_sessionStorageMap->setItem(item.key, item.value, oldValue, quotaException); + else + ensureDatabase().setItem(item.key, item.value, oldValue, quotaException); + } +} + void StorageArea::removeItem(IPC::Connection::UniqueID sourceConnection, StorageAreaImplIdentifier storageAreaImplID, const String& key, const String& urlString) { ASSERT(!RunLoop::isMain()); diff --git a/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h b/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h index 9c715702dbe69b7f33c7c31be45779b32ea96a34..9174bb3f38b63d431fe2a8932d2646dea1c682ff 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h +++ b/Source/WebKit/NetworkProcess/WebStorage/StorageArea.h @@ -64,6 +64,7 @@ public: void removeItem(IPC::Connection::UniqueID sourceConnection, StorageAreaImplIdentifier, const String& key, const String& urlString); void clear(IPC::Connection::UniqueID sourceConnection, StorageAreaImplIdentifier, const String& urlString); + void setItems(const HashMap& items, bool& quotaException); HashMap items() const; void clear(); diff --git a/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp b/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp index 5bcca299ba415e39c02845997e5806b2846da93c..a7526a2adbd93ecb3e16a9b8b8f754152c79f2d4 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp +++ b/Source/WebKit/NetworkProcess/WebStorage/StorageManager.cpp @@ -147,6 +147,19 @@ HashSet StorageManager::getLocalStorageOriginsCrossThreadCop return origins; } +Vector>> StorageManager::getLocalStorageDataCrossThreadCopy() const +{ + ASSERT(!RunLoop::isMain()); + + Vector>> result; + for (const auto& localStorageNameSpace : m_localStorageNamespaces.values()) { + localStorageNameSpace->forEachStorageArea([&] (const StorageArea& area) { + result.append({ area.securityOrigin().isolatedCopy(), area.items() }); + }); + } + return result; +} + Vector StorageManager::getLocalStorageOriginDetailsCrossThreadCopy() const { ASSERT(!RunLoop::isMain()); diff --git a/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h b/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h index 0d6e7aedff68227bf7dc8ab7184abc6fd3321c54..67b616d818aa42f8cae33f0535c888cd4c5ec07e 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h +++ b/Source/WebKit/NetworkProcess/WebStorage/StorageManager.h @@ -66,6 +66,7 @@ public: void deleteSessionStorageEntriesForOrigins(const Vector&); HashSet getLocalStorageOriginsCrossThreadCopy() const; + Vector>> getLocalStorageDataCrossThreadCopy() const; void deleteLocalStorageOriginsModifiedSince(WallTime); void deleteLocalStorageEntriesForOrigins(const Vector&); Vector getLocalStorageOriginDetailsCrossThreadCopy() const; diff --git a/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp b/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp index 982621afbfed2dda9dcc62a37430658c373944f3..f51f1858bf3f063ccc6a0af1ec1a55a34954b89e 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp +++ b/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.cpp @@ -272,6 +272,50 @@ void StorageManagerSet::getLocalStorageOrigins(PAL::SessionID sessionID, GetOrig }); } +void StorageManagerSet::getLocalStorageData(PAL::SessionID sessionID, GetLocalStorageDataCallback&& completionHandler) +{ + ASSERT(RunLoop::isMain()); + + m_queue->dispatch([this, protectedThis = makeRef(*this), sessionID, completionHandler = WTFMove(completionHandler)]() mutable { + auto* storageManager = m_storageManagers.get(sessionID); + ASSERT(storageManager); + + auto origins = storageManager->getLocalStorageDataCrossThreadCopy(); + RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), origins = WTFMove(origins)]() mutable { + completionHandler(WTFMove(origins)); + }); + }); +} + +void StorageManagerSet::setLocalStorageData(PAL::SessionID sessionID, WebKit::StorageNamespaceIdentifier storageNamespaceID, Vector>>&& origins, CompletionHandler&& completionHandler) +{ + ASSERT(RunLoop::isMain()); + + m_queue->dispatch([this, protectedThis = makeRef(*this), sessionID, storageNamespaceID, origins = WTFMove(origins), completionHandler = WTFMove(completionHandler)]() mutable { + auto* storageManager = m_storageManagers.get(sessionID); + ASSERT(storageManager); + + String error; + for (const auto& originData : origins) { + auto* storageArea = storageManager->createLocalStorageArea(storageNamespaceID, originData.first.isolatedCopy(), m_queue.copyRef()); + if (!storageArea) { + error = "Cannot create storage area"; + break; + } + bool quotaException = false; + storageArea->setItems(originData.second, quotaException); + if (quotaException) { + error = "Storage quota exceeded"; + break; + } + } + + RunLoop::main().dispatch([completionHandler = WTFMove(completionHandler), error = WTFMove(error)]() mutable { + completionHandler(error); + }); + }); +} + void StorageManagerSet::deleteLocalStorageModifiedSince(PAL::SessionID sessionID, WallTime time, DeleteCallback&& completionHandler) { ASSERT(RunLoop::isMain()); diff --git a/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.h b/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.h index 6945f2b199202a77413bef711a59510a700d18b3..d7e84ca85e18163a02407f383339df4ff95984e5 100644 --- a/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.h +++ b/Source/WebKit/NetworkProcess/WebStorage/StorageManagerSet.h @@ -45,6 +45,7 @@ using ConnectToStorageAreaCallback = CompletionHandler&)>; using GetOriginsCallback = CompletionHandler&&)>; using GetOriginDetailsCallback = CompletionHandler&&)>; +using GetLocalStorageDataCallback = CompletionHandler>>&&)>; using DeleteCallback = CompletionHandler; class StorageManagerSet : public IPC::Connection::WorkQueueMessageReceiver { @@ -72,6 +73,8 @@ public: void deleteLocalStorageModifiedSince(PAL::SessionID, WallTime, DeleteCallback&&); void deleteLocalStorageForOrigins(PAL::SessionID, const Vector&, DeleteCallback&&); void getLocalStorageOriginDetails(PAL::SessionID, GetOriginDetailsCallback&&); + void getLocalStorageData(PAL::SessionID, GetLocalStorageDataCallback&&); + void setLocalStorageData(PAL::SessionID sessionID, WebKit::StorageNamespaceIdentifier storageNamespaceID, Vector>>&& origins, CompletionHandler&&); void renameOrigin(PAL::SessionID, const URL&, const URL&, CompletionHandler&&); void didReceiveMessage(IPC::Connection&, IPC::Decoder&); diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h index 4ebbd90cc645df5f9ddbb860d08aa3eb053c2ff6..3d5d56a5a1b407f27e533c9c71d3e4c4fb012c36 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.h @@ -86,6 +86,8 @@ public: void checkTAO(const WebCore::ResourceResponse&); + static void setCookieFromResponse(NetworkSessionCocoa& session, const NetworkLoadParameters&, const URL& mainDocumentURL, const String& setCookieValue); + private: NetworkDataTaskCocoa(NetworkSession&, NetworkDataTaskClient&, const NetworkLoadParameters&); diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm index f74b3129fe72bc9fce62360606d3b39b0712cf89..f2d20693b81f3a953102ab335f3744c28be4a0ea 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkDataTaskCocoa.mm @@ -42,6 +42,7 @@ #import #import #import +#import #import #import #import @@ -740,4 +741,59 @@ void NetworkDataTaskCocoa::checkTAO(const WebCore::ResourceResponse& response) networkLoadMetrics().failsTAOCheck = !passesTimingAllowOriginCheck(response, *origin); } +class DummyNetworkDataTaskClient: public NetworkDataTaskClient { +public: + void willPerformHTTPRedirection(WebCore::ResourceResponse&&, WebCore::ResourceRequest&&, RedirectCompletionHandler&&) final {} + void didReceiveChallenge(WebCore::AuthenticationChallenge&&, NegotiatedLegacyTLS, ChallengeCompletionHandler&&) final {} + void didReceiveResponse(WebCore::ResourceResponse&&, NegotiatedLegacyTLS, ResponseCompletionHandler&&) final {} + void didReceiveData(Ref&&) final {} + void didCompleteWithError(const WebCore::ResourceError&, const WebCore::NetworkLoadMetrics&) final {} + void didSendData(uint64_t totalBytesSent, uint64_t totalBytesExpectedToSend) final {} + void wasBlocked() final {} + void cannotShowURL() final {} + void wasBlockedByRestrictions() final {} + ~DummyNetworkDataTaskClient() {} +}; + +// static +void NetworkDataTaskCocoa::setCookieFromResponse(NetworkSessionCocoa& networkSession, const NetworkLoadParameters& parameters, const URL& mainDocumentURL, const String& setCookieValue) +{ + const URL& url = parameters.request.url(); + DummyNetworkDataTaskClient client; + RefPtr taskGeneric = NetworkDataTask::create(networkSession, client, parameters); + NetworkDataTaskCocoa* task = static_cast(taskGeneric.get()); + // Note: we are not calling task->resume(), and miss some logic from there. + + WebCore::ResourceResponse resourceResponse; + resourceResponse.setURL(url); + task->didReceiveResponse(WTFMove(resourceResponse), NegotiatedLegacyTLS::No, [](WebCore::PolicyAction policyAction) {}); + + if (task->m_hasBeenSetToUseStatelessCookieStorage || !task->m_sessionWrapper) { + task->cancel(); + return; + } + + NSURLSessionConfiguration* configuration = [task->m_sessionWrapper->session configuration]; + if (!configuration.HTTPCookieStorage) { + task->cancel(); + return; + } + + NSString* cookieString = (NSString *)setCookieValue; + NSString* cookieKey = @"Set-Cookie"; + NSDictionary* headers = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObject:cookieString] forKeys:[NSArray arrayWithObject:cookieKey]]; + NSArray* cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:(NSURL *)url]; + + NSURL* siteForCookies = task->m_task.get()._siteForCookies; + NSURL* documentURL = task->isTopLevelNavigation() ? siteForCookies : (NSURL *)mainDocumentURL; + if (siteForCookies && documentURL) { + // Both siteForCookies and/or documentURL may be nil, for example when one of them is about:blank. + BEGIN_BLOCK_OBJC_EXCEPTIONS + [configuration.HTTPCookieStorage setCookies:cookies forURL:siteForCookies mainDocumentURL:documentURL]; + END_BLOCK_OBJC_EXCEPTIONS + } + + task->cancel(); +} + } diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm index fdce7681fe6f28872b422e63549192d519476729..2ba62f93a3c4dfe91f77097ad98748486f6d3471 100644 --- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm +++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm @@ -700,7 +700,7 @@ static inline void processServerTrustEvaluation(NetworkSessionCocoa& session, Se NegotiatedLegacyTLS negotiatedLegacyTLS = NegotiatedLegacyTLS::No; if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - if (NetworkSessionCocoa::allowsSpecificHTTPSCertificateForHost(challenge)) + if (sessionCocoa->ignoreCertificateErrors() || sessionCocoa->allowsSpecificHTTPSCertificateForHost(challenge)) return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); #if HAVE(TLS_PROTOCOL_VERSION_T) @@ -959,6 +959,13 @@ static inline void processServerTrustEvaluation(NetworkSessionCocoa& session, Se resourceResponse.setDeprecatedNetworkLoadMetrics(WebCore::copyTimingData(taskMetrics, networkDataTask->networkLoadMetrics())); + __block WebCore::HTTPHeaderMap requestHeaders; + NSURLSessionTaskTransactionMetrics *m = dataTask._incompleteTaskMetrics.transactionMetrics.lastObject; + [m.request.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(NSString *name, NSString *value, BOOL *) { + requestHeaders.set(String(name), String(value)); + }]; + resourceResponse.m_httpRequestHeaderFields = WTFMove(requestHeaders); + networkDataTask->didReceiveResponse(WTFMove(resourceResponse), negotiatedLegacyTLS, [completionHandler = makeBlockPtr(completionHandler), taskIdentifier](WebCore::PolicyAction policyAction) { #if !LOG_DISABLED LOG(NetworkSession, "%llu didReceiveResponse completionHandler (%d)", taskIdentifier, policyAction); diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp index e9f9b2c257866d9300e79781cbef3addc59cd9de..c45d2f047614da8a5e360b88960fbd2afb16072f 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp @@ -26,9 +26,13 @@ #include "config.h" #include "NetworkDataTaskCurl.h" +#include "APIError.h" #include "AuthenticationChallengeDisposition.h" #include "AuthenticationManager.h" +#include "DataReference.h" +#include "Download.h" #include "NetworkSessionCurl.h" +#include "NetworkProcess.h" #include #include #include @@ -40,6 +44,7 @@ #include #include #include +#include namespace WebKit { @@ -77,6 +82,8 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); m_curlRequest->setAuthenticationScheme(ProtectionSpaceAuthenticationSchemeHTTPBasic); } + if (m_session->ignoreCertificateErrors()) + m_curlRequest->disableServerTrustEvaluation(); m_curlRequest->start(); } @@ -106,6 +113,9 @@ void NetworkDataTaskCurl::cancel() if (m_curlRequest) m_curlRequest->cancel(); + + if (isDownload()) + deleteDownloadFile(); } void NetworkDataTaskCurl::invalidateAndCancel() @@ -150,6 +160,7 @@ void NetworkDataTaskCurl::curlDidReceiveResponse(CurlRequest& request, CurlRespo m_response = ResourceResponse(receivedResponse); m_response.setCertificateInfo(WTFMove(receivedResponse.certificateInfo)); m_response.setDeprecatedNetworkLoadMetrics(Box::create(WTFMove(receivedResponse.networkLoadMetrics))); + m_response.m_httpRequestHeaderFields = request.resourceRequest().httpHeaderFields(); handleCookieHeaders(request.resourceRequest(), receivedResponse); @@ -177,7 +188,10 @@ void NetworkDataTaskCurl::curlDidReceiveBuffer(CurlRequest&, Ref&& auto protectedThis = makeRef(*this); if (state() == State::Canceling || state() == State::Completed || (!m_client && !isDownload())) return; - + if (isDownload()) { + FileSystem::writeToFile(m_downloadDestinationFile, buffer->data(), buffer->size()); + return; + } m_client->didReceiveData(WTFMove(buffer)); } @@ -186,9 +200,26 @@ void NetworkDataTaskCurl::curlDidComplete(CurlRequest&, NetworkLoadMetrics&& net if (state() == State::Canceling || state() == State::Completed || (!m_client && !isDownload())) return; + if (isDownload()) { + auto* download = m_session->networkProcess().downloadManager().download(m_pendingDownloadID); + ASSERT(download); + FileSystem::closeFile(m_downloadDestinationFile); + m_downloadDestinationFile = FileSystem::invalidPlatformFileHandle; + download->didFinish(); + return; + } m_client->didCompleteWithError({ }, WTFMove(networkLoadMetrics)); } +void NetworkDataTaskCurl::deleteDownloadFile() +{ + if (m_downloadDestinationFile != FileSystem::invalidPlatformFileHandle) { + FileSystem::closeFile(m_downloadDestinationFile); + FileSystem::deleteFile(m_pendingDownloadLocation); + m_downloadDestinationFile = FileSystem::invalidPlatformFileHandle; + } +} + void NetworkDataTaskCurl::curlDidFailWithError(CurlRequest& request, ResourceError&& resourceError, CertificateInfo&& certificateInfo) { if (state() == State::Canceling || state() == State::Completed || (!m_client && !isDownload())) @@ -199,6 +230,14 @@ void NetworkDataTaskCurl::curlDidFailWithError(CurlRequest& request, ResourceErr return; } + if (isDownload()) { + deleteDownloadFile(); + auto* download = m_session->networkProcess().downloadManager().download(m_pendingDownloadID); + ASSERT(download); + download->didFail(resourceError, IPC::DataReference()); + return; + } + m_client->didCompleteWithError(resourceError); } @@ -236,6 +275,19 @@ void NetworkDataTaskCurl::invokeDidReceiveResponse() case PolicyAction::Ignore: invalidateAndCancel(); break; + case PolicyAction::Download: { + FileSystem::deleteFile(m_pendingDownloadLocation); + auto& downloadManager = m_session->networkProcess().downloadManager(); + auto download = makeUnique(downloadManager, m_pendingDownloadID, *this, *m_session, suggestedFilename()); + auto* downloadPtr = download.get(); + downloadManager.dataTaskBecameDownloadTask(m_pendingDownloadID, WTFMove(download)); + m_downloadDestinationFile = FileSystem::openFile(m_pendingDownloadLocation, FileSystem::FileOpenMode::Write); + downloadPtr->didCreateDestination(m_pendingDownloadLocation); + + if (m_curlRequest) + m_curlRequest->completeDidReceiveResponse(); + break; + } default: notImplemented(); break; @@ -315,6 +367,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection() m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password()); m_curlRequest->setAuthenticationScheme(ProtectionSpaceAuthenticationSchemeHTTPBasic); } + if (m_session->ignoreCertificateErrors()) + m_curlRequest->disableServerTrustEvaluation(); m_curlRequest->start(); if (m_state != State::Suspended) { diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h index 1c427ddb78d6953fe8960c5692afde4f4f0eee85..cf33ff6076dd95ffe564f1dde89c177acd27b02c 100644 --- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h +++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h @@ -32,6 +32,7 @@ #include #include #include +#include #include namespace WebCore { @@ -85,13 +86,13 @@ private: void appendCookieHeader(WebCore::ResourceRequest&); void handleCookieHeaders(const WebCore::ResourceRequest&, const WebCore::CurlResponse&); + String suggestedFilename() const override; bool isThirdPartyRequest(const WebCore::ResourceRequest&); bool shouldBlockCookies(const WebCore::ResourceRequest&); void blockCookies(); void unblockCookies(); - - String suggestedFilename() const override; + void deleteDownloadFile(); State m_state { State::Suspended }; @@ -103,6 +104,8 @@ private: WebCore::FrameIdentifier m_frameID; WebCore::PageIdentifier m_pageID; + FileSystem::PlatformFileHandle m_downloadDestinationFile { FileSystem::invalidPlatformFileHandle }; + bool m_blockingCookies { false }; WebCore::ShouldRelaxThirdPartyCookieBlocking m_shouldRelaxThirdPartyCookieBlocking { WebCore::ShouldRelaxThirdPartyCookieBlocking::No }; diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp index dbdfe70ca4f50f2aaba4e9f51037b8a89aad69e8..5f5ef27c9bfd20c5006dac8741ead2579704d17b 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp @@ -491,6 +491,7 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr&& inputStream) m_networkLoadMetrics.failsTAOCheck = !passesTimingAllowOriginCheck(m_response, *origin); } + m_response.m_httpRequestHeaderFields = m_networkLoadMetrics.requestHeaders; dispatchDidReceiveResponse(); } @@ -588,6 +589,8 @@ bool NetworkDataTaskSoup::acceptCertificate(GTlsCertificate* certificate, GTlsCe { ASSERT(m_soupMessage); URL url = soupURIToURL(soup_message_get_uri(m_soupMessage.get())); + if (m_session->ignoreCertificateErrors()) + return true; auto error = static_cast(*m_session).soupNetworkSession().checkTLSErrors(url, certificate, tlsErrors); if (!error) return true; diff --git a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp index 06ca252b043959d457814d45886949a85b1a19c1..597e63aca71d213526d953ead357fbc0e0405f8d 100644 --- a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp +++ b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp @@ -113,6 +113,11 @@ static gboolean webSocketAcceptCertificateCallback(GTlsConnection* connection, G return !session->soupNetworkSession().checkTLSErrors(soupURIToURL(soup_message_get_uri(soupMessage)), certificate, errors); } +static gboolean webSocketAcceptCertificateCallbackIgnoreTLSErrors(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) +{ + return TRUE; +} + static void webSocketMessageNetworkEventCallback(SoupMessage* soupMessage, GSocketClientEvent event, GIOStream* connection, NetworkSessionSoup* session) { if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING) @@ -123,6 +128,15 @@ static void webSocketMessageNetworkEventCallback(SoupMessage* soupMessage, GSock } #endif +static void webSocketMessageNetworkEventCallbackIgnoreTLSErrors(SoupMessage* soupMessage, GSocketClientEvent event, GIOStream* connection) +{ + if (event != G_SOCKET_CLIENT_TLS_HANDSHAKING) + return; + + g_object_set_data(G_OBJECT(connection), "wk-soup-message", soupMessage); + g_signal_connect(connection, "accept-certificate", G_CALLBACK(webSocketAcceptCertificateCallbackIgnoreTLSErrors), soupMessage); +} + std::unique_ptr NetworkSessionSoup::createWebSocketTask(WebPageProxyIdentifier, NetworkSocketChannel& channel, const ResourceRequest& request, const String& protocol) { GRefPtr soupMessage = request.createSoupMessage(blobRegistry()); @@ -131,14 +145,21 @@ std::unique_ptr NetworkSessionSoup::createWebSocketTask(WebPagePr if (request.url().protocolIs("wss")) { #if USE(SOUP2) - g_signal_connect(soupMessage.get(), "network-event", G_CALLBACK(webSocketMessageNetworkEventCallback), this); + if (ignoreCertificateErrors()) + g_signal_connect(soupMessage.get(), "network-event", G_CALLBACK(webSocketMessageNetworkEventCallbackIgnoreTLSErrors), this); + else + g_signal_connect(soupMessage.get(), "network-event", G_CALLBACK(webSocketMessageNetworkEventCallback), this); #else - g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) -> gboolean { - if (DeprecatedGlobalSettings::allowsAnySSLCertificate()) - return TRUE; - - return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors); - }), this); + if (ignoreCertificateErrors()) { + g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(webSocketAcceptCertificateCallbackIgnoreTLSErrors), this); + } else { + g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session) -> gboolean { + if (DeprecatedGlobalSettings::allowsAnySSLCertificate()) + return TRUE; + + return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors); + }), this); + } #endif } return makeUnique(channel, request, soupSession(), soupMessage.get(), protocol); diff --git a/Source/WebKit/PlatformGTK.cmake b/Source/WebKit/PlatformGTK.cmake index d679785ca3bd58b2ed2ce08765eb55701bf5e723..14de9b9f902d7d131f44d0aedcf7ed751e55e7ca 100644 --- a/Source/WebKit/PlatformGTK.cmake +++ b/Source/WebKit/PlatformGTK.cmake @@ -450,6 +450,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GSTREAMER_PBUTILS_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} +# Playwright begin + ${LIBVPX_INCLUDE_DIRS} +# Playwright end ) if (USE_WPE_RENDERER) @@ -503,6 +506,9 @@ if (USE_LIBWEBRTC) list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES "${THIRDPARTY_DIR}/libwebrtc/Source/" "${THIRDPARTY_DIR}/libwebrtc/Source/webrtc" +# Playwright begin + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" +# Playwright end ) endif () @@ -517,6 +523,12 @@ if (ENABLE_MEDIA_STREAM) ) endif () +# Playwright begin +list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" +) +# Playwright end + # To generate WebKitEnumTypes.h we want to use all installed headers, except WebKitEnumTypes.h itself. set(WebKit2GTK_ENUM_GENERATION_HEADERS ${WebKit2GTK_INSTALLED_HEADERS}) list(REMOVE_ITEM WebKit2GTK_ENUM_GENERATION_HEADERS ${WebKit2Gtk_DERIVED_SOURCES_DIR}/webkit2/WebKitEnumTypes.h) diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake index e397c07b7cf7170f4d833997d499b4ac7ffcd898..ba2270f561b90cc54682b77c02c9028552e951fa 100644 --- a/Source/WebKit/PlatformWPE.cmake +++ b/Source/WebKit/PlatformWPE.cmake @@ -278,6 +278,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" @@ -300,8 +301,17 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES ${GIO_UNIX_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${LIBSOUP_INCLUDE_DIRS} +# Playwright begin + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" +# Playwright end ) +# Playwright begin +list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" +) +# Playwright end + list(APPEND WebKit_LIBRARIES Cairo::Cairo Freetype::Freetype diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake index 01565d550697b25367bb36971d6fe5ec33f712f0..98fb300309de1c0567912158f23ab39e7c0e21d5 100644 --- a/Source/WebKit/PlatformWin.cmake +++ b/Source/WebKit/PlatformWin.cmake @@ -69,8 +69,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 @@ -88,6 +92,7 @@ list(APPEND WebKit_SOURCES WebProcess/Plugins/Netscape/win/PluginProxyWin.cpp WebProcess/WebCoreSupport/win/WebPopupMenuWin.cpp + WebProcess/WebCoreSupport/win/WebDragClientWin.cpp WebProcess/WebPage/AcceleratedSurface.cpp @@ -129,6 +134,72 @@ list(APPEND WebKit_INCLUDE_DIRECTORIES "${WEBKIT_DIR}/win" ) +# Playwright begin +list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include" + "${LIBVPX_CUSTOM_INCLUDE_DIR}" +) + +list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm" +) + +list(APPEND WebKit_SOURCES + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvwriter.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_mmi.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_from.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_mmi.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_any.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_mmi.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_any.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_common.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_mmi.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_uv.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_win.cc" + "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/video_common.cc" +) +# Playwright end + set(WebKitCommonIncludeDirectories ${WebKit_INCLUDE_DIRECTORIES}) set(WebKitCommonSystemIncludeDirectories ${WebKit_SYSTEM_INCLUDE_DIRECTORIES}) @@ -181,6 +252,7 @@ if (${WTF_PLATFORM_WIN_CAIRO}) OpenSSL::SSL mfuuid.lib strmiids.lib + ${LIBVPX_CUSTOM_LIBRARY} ) endif () diff --git a/Source/WebKit/Shared/API/c/wpe/WebKit.h b/Source/WebKit/Shared/API/c/wpe/WebKit.h index caf67e1dece5b727e43eba780e70814f8fdb0f63..740150d2589d6e16a516daa3bf6ef899ac538c99 100644 --- a/Source/WebKit/Shared/API/c/wpe/WebKit.h +++ b/Source/WebKit/Shared/API/c/wpe/WebKit.h @@ -77,6 +77,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 ee8cac1c980039c4a36de5501ab7f135e710d06b..deae2be9e720ff76186ecea89920dfc39c4f186a 100644 --- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h +++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h @@ -33,6 +33,7 @@ #if USE(APPKIT) #include OBJC_CLASS NSView; +OBJC_CLASS NSEvent; #endif #if PLATFORM(GTK) @@ -65,19 +66,35 @@ 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&); NativeWebKeyboardEvent(GdkEvent*, const String&, Vector&& commands); NativeWebKeyboardEvent(const String&, std::optional>&&, std::optional&&); NativeWebKeyboardEvent(Type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector&& commands, bool isKeypad, OptionSet); + 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, std::optional>&&, std::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 001558dd58f4d85f360d5711caa03db33889011e..1e0898f985f1d13036d31e3e284258a3c64fa0a4 100644 --- a/Source/WebKit/Shared/NativeWebMouseEvent.h +++ b/Source/WebKit/Shared/NativeWebMouseEvent.h @@ -77,6 +77,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/WebCoreArgumentCoders.cpp b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp index 91d21d8f236bd18832b50d2cad311cc6f2488cee..6c4caa100f785aa896569f24539467693295746c 100644 --- a/Source/WebKit/Shared/WebCoreArgumentCoders.cpp +++ b/Source/WebKit/Shared/WebCoreArgumentCoders.cpp @@ -120,6 +120,10 @@ #include #endif +#if PLATFORM(WPE) +#include "ArgumentCodersWPE.h" +#endif + // FIXME: Seems like we could use std::tuple to cut down the code below a lot! namespace IPC { @@ -675,7 +679,7 @@ bool ArgumentCoder::decode(Decoder& decoder, FloatBoxExtent& flo { return SimpleArgumentCoder::decode(decoder, floatBoxExtent); } - + void ArgumentCoder::encode(Encoder& encoder, const FloatSize& floatSize) { @@ -1403,6 +1407,9 @@ void ArgumentCoder::encode(Encoder& encoder, const WindowFeature encoder << windowFeatures.resizable; encoder << windowFeatures.fullscreen; encoder << windowFeatures.dialog; + encoder << windowFeatures.noopener; + encoder << windowFeatures.noreferrer; + encoder << windowFeatures.additionalFeatures; } bool ArgumentCoder::decode(Decoder& decoder, WindowFeatures& windowFeatures) @@ -1431,6 +1438,12 @@ bool ArgumentCoder::decode(Decoder& decoder, WindowFeatures& win return false; if (!decoder.decode(windowFeatures.dialog)) return false; + if (!decoder.decode(windowFeatures.noopener)) + return false; + if (!decoder.decode(windowFeatures.noreferrer)) + return false; + if (!decoder.decode(windowFeatures.additionalFeatures)) + return false; return true; } @@ -1444,6 +1457,11 @@ void ArgumentCoder::encode(Encoder& encoder, const DragData& dragData) #if PLATFORM(COCOA) encoder << dragData.pasteboardName(); encoder << dragData.fileNames(); +#endif +#if PLATFORM(WIN) + DragData dragDataCopy = dragData; + HashMap> hash = dragDataCopy.dragDataMap(); + encoder << hash; #endif encoder << dragData.dragDestinationActionMask(); encoder << dragData.pageID(); @@ -1467,9 +1485,16 @@ bool ArgumentCoder::decode(Decoder& decoder, DragData& dragData) if (!decoder.decode(applicationFlags)) return false; +#if PLATFORM(WIN) + DragDataMap dragDataMap; + if (!decoder.decode(dragDataMap)) + return false; +#else String pasteboardName; - Vector fileNames; +#endif + #if PLATFORM(COCOA) + Vector fileNames; if (!decoder.decode(pasteboardName)) return false; @@ -1485,8 +1510,14 @@ bool ArgumentCoder::decode(Decoder& decoder, DragData& dragData) if (!decoder.decode(pageID)) return false; +#if PLATFORM(WIN) + dragData = DragData(dragDataMap, clientPosition, globalPosition, draggingSourceOperationMask, applicationFlags, pageID); +#else dragData = DragData(pasteboardName, clientPosition, globalPosition, draggingSourceOperationMask, applicationFlags, dragDestinationActionMask, pageID); +#endif +#if PLATFORM(COCOA) dragData.setFileNames(fileNames); +#endif return true; } diff --git a/Source/WebKit/Shared/WebEvent.h b/Source/WebKit/Shared/WebEvent.h index 3ae6504779d3917a79f69f32b58260afeda270b4..72d44c33953cc13bf2ed7c762b4f9a7b88571b56 100644 --- a/Source/WebKit/Shared/WebEvent.h +++ b/Source/WebKit/Shared/WebEvent.h @@ -31,6 +31,7 @@ #include #include +#include #include #include diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp index a70eb76c5c22a2c779c30874433ac19036b5f1a4..f97fa9dec785fd6327bb7847454e8a32b8a0d3ac 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, std::optional>&& preeditUnderlines, std::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/WebKeyboardEvent.h b/Source/WebKit/Shared/WebKeyboardEvent.h index 7a5893eb68ad24cf92c832070485489b7cfafa0c..a2d68a5eb59d8b7155c1e17b75a12e55f299b868 100644 --- a/Source/WebKit/Shared/WebKeyboardEvent.h +++ b/Source/WebKit/Shared/WebKeyboardEvent.h @@ -43,14 +43,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, std::optional>&&, std::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, std::optional>&&, std::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; } diff --git a/Source/WebKit/Shared/WebPageCreationParameters.cpp b/Source/WebKit/Shared/WebPageCreationParameters.cpp index 6a25231f6fc258c1e38aa05ce12aa444fd7096c8..b25472d15a30834997e39632144a44aa25103654 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.cpp +++ b/Source/WebKit/Shared/WebPageCreationParameters.cpp @@ -156,6 +156,8 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const encoder << crossOriginAccessControlCheckEnabled; encoder << processDisplayName; + encoder << shouldPauseInInspectorWhenShown; + encoder << shouldCaptureAudioInUIProcess; encoder << shouldCaptureAudioInGPUProcess; encoder << shouldCaptureVideoInUIProcess; @@ -539,7 +541,10 @@ std::optional WebPageCreationParameters::decode(IPC:: if (!processDisplayName) return std::nullopt; parameters.processDisplayName = WTFMove(*processDisplayName); - + + if (!decoder.decode(parameters.shouldPauseInInspectorWhenShown)) + return std::nullopt; + if (!decoder.decode(parameters.shouldCaptureAudioInUIProcess)) return std::nullopt; diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h index c58e6c220b1a03766aae548472f16b783e0402ac..f2d004ec07037b483c3ff0ea20c7f38a07084ad5 100644 --- a/Source/WebKit/Shared/WebPageCreationParameters.h +++ b/Source/WebKit/Shared/WebPageCreationParameters.h @@ -247,6 +247,8 @@ struct WebPageCreationParameters { WebCore::ShouldRelaxThirdPartyCookieBlocking shouldRelaxThirdPartyCookieBlocking { WebCore::ShouldRelaxThirdPartyCookieBlocking::No }; + 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 c204637774ee803eac42a34cde79aa556f143b82..345f5b08179e3dd239725bed06e48b46bc718336 100644 --- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp @@ -50,7 +50,7 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(Type type, const String& text, co } NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event) - : WebKeyboardEvent(event.type(), event.text(), event.key(), event.code(), event.keyIdentifier(), event.windowsVirtualKeyCode(), event.nativeVirtualKeyCode(), event.handledByInputMethod(), std::optional>(event.preeditUnderlines()), std::optional(event.preeditSelectionRange()), Vector(event.commands()), event.isKeypad(), event.modifiers(), event.timestamp()) + : WebKeyboardEvent(event) , m_nativeEvent(event.nativeEvent() ? gdk_event_copy(event.nativeEvent()) : nullptr) { } diff --git a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp index 7cc65739c320cb4312d9d705284220a383a0293a..da53885517d55d424423ee3d0dcead25825cc022 100644 --- a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp +++ b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp @@ -54,7 +54,7 @@ NativeWebMouseEvent::NativeWebMouseEvent(Type type, Button button, unsigned shor } NativeWebMouseEvent::NativeWebMouseEvent(const NativeWebMouseEvent& event) - : WebMouseEvent(event.type(), event.button(), event.buttons(), event.position(), event.globalPosition(), event.deltaX(), event.deltaY(), event.deltaZ(), event.clickCount(), event.modifiers(), event.timestamp(), 0, NoTap, event.pointerId(), event.pointerType()) + : WebMouseEvent(event) , m_nativeEvent(event.nativeEvent() ? gdk_event_copy(const_cast(event.nativeEvent())) : nullptr) { } diff --git a/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp b/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp index 03e118154f6bb5b704b4ecb83d3d9543f8c5a5fa..9725caaac6ee65a96ea324ddbb4e1a3785bbc028 100644 --- a/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp +++ b/Source/WebKit/Shared/ios/WebPlatformTouchPointIOS.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "WebTouchEvent.h" -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY) #include "WebCoreArgumentCoders.h" @@ -79,4 +79,4 @@ std::optional WebPlatformTouchPoint::decode(IPC::Decoder& } // 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 e40a6e172bfd2b75076fd4053da643ebab9eb81f..2516655bbc9e5bc863537a554c5faac0f6fc1a09 100644 --- a/Source/WebKit/Shared/ios/WebTouchEventIOS.cpp +++ b/Source/WebKit/Shared/ios/WebTouchEventIOS.cpp @@ -26,7 +26,7 @@ #include "config.h" #include "WebTouchEvent.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/libwpe/ArgumentCodersWPE.cpp b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..678010b33d70dae6369ace4337b4c0eb81152250 --- /dev/null +++ b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ArgumentCodersWPE.h" + +#include "DataReference.h" +#include "ShareableBitmap.h" +#include "WebCoreArgumentCoders.h" +#include +#include +#include + +namespace IPC { +using namespace WebCore; +using namespace WebKit; + +static void encodeImage(Encoder& encoder, Image& image) +{ + RefPtr bitmap = ShareableBitmap::createShareable(IntSize(image.size()), { }); + bitmap->createGraphicsContext()->drawImage(image, IntPoint()); + + ShareableBitmap::Handle handle; + bitmap->createHandle(handle); + + encoder << handle; +} + +static WARN_UNUSED_RETURN bool decodeImage(Decoder& decoder, RefPtr& image) +{ + ShareableBitmap::Handle handle; + if (!decoder.decode(handle)) + return false; + + RefPtr bitmap = ShareableBitmap::create(handle); + if (!bitmap) + return false; + image = bitmap->createImage(); + if (!image) + return false; + return true; +} + +void ArgumentCoder::encode(Encoder& encoder, const SelectionData& selection) +{ + bool hasText = selection.hasText(); + encoder << hasText; + if (hasText) + encoder << selection.text(); + bool hasMarkup = selection.hasMarkup(); + encoder << hasMarkup; + if (hasMarkup) + encoder << selection.markup(); + + bool hasURL = selection.hasURL(); + encoder << hasURL; + if (hasURL) + encoder << selection.url().string(); + + bool hasURIList = selection.hasURIList(); + encoder << hasURIList; + if (hasURIList) + encoder << selection.uriList(); + + bool hasImage = selection.hasImage(); + encoder << hasImage; + if (hasImage) + encodeImage(encoder, *selection.image()); + + bool hasCustomData = selection.hasCustomData(); + encoder << hasCustomData; + if (hasCustomData) + encoder << RefPtr(selection.customData()); + + bool canSmartReplace = selection.canSmartReplace(); + encoder << canSmartReplace; +} + +std::optional ArgumentCoder::decode(Decoder& decoder) +{ + SelectionData selection; + + bool hasText; + if (!decoder.decode(hasText)) + return std::nullopt; + if (hasText) { + String text; + if (!decoder.decode(text)) + return std::nullopt; + selection.setText(text); + } + + bool hasMarkup; + if (!decoder.decode(hasMarkup)) + return std::nullopt; + if (hasMarkup) { + String markup; + if (!decoder.decode(markup)) + return std::nullopt; + selection.setMarkup(markup); + } + + bool hasURL; + if (!decoder.decode(hasURL)) + return std::nullopt; + if (hasURL) { + String url; + if (!decoder.decode(url)) + return std::nullopt; + selection.setURL(URL(URL(), url), String()); + } + + bool hasURIList; + if (!decoder.decode(hasURIList)) + return std::nullopt; + if (hasURIList) { + String uriList; + if (!decoder.decode(uriList)) + return std::nullopt; + selection.setURIList(uriList); + } + + bool hasImage; + if (!decoder.decode(hasImage)) + return std::nullopt; + if (hasImage) { + RefPtr image; + if (!decodeImage(decoder, image)) + return std::nullopt; + selection.setImage(image.get()); + } + + bool hasCustomData; + if (!decoder.decode(hasCustomData)) + return std::nullopt; + if (hasCustomData) { + RefPtr buffer; + if (!decoder.decode(buffer)) + return std::nullopt; + selection.setCustomData(Ref(*buffer)); + } + + bool canSmartReplace; + if (!decoder.decode(canSmartReplace)) + return std::nullopt; + selection.setCanSmartReplace(canSmartReplace); + + return selection; +} + +} diff --git a/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.h b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.h new file mode 100644 index 0000000000000000000000000000000000000000..789a0d7cf69704c8f665a9ed79348fbcbc1301c4 --- /dev/null +++ b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "ArgumentCoders.h" + +namespace WebCore { +class SelectionData; +} + +namespace IPC { + +template<> struct ArgumentCoder { + static void encode(Encoder&, const WebCore::SelectionData&); + static std::optional decode(Decoder&); +}; + +} // namespace IPC diff --git a/Source/WebKit/Shared/win/WebEventFactory.cpp b/Source/WebKit/Shared/win/WebEventFactory.cpp index 85d6f74114f4e7f82d9502d1b99d69098d6a49b6..6896c9756edb233dda46c7031e1af69923da8c23 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 d488a3d966ec641d8dcf652fa37b2b49d9cd45d7..aa66ba61048e23194fbd24e955ecd68e6a5031ba 100644 --- a/Source/WebKit/Sources.txt +++ b/Source/WebKit/Sources.txt @@ -289,11 +289,14 @@ Shared/WebsiteData/WebsiteData.cpp UIProcess/AuxiliaryProcessProxy.cpp UIProcess/BackgroundProcessResponsivenessTimer.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/MediaKeySystemPermissionRequestManagerProxy.cpp UIProcess/MediaKeySystemPermissionRequestProxy.cpp @@ -302,6 +305,7 @@ UIProcess/PageLoadState.cpp UIProcess/ProcessAssertion.cpp UIProcess/ProcessThrottler.cpp UIProcess/ProvisionalPageProxy.cpp +UIProcess/RemoteInspectorPipe.cpp UIProcess/ResponsivenessTimer.cpp UIProcess/SpeechRecognitionRemoteRealtimeMediaSource.cpp UIProcess/SpeechRecognitionRemoteRealtimeMediaSourceManager.cpp @@ -342,6 +346,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 @@ -463,7 +469,11 @@ UIProcess/Inspector/WebInspectorUtilities.cpp UIProcess/Inspector/WebPageDebuggable.cpp UIProcess/Inspector/WebPageInspectorController.cpp +UIProcess/Inspector/Agents/CairoJpegEncoder.cpp UIProcess/Inspector/Agents/InspectorBrowserAgent.cpp +UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp +UIProcess/Inspector/Agents/ScreencastEncoder.cpp +UIProcess/Inspector/Agents/WebMFileWriter.cpp UIProcess/Media/AudioSessionRoutingArbitratorProxy.cpp UIProcess/Media/MediaUsageManager.cpp diff --git a/Source/WebKit/SourcesCocoa.txt b/Source/WebKit/SourcesCocoa.txt index 4cfd09faad063bc1a0f27401927118a3a0165277..f728a8620dbb2d00e2113c9f49ca04751204034d 100644 --- a/Source/WebKit/SourcesCocoa.txt +++ b/Source/WebKit/SourcesCocoa.txt @@ -268,6 +268,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 @@ -439,6 +440,7 @@ UIProcess/Inspector/ios/WKInspectorHighlightView.mm UIProcess/Inspector/ios/WKInspectorNodeSearchGestureRecognizer.mm UIProcess/Inspector/mac/RemoteWebInspectorUIProxyMac.mm +UIProcess/Inspector/mac/ScreencastEncoderMac.mm UIProcess/Inspector/mac/WebInspectorUIProxyMac.mm UIProcess/Inspector/mac/WKInspectorResourceURLSchemeHandler.mm UIProcess/Inspector/mac/WKInspectorViewController.mm diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt index a4391be7b637fd96d880cb06838b6deb5db552b6..3f7d5e6c9debc1cf1155da11bad14fc5c3b01dc8 100644 --- a/Source/WebKit/SourcesGTK.txt +++ b/Source/WebKit/SourcesGTK.txt @@ -125,6 +125,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 @@ -238,6 +239,7 @@ UIProcess/WebsiteData/unix/WebsiteDataStoreUnix.cpp UIProcess/cairo/BackingStoreCairo.cpp @no-unify +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/WebPageProxyGLib.cpp UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp @@ -254,6 +256,7 @@ UIProcess/gtk/ClipboardGtk3.cpp @no-unify UIProcess/gtk/ClipboardGtk4.cpp @no-unify UIProcess/gtk/WebDateTimePickerGtk.cpp UIProcess/gtk/HardwareAccelerationManager.cpp +UIProcess/gtk/InspectorTargetProxyGtk.cpp UIProcess/gtk/KeyBindingTranslator.cpp UIProcess/gtk/PointerLockManager.cpp @no-unify UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify @@ -266,6 +269,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 f8fb1511f2a019a08a896f7cbf45ca470da28185..eca7474a51db8dcf86fd4c538addd69633ffebe9 100644 --- a/Source/WebKit/SourcesWPE.txt +++ b/Source/WebKit/SourcesWPE.txt @@ -86,6 +86,7 @@ Shared/glib/ProcessExecutablePathGLib.cpp Shared/glib/UserMessage.cpp Shared/glib/WebContextMenuItemGlib.cpp +Shared/libwpe/ArgumentCodersWPE.cpp Shared/libwpe/NativeWebKeyboardEventLibWPE.cpp Shared/libwpe/NativeWebMouseEventLibWPE.cpp Shared/libwpe/NativeWebTouchEventLibWPE.cpp @@ -118,6 +119,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 @@ -182,6 +184,7 @@ UIProcess/API/wpe/InputMethodFilterWPE.cpp @no-unify UIProcess/API/wpe/PageClientImpl.cpp @no-unify UIProcess/API/wpe/TouchGestureController.cpp @no-unify UIProcess/API/wpe/WebKitColor.cpp @no-unify +UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.cpp @no-unify UIProcess/API/wpe/WebKitInputMethodContextWPE.cpp @no-unify UIProcess/API/wpe/WebKitPopupMenu.cpp @no-unify UIProcess/API/wpe/WebKitRectangle.cpp @no-unify @@ -198,6 +201,7 @@ UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp UIProcess/geoclue/GeoclueGeolocationProvider.cpp +UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp UIProcess/glib/WebPageProxyGLib.cpp UIProcess/glib/WebProcessPoolGLib.cpp UIProcess/glib/WebProcessProxyGLib.cpp @@ -220,6 +224,10 @@ UIProcess/linux/MemoryPressureMonitor.cpp UIProcess/soup/WebCookieManagerProxySoup.cpp UIProcess/soup/WebProcessPoolSoup.cpp +UIProcess/wpe/InspectorTargetProxyWPE.cpp +UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp +UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp + UIProcess/wpe/WebPageProxyWPE.cpp WebProcess/GPU/media/gstreamer/VideoLayerRemoteGStreamer.cpp @@ -248,6 +256,8 @@ WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp +WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp + WebProcess/WebCoreSupport/wpe/WebEditorClientWPE.cpp WebProcess/WebPage/AcceleratedSurface.cpp diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp index 95ffe0584caa71911dabce619d8429df55daece0..afd48bd8e3bc1ada31d6b2d1d84097f878bb36f5 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp @@ -54,6 +54,9 @@ Ref ProcessPoolConfiguration::copy() copy->m_attrStyleEnabled = this->m_attrStyleEnabled; copy->m_shouldThrowExceptionForGlobalConstantRedeclaration = this->m_shouldThrowExceptionForGlobalConstantRedeclaration; 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 fa69a4b457ee31cec78765e262b0af13fe40b87d..a0134fe49a4404f0441bfa8e8720273c6cad3835 100644 --- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h @@ -101,6 +101,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; } @@ -164,6 +169,9 @@ private: bool m_attrStyleEnabled { false }; bool m_shouldThrowExceptionForGlobalConstantRedeclaration { true }; 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 62a9bfce66229aff03d0cdfba216a309bd21c334..2ec448782ccf41f754b226e70f8674db1cc01170 100644 --- a/Source/WebKit/UIProcess/API/APIUIClient.h +++ b/Source/WebKit/UIProcess/API/APIUIClient.h @@ -94,6 +94,7 @@ public: virtual void runJavaScriptAlert(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(); } virtual void runJavaScriptConfirm(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(false); } virtual void runJavaScriptPrompt(WebKit::WebPageProxy&, const WTF::String&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function&& completionHandler) { completionHandler(WTF::String()); } + virtual void handleJavaScriptDialog(WebKit::WebPageProxy&, bool, const WTF::String&) { } virtual void setStatusText(WebKit::WebPageProxy*, const WTF::String&) { } virtual void mouseDidMoveOverElement(WebKit::WebPageProxy&, const WebKit::WebHitTestResultData&, OptionSet, Object*) { } diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.cpp b/Source/WebKit/UIProcess/API/C/WKInspector.cpp index e1465edd29caf3109c17d44bb3c88aaba98cfbb5..32d569d3240c583334b8b6512407430fd448ae75 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 "WebInspectorUIProxy.h" #include "WebPageProxy.h" @@ -130,4 +135,11 @@ void WKInspectorToggleElementSelection(WKInspectorRef inspectorRef) toImpl(inspectorRef)->toggleElementSelection(); } +void WKInspectorInitializeRemoteInspectorPipe(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit) +{ +#if PLATFORM(WIN) + initializeBrowserInspectorPipe(makeUnique(configureDataStore, createPage, quit)); +#endif +} + #endif // !PLATFORM(IOS_FAMILY) diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.h b/Source/WebKit/UIProcess/API/C/WKInspector.h index 026121d114c5fcad84c1396be8d692625beaa3bd..edd6e5cae033124c589959a42522fde07a42fdf6 100644 --- a/Source/WebKit/UIProcess/API/C/WKInspector.h +++ b/Source/WebKit/UIProcess/API/C/WKInspector.h @@ -66,6 +66,10 @@ WK_EXPORT void WKInspectorTogglePageProfiling(WKInspectorRef inspector); WK_EXPORT bool WKInspectorIsElementSelectionActive(WKInspectorRef inspector); WK_EXPORT void WKInspectorToggleElementSelection(WKInspectorRef inspector); +typedef void (*ConfigureDataStoreCallback)(WKWebsiteDataStoreRef dataStore); +typedef WKPageRef (*CreatePageCallback)(WKPageConfigurationRef configuration); +typedef void (*QuitCallback)(); +WK_EXPORT void WKInspectorInitializeRemoteInspectorPipe(ConfigureDataStoreCallback, CreatePageCallback, QuitCallback); #ifdef __cplusplus } #endif diff --git a/Source/WebKit/UIProcess/API/C/WKPage.cpp b/Source/WebKit/UIProcess/API/C/WKPage.cpp index 702efb299a41b013c856905e9e6b80262770afe1..657d69666f19aef2ac262408fa61283173994027 100644 --- a/Source/WebKit/UIProcess/API/C/WKPage.cpp +++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp @@ -1778,6 +1778,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) @@ -1838,6 +1845,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 ed980be17cdf9faec3f7af1bdc7cfd640bab8fc2..ca3c0ff1ec6d30173ae15e786f30ef1bad0e5bb6 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); @@ -1354,6 +1355,7 @@ typedef struct WKPageUIClientV14 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; } WKPageUIClientV14; typedef struct WKPageUIClientV15 { @@ -1461,6 +1463,7 @@ typedef struct WKPageUIClientV15 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; @@ -1572,6 +1575,7 @@ typedef struct WKPageUIClientV16 { // Version 14. WKPageRunWebAuthenticationPanelCallback runWebAuthenticationPanel; + WKPageHandleJavaScriptDialogCallback handleJavaScriptDialog; // Version 15. WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback decidePolicyForSpeechRecognitionPermissionRequest; diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h index 82003ea11098fa60e7ac7e2cdd29ea86154c7ccb..b0ebb2874de88f8e11c515d973b4e2cea160304a 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h +++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h @@ -135,6 +135,12 @@ typedef NS_ENUM(NSInteger, WKMediaCaptureType) { */ - (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; /*! @abstract A delegate to request permission for microphone audio and camera video access. @param webView The web view invoking the delegate method. diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h index afa925f36c29db9c23921298dead9cce737500d6..42d396342acdb6d39830f611df0ee40ea6ec879e 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 @@ -79,6 +78,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 672b2053442e7e834aa453c40d32c9d90701e103..3d49ea06d6cda6c274ef9c59c003a1275e916810 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm @@ -42,6 +42,7 @@ #import "_WKResourceLoadStatisticsThirdPartyInternal.h" #import "_WKWebsiteDataStoreConfigurationInternal.h" #import "_WKWebsiteDataStoreDelegate.h" +#import #import #import #import @@ -203,6 +204,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..5fabe06a3289689246c36dfd96eb9900a48b2b0f --- /dev/null +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@class WKWebView; + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserContext : NSObject +@property (nonatomic, strong) WKWebsiteDataStore *dataStore; +@property (nonatomic, strong) WKProcessPool *processPool; +@end + +@protocol _WKBrowserInspectorDelegate +- (WKWebView *)createNewPage:(uint64_t)sessionID; +- (_WKBrowserContext *)createBrowserContext:(NSString *)proxyServer WithBypassList:(NSString *)proxyBypassList; +- (void)deleteBrowserContext:(uint64_t)sessionID; +- (void)quit; +@end + +WK_CLASS_AVAILABLE(macos(10.14.0)) +@interface _WKBrowserInspector : NSObject ++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate headless:(BOOL)headless; +@end + + +NS_ASSUME_NONNULL_END + diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm new file mode 100644 index 0000000000000000000000000000000000000000..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/_WKDownload.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm index 0b32900879f73b9776f1bfbb6aec73c0553f7ac0..d3bac7b1130311c1094401b57c28b8f617d153aa 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKDownload.mm @@ -32,6 +32,7 @@ #import "WKFrameInfoInternal.h" #import "WKNSData.h" #import "WKWebViewInternal.h" +#import #import ALLOW_DEPRECATED_DECLARATIONS_BEGIN diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKDownloadInternal.h b/Source/WebKit/UIProcess/API/Cocoa/_WKDownloadInternal.h index ca94c2173757a54a0c755cbf30f8e05a0b75c9cb..422c1379da9b091ae5903a42bc7625be78030016 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKDownloadInternal.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKDownloadInternal.h @@ -24,6 +24,7 @@ */ #import "_WKDownload.h" +#import "WKObject.h" #import diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm index 46561d34314a79d42c57e59bf7927ad1fa451045..c84cbe9adc5236ad64240a18f5ff9a7215ba2ba2 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKInspectorExtension.mm @@ -24,7 +24,10 @@ */ #import "config.h" +#import "WKError.h" #import "_WKInspectorExtensionInternal.h" +#import +#import #if ENABLE(INSPECTOR_EXTENSIONS) diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h index 8a62271a7c58409835f1d7bfe993220207c85457..9500591716027a3a09bee5dc0608f64991b06ce5 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h @@ -65,6 +65,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 processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol WK_API_AVAILABLE(macos(12.0), ios(15.0)); diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm index e23314a2904c781ca23a9f8d906299740677759e..941d0b483bba4647a9b4b160e9c3c9a79b9c0494 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm @@ -245,6 +245,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 c130399cf9f3063f5a2dcc392e19eefd763c153a..3c10bb7e9dc8d9834b90a8d8faaac361f1268504 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKRemoteWebInspectorViewController.mm @@ -24,6 +24,7 @@ */ #import "config.h" +#import "WKWebViewPrivate.h" #import "_WKRemoteWebInspectorViewControllerInternal.h" #if PLATFORM(MAC) diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h index 4974e14214e2bb3e982325b885bab33e54f83998..cacdf8c71fab248d38d2faf03f7affdcfed1ef62 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h @@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN @class _WKUserContentWorld; @class WKContentWorld; @class WKWebView; +@class WKContentWorld; typedef NS_ENUM(NSInteger, _WKUserStyleLevel) { _WKUserStyleUserLevel, diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm index 1e827013c603ae8bd43d798170deb98fc3153852..2075bc78069bde530ec237c0b761773c10013948 100644 --- a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm +++ b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.mm @@ -35,6 +35,7 @@ #import "WebPageProxy.h" #import "_WKUserContentWorldInternal.h" #import +#import #import @implementation _WKUserStyleSheet diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp new file mode 100644 index 0000000000000000000000000000000000000000..54529a23f53cebe6f8a96873ca6c2f31f0481ae0 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebKitBrowserInspector.h" + +#include "BrowserInspectorPipe.h" +#include "InspectorPlaywrightAgentClientGLib.h" +#include "WebKitBrowserInspectorPrivate.h" +#include "WebKitWebViewPrivate.h" +#include +#include + +/** + * SECTION: WebKitBrowserInspector + * @Short_description: Access to the WebKit browser inspector + * @Title: WebKitBrowserInspector + * + * The WebKit Browser Inspector is an experimental API that provides + * access to the inspector via the remote debugging protocol. The protocol + * allows to create ephemeral contexts and create pages in them and then + * manipulate them using the inspector commands. This may be useful for + * the browser automation or remote debugging. + * + * Currently the protocol can be exposed to the parent process via a unix + * pipe. + */ + +enum { + CREATE_NEW_PAGE, + QUIT_APPLICATION, + + LAST_SIGNAL +}; + +struct _WebKitBrowserInspectorPrivate { + int unused { 0 }; +}; + +WEBKIT_DEFINE_TYPE(WebKitBrowserInspector, webkit_browser_inspector, G_TYPE_OBJECT) + +static guint signals[LAST_SIGNAL] = { 0, }; + +static void webkit_browser_inspector_class_init(WebKitBrowserInspectorClass* findClass) +{ + GObjectClass* gObjectClass = G_OBJECT_CLASS(findClass); + + /** + * WebKitBrowserInspector::create-new-page: + * @inspector: the #WebKitBrowserInspector on which the signal is emitted + * + * Emitted when the inspector is requested to create a new page in the provided + * #WebKitWebContext. + * + * This signal is emitted when inspector receives 'Browser.createPage' command + * from its remote client. If the signal is not handled the command will fail. + * + * Returns: %WebKitWebView that contains created page. + */ + signals[CREATE_NEW_PAGE] = g_signal_new( + "create-new-page", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitBrowserInspectorClass, create_new_page), + nullptr, nullptr, + g_cclosure_marshal_generic, +#if PLATFORM(GTK) + GTK_TYPE_WIDGET, +#else + WEBKIT_TYPE_WEB_VIEW, +#endif + 1, + WEBKIT_TYPE_WEB_CONTEXT); + + /** + * WebKitBrowserInspector::quit-application: + * @inspector: the #WebKitBrowserInspector on which the signal is emitted + * + * Emitted when the inspector is requested to close the browser application. + * + * This signal is emitted when inspector receives 'Browser.close' command + * from its remote client. If the signal is not handled the command will fail. + */ + signals[QUIT_APPLICATION] = g_signal_new( + "quit-application", + G_TYPE_FROM_CLASS(gObjectClass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(WebKitBrowserInspectorClass, quit_application), + nullptr, nullptr, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext* context) +{ + WebKitWebView* newWebView; + g_signal_emit(webkit_browser_inspector_get_default(), signals[CREATE_NEW_PAGE], 0, context, &newWebView); + if (!newWebView) + return nullptr; + return &webkitWebViewGetPage(newWebView); +} + +void webkitBrowserInspectorQuitApplication() +{ + g_signal_emit(webkit_browser_inspector_get_default(), signals[QUIT_APPLICATION], 0, NULL); +} + +static gpointer createWebKitBrowserInspector(gpointer) +{ + static GRefPtr browserInspector = adoptGRef(WEBKIT_BROWSER_INSPECTOR(g_object_new(WEBKIT_TYPE_BROWSER_INSPECTOR, nullptr))); + return browserInspector.get(); +} + +/** + * webkit_browser_inspector_get_default: + * + * Gets the default instance of the browser inspector. + * + * Returns: (transfer none): a #WebKitBrowserInspector + */ +WebKitBrowserInspector* webkit_browser_inspector_get_default(void) +{ + static GOnce onceInit = G_ONCE_INIT; + return WEBKIT_BROWSER_INSPECTOR(g_once(&onceInit, createWebKitBrowserInspector, 0)); +} + +/** + * webkit_browser_inspector_initialize_pipe: + * + * Creates browser inspector and configures pipe handler to communicate with + * the parent process. + */ +void webkit_browser_inspector_initialize_pipe(const char* defaultProxyURI, const char* const* ignoreHosts) +{ + WebKit::initializeBrowserInspectorPipe(makeUnique(defaultProxyURI, ignoreHosts)); +} diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h new file mode 100644 index 0000000000000000000000000000000000000000..e0b1da48465c850f541532ed961d1b778bea6028 --- /dev/null +++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "WebKitBrowserInspector.h" +#include "WebPageProxy.h" + +WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext*); +void webkitBrowserInspectorQuitApplication(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp index 0afd97be464ceb609f1c43aa720f3b4c297778bd..0826356fe6d35615e9b2c84647dfe3dadab73eb1 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp @@ -98,6 +98,10 @@ private: page.makeViewBlankIfUnpaintedSinceLastLoadCommit(); webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTFMove(completionHandler)); } + void handleJavaScriptDialog(WebPageProxy&, bool accept, const String& value) final + { + webkitWebViewHandleJavaScriptDialog(m_webView, accept, value); + } bool canRunBeforeUnloadConfirmPanel() const final { return true; } diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp index 6dd9f20e4ff2bda0184d0645301cef22e47dcf15..7a5f57daa83818b2dfb4bcbcbf5c18c8621a6b25 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp @@ -118,8 +118,8 @@ enum { PROP_LOCAL_STORAGE_DIRECTORY, #endif PROP_WEBSITE_DATA_MANAGER, -#if PLATFORM(GTK) PROP_PSON_ENABLED, +#if PLATFORM(GTK) #if !USE(GTK4) PROP_USE_SYSTEM_APPEARANCE_FOR_SCROLLBARS, #endif @@ -207,8 +207,8 @@ struct _WebKitWebContextPrivate { RefPtr processPool; bool clientsDetached; -#if PLATFORM(GTK) bool psonEnabled; +#if PLATFORM(GTK) #if !USE(GTK4) bool useSystemAppearanceForScrollbars; #endif @@ -307,11 +307,9 @@ WEBKIT_DEFINE_TYPE(WebKitWebContext, webkit_web_context, G_TYPE_OBJECT) static const char* injectedBundleDirectory() { -#if ENABLE(DEVELOPER_MODE) const char* bundleDirectory = g_getenv("WEBKIT_INJECTED_BUNDLE_PATH"); if (bundleDirectory && g_file_test(bundleDirectory, G_FILE_TEST_IS_DIR)) return bundleDirectory; -#endif #if PLATFORM(GTK) static const char* injectedBundlePath = LIBDIR G_DIR_SEPARATOR_S "webkit2gtk-" WEBKITGTK_API_VERSION_STRING @@ -336,10 +334,10 @@ 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; +#if PLATFORM(GTK) #if !USE(GTK4) case PROP_USE_SYSTEM_APPEARANCE_FOR_SCROLLBARS: g_value_set_boolean(value, webkit_web_context_get_use_system_appearance_for_scrollbars(context)); @@ -366,10 +364,10 @@ 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; +#if PLATFORM(GTK) #if !USE(GTK4) case PROP_USE_SYSTEM_APPEARANCE_FOR_SCROLLBARS: webkit_web_context_set_use_system_appearance_for_scrollbars(context, g_value_get_boolean(value)); @@ -381,10 +379,19 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa } } +static int webkitWebContext = 0; + +int webkitWebContextExistingCount() +{ + return webkitWebContext; +} + static void webkitWebContextConstructed(GObject* object) { G_OBJECT_CLASS(webkit_web_context_parent_class)->constructed(object); + ++webkitWebContext; + GUniquePtr bundleFilename(g_build_filename(injectedBundleDirectory(), INJECTED_BUNDLE_FILENAME, nullptr)); WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(object); @@ -393,8 +400,8 @@ static void webkitWebContextConstructed(GObject* object) API::ProcessPoolConfiguration configuration; configuration.setInjectedBundlePath(FileSystem::stringFromFileSystemRepresentation(bundleFilename.get())); configuration.setUsesWebProcessCache(true); -#if PLATFORM(GTK) configuration.setProcessSwapsOnNavigation(priv->psonEnabled); +#if PLATFORM(GTK) #if !USE(GTK4) configuration.setUseSystemAppearanceForScrollbars(priv->useSystemAppearanceForScrollbars); #endif @@ -431,6 +438,8 @@ static void webkitWebContextConstructed(GObject* object) static void webkitWebContextDispose(GObject* object) { + --webkitWebContext; + WebKitWebContextPrivate* priv = WEBKIT_WEB_CONTEXT(object)->priv; if (!priv->clientsDetached) { priv->clientsDetached = true; @@ -499,7 +508,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: * @@ -521,6 +529,7 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass FALSE, static_cast(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); +#if PLATFORM(GTK) #if !USE(GTK4) /** * WebKitWebContext:use-system-appearance-for-scrollbars: diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h index 78d1578f94793e9e59a3d4d2b33e79ea8530fa04..493cdadac3873508b3efa3048638e73a13f4c976 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h @@ -45,3 +45,4 @@ void webkitWebContextInitializeNotificationPermissions(WebKitWebContext*); #if ENABLE(REMOTE_INSPECTOR) void webkitWebContextWillCloseAutomationSession(WebKitWebContext*); #endif +int webkitWebContextExistingCount(); diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp index d93eab93a79bbe3005a510224798ff9956c9ae19..52de3373ce0353e9d7dc3e3d7a2d85f3643c8593 100644 --- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp +++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp @@ -32,6 +32,7 @@ #include "WebCertificateInfo.h" #include "WebContextMenuItem.h" #include "WebContextMenuItemData.h" +#include "WebPageInspectorController.h" #include "WebKitAuthenticationRequestPrivate.h" #include "WebKitBackForwardListPrivate.h" #include "WebKitContextMenuClient.h" @@ -133,6 +134,7 @@ enum { CLOSE, SCRIPT_DIALOG, + SCRIPT_DIALOG_HANDLED, DECIDE_POLICY, PERMISSION_REQUEST, @@ -445,6 +447,9 @@ void WebKitWebViewClient::handleDownloadRequest(WKWPE::View&, DownloadProxy& dow void WebKitWebViewClient::frameDisplayed(WKWPE::View&) { + if (RefPtr surface = adoptRef(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get()))) + getPage(m_webView).inspectorController().didPaint(surface.get()); + { SetForScope inFrameDisplayedGuard(m_webView->priv->inFrameDisplayed, true); for (const auto& callback : m_webView->priv->frameDisplayedCallbacks) { @@ -475,6 +480,7 @@ void WebKitWebViewClient::didReceiveUserMessage(WKWPE::View&, UserMessage&& mess { webkitWebViewDidReceiveUserMessage(m_webView, WTFMove(message), WTFMove(completionHandler)); } + #endif static gboolean webkitWebViewLoadFail(WebKitWebView* webView, WebKitLoadEvent, const char* failingURI, GError* error) @@ -1609,6 +1615,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 @@ -2441,6 +2456,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const webkit_script_dialog_unref(webView->priv->currentScriptDialog); } +void webkitWebViewHandleJavaScriptDialog(WebKitWebView* webView, bool accept, const String& value) { + auto* dialog = webView->priv->currentScriptDialog; +#if PLATFORM(WPE) + dialog->isUserHandled = false; +#endif + webkit_script_dialog_ref(dialog); + if (!value.isNull()) + webkitWebViewSetCurrentScriptDialogUserInput(webView, value); + if (accept) + webkitWebViewAcceptCurrentScriptDialog(webView); + else + webkitWebViewDismissCurrentScriptDialog(webView); + gboolean returnValue; + g_signal_emit(webView, signals[SCRIPT_DIALOG_HANDLED], 0, dialog, &returnValue); + webkit_script_dialog_unref(dialog); +} + bool webkitWebViewIsShowingScriptDialog(WebKitWebView* webView) { if (!webView->priv->currentScriptDialog) diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h index d7a43204be693f2a7ef86240eaf567fe70052a2c..0e247c48858522e55f65957fd0d1e147cafce092 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 26340c991097a452783c8d4b31bb2cfdfe0bc71f..0becf018fa83c21f71ca59070f29337d35a1299b 100644 --- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp @@ -245,6 +245,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool { if (wasEventHandled || event.type() != WebEvent::Type::KeyDown || !event.nativeEvent()) 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..9f1a0173a5641d6f158d815b8f7b9ea66f65c26d --- /dev/null +++ b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(__WEBKIT2_H_INSIDE__) && !defined(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); + WebKitWebView *(* quit_application) (WebKitBrowserInspector *browser_inspector); + + void (*_webkit_reserved0) (void); + void (*_webkit_reserved1) (void); + void (*_webkit_reserved2) (void); + void (*_webkit_reserved3) (void); +}; + +WEBKIT_API GType +webkit_browser_inspector_get_type (void); + +WEBKIT_API WebKitBrowserInspector * +webkit_browser_inspector_get_default (void); + +WEBKIT_API void +webkit_browser_inspector_initialize_pipe (const char* defaultProxyURI, + const char* const* ignoreHosts); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp index 5b077d94407877794a3e5913dbd9f87f71cc9586..ef311b312be7decd0f207de61ce35ea7d5b860d0 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -2489,6 +2489,11 @@ void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase) #endif } +WebKit::AcceleratedBackingStore* webkitWebViewBaseGetAcceleratedBackingStore(WebKitWebViewBase* webkitWebViewBase) +{ + return webkitWebViewBase->priv->acceleratedBackingStore.get(); +} + void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext) { ASSERT(webkitWebViewBase->priv->acceleratedBackingStore); diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h index d28f9c69cabe96554daddfec77e6f007aa0987da..ece01f3d3e2f6aaca191975048320b6a91b946ea 100644 --- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h +++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h @@ -27,6 +27,7 @@ #pragma once +#include "AcceleratedBackingStore.h" #include "APIPageConfiguration.h" #include "InputMethodState.h" #include "SameDocumentNavigationType.h" @@ -117,3 +118,5 @@ void webkitWebViewBaseSynthesizeCompositionKeyPress(WebKitWebViewBase*, const St void webkitWebViewBaseMakeBlank(WebKitWebViewBase*, bool); void webkitWebViewBasePageGrabbedTouch(WebKitWebViewBase*); void webkitWebViewBaseSetShouldNotifyFocusEvents(WebKitWebViewBase*, bool); + +WebKit::AcceleratedBackingStore* webkitWebViewBaseGetAcceleratedBackingStore(WebKitWebViewBase*); diff --git a/Source/WebKit/UIProcess/API/gtk/webkit2.h b/Source/WebKit/UIProcess/API/gtk/webkit2.h index ecbe433ed888353b1e6013943b4463835c3582d2..7385877fe664515814fc5c3380a2b7298ff90e1e 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/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp index 9631a3f19d24c29286ab634c0bd65cfbc83f9334..15c2813f21b419fc9067ae88231de2b12829c38f 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp @@ -34,6 +34,7 @@ #include "WPEView.h" #include "WebContextMenuProxy.h" #include "WebContextMenuProxyWPE.h" +#include "WebKitDataListSuggestionsDropdown.h" #include "WebKitPopupMenu.h" #include #include @@ -194,7 +195,7 @@ WebCore::IntPoint PageClientImpl::accessibilityScreenToRootView(const WebCore::I WebCore::IntRect PageClientImpl::rootViewToAccessibilityScreen(const WebCore::IntRect& rect) { - return rootViewToScreen(rect); + return rootViewToScreen(rect); } void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool) @@ -446,4 +447,11 @@ void PageClientImpl::selectionDidChange() m_view.selectionDidChange(); } +#if ENABLE(DATALIST_ELEMENT) +RefPtr PageClientImpl::createDataListSuggestionsDropdown(WebKit::WebPageProxy& page) +{ + return WebKitDataListSuggestionsDropdown::create(page); +} +#endif + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h index 8ab8db715db64616a15a06bb2b4760a40ad5f254..0307a117cbd5c4fb767c4905e9e3370efd5ebf9a 100644 --- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h +++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h @@ -166,6 +166,10 @@ private: void selectionDidChange() override; +#if ENABLE(DATALIST_ELEMENT) + RefPtr createDataListSuggestionsDropdown(WebKit::WebPageProxy& page) override; +#endif + WKWPE::View& m_view; }; diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h new file mode 100644 index 0000000000000000000000000000000000000000..cb1a540d341b07581ec87b922b7d007ce45ba989 --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(__WEBKIT_H_INSIDE__) && !defined(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); + WebKitWebView *(* quit_application) (WebKitBrowserInspector *browser_inspector); + + void (*_webkit_reserved0) (void); + void (*_webkit_reserved1) (void); + void (*_webkit_reserved2) (void); + void (*_webkit_reserved3) (void); +}; + +WEBKIT_API GType +webkit_browser_inspector_get_type (void); + +WEBKIT_API WebKitBrowserInspector * +webkit_browser_inspector_get_default (void); + +WEBKIT_API void +webkit_browser_inspector_initialize_pipe (const char* defaultProxyURI, + const char* const* ignoreHosts); + +G_END_DECLS + +#endif diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.cpp b/Source/WebKit/UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afafef2b7fb433e006b1763e653e200bc80edcbd --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebKitDataListSuggestionsDropdown.h" + +#if ENABLE(DATALIST_ELEMENT) + +#include "WebPageProxy.h" + +namespace WebKit { + +WebKitDataListSuggestionsDropdown::WebKitDataListSuggestionsDropdown(WebPageProxy& page) + : WebDataListSuggestionsDropdown(page) +{ +} + +WebKitDataListSuggestionsDropdown::~WebKitDataListSuggestionsDropdown() +{ +} + +void WebKitDataListSuggestionsDropdown::show(WebCore::DataListSuggestionInformation&& information) +{ +} + +void WebKitDataListSuggestionsDropdown::handleKeydownWithIdentifier(const String& key) +{ +} + +void WebKitDataListSuggestionsDropdown::close() +{ +} + +} // namespace WebKit + +#endif // ENABLE(DATALIST_ELEMENT) diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.h b/Source/WebKit/UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.h new file mode 100644 index 0000000000000000000000000000000000000000..0a099832c3dd959f456fcae49a1d62a9477d2758 --- /dev/null +++ b/Source/WebKit/UIProcess/API/wpe/WebKitDataListSuggestionsDropdown.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(DATALIST_ELEMENT) + +#include "WebDataListSuggestionsDropdown.h" + +namespace WebKit { + +class WebPageProxy; + +class WebKitDataListSuggestionsDropdown final : public WebDataListSuggestionsDropdown { +public: + static Ref create(WebPageProxy& page) + { + return adoptRef(*new WebKitDataListSuggestionsDropdown(page)); + } + + ~WebKitDataListSuggestionsDropdown(); + +private: + WebKitDataListSuggestionsDropdown(WebPageProxy&); + + void show(WebCore::DataListSuggestionInformation&&) final; + void handleKeydownWithIdentifier(const String&) final; + void close() final; +}; + +} // namespace WebKit + +#endif // ENABLE(DATALIST_ELEMENT) diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp index e0fc205b39095cf8aae201a1dcca520461c60de4..872186ad99a7b82f0c61705ff6c5ae4453e5e1d4 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp @@ -54,6 +54,7 @@ struct _WebKitWebViewBackend { struct wpe_view_backend* backend; GDestroyNotify notifyCallback; gpointer notifyCallbackData; + take_screenshot_callback screenshotCallback; int referenceCount { 1 }; }; @@ -116,6 +117,19 @@ struct wpe_view_backend* webkit_web_view_backend_get_wpe_backend(WebKitWebViewBa return viewBackend->backend; } +void webkit_web_view_backend_set_screenshot_callback(WebKitWebViewBackend *view_backend, take_screenshot_callback callback) +{ + view_backend->screenshotCallback = callback; +} + +cairo_surface_t* webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend* view_backend) +{ + if (!view_backend->screenshotCallback) + return nullptr; + + return view_backend->screenshotCallback(view_backend->notifyCallbackData); +} + namespace WTF { template <> WebKitWebViewBackend* refGPtr(WebKitWebViewBackend* ptr) diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h index 6663964d5abac79e123d90e0351590884c66aa72..13ba5e7c3895c6e4efda95f1f90b9baea1c1bf30 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h @@ -27,6 +27,7 @@ #include #include #include +#include G_BEGIN_DECLS @@ -44,6 +45,12 @@ webkit_web_view_backend_new (struct wpe_view_backend *backend, WEBKIT_API struct wpe_view_backend * webkit_web_view_backend_get_wpe_backend (WebKitWebViewBackend *view_backend); +typedef cairo_surface_t* (*take_screenshot_callback)(gpointer user_data); + +WEBKIT_API void +webkit_web_view_backend_set_screenshot_callback (WebKitWebViewBackend *view_backend, + take_screenshot_callback callback); + G_END_DECLS #endif /* WebKitWebViewBackend_h */ diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h index e4b92ace1531090ae38a7aec3d3d4febf19aee84..43690f9ef4969a39084501613bfc00a77fd5df49 100644 --- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h +++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h @@ -31,3 +31,5 @@ template <> void derefGPtr(WebKitWebViewBackend* ptr); } void webkitWebViewBackendUnref(WebKitWebViewBackend*); + +cairo_surface_t* webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend*); diff --git a/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt b/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt index 8cf9d4ff38382b3d348a732d69d00e7720576777..052e75a649f49ca8704d013a03299fd4aca68fa1 100644 --- a/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt +++ b/Source/WebKit/UIProcess/API/wpe/docs/wpe-1.0-sections.txt @@ -320,6 +320,8 @@ WEBKIT_TYPE_WEB_VIEW_BACKEND WebKitWebViewBackend webkit_web_view_backend_get_wpe_backend webkit_web_view_backend_new +take_screenshot_callback +webkit_web_view_backend_set_screenshot_callback webkit_web_view_backend_get_type diff --git a/Source/WebKit/UIProcess/API/wpe/webkit.h b/Source/WebKit/UIProcess/API/wpe/webkit.h index 87929257bf73aba684a380accd8c1bbb394bad87..5d47bce94b6d4b9e54fc1fef794bde7506310e32 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/BackingStore.h b/Source/WebKit/UIProcess/BackingStore.h index fe3c63e61f778762dc2c2080c74ec53fdf8c2e5f..c43a8226c9be702e248f1712e465efa396ee8969 100644 --- a/Source/WebKit/UIProcess/BackingStore.h +++ b/Source/WebKit/UIProcess/BackingStore.h @@ -60,6 +60,7 @@ public: #if USE(CAIRO) typedef cairo_t* PlatformGraphicsContext; + cairo_surface_t* surface() const; #elif USE(DIRECT2D) struct DXConnections { ID3D11DeviceContext1* immediateContext { nullptr }; diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cfb57a48ce387b79613b757e2eb4de2c378aac30 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "BrowserInspectorPipe.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include "InspectorPlaywrightAgentClient.h" +#include "RemoteInspectorPipe.h" +#include "WebKit2Initialize.h" +#include + +namespace WebKit { + +void initializeBrowserInspectorPipe(std::unique_ptr client) +{ + // Initialize main loop before creating inspecor agent and pipe queues. + WebKit::InitializeWebKit2(); + + class BrowserInspectorPipe { + public: + BrowserInspectorPipe(std::unique_ptr client) + : m_playwrightAgent(std::move(client)) + , m_remoteInspectorPipe(m_playwrightAgent) + { + } + + InspectorPlaywrightAgent m_playwrightAgent; + RemoteInspectorPipe m_remoteInspectorPipe; + }; + + static NeverDestroyed pipe(std::move(client)); +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.h b/Source/WebKit/UIProcess/BrowserInspectorPipe.h new file mode 100644 index 0000000000000000000000000000000000000000..cd66887de171cda7d15a8e4dc6dbff63665dc619 --- /dev/null +++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +namespace WebKit { + +class InspectorPlaywrightAgentClient; + +void initializeBrowserInspectorPipe(std::unique_ptr client); + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/Cocoa/AutomationClient.mm b/Source/WebKit/UIProcess/Cocoa/AutomationClient.mm index 02dadcc4c813ad82c718f16a583616e03e35a195..5211c6b38efaf2a62eb556ec060cd9caa5e5d40e 100644 --- a/Source/WebKit/UIProcess/Cocoa/AutomationClient.mm +++ b/Source/WebKit/UIProcess/Cocoa/AutomationClient.mm @@ -35,6 +35,7 @@ #import #import #import +#import using namespace Inspector; 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/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h index 849900649a2c6ee11595d743de5a1e6f188f48e7..d202e9374ad408c6621a318111266e4e9a54dae8 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h @@ -94,6 +94,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; @@ -185,6 +186,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 388429087a1a368a52d5983ed865b61373b33996..1eaaabd4ab0ce7c321c64e6ed55c73320f9f2d50 100644 --- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm +++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm @@ -106,6 +106,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.webViewRequestGeolocationPermissionForOriginDecisionHandler = [delegate respondsToSelector:@selector(_webView:requestGeolocationPermissionForOrigin:initiatedByFrame:decisionHandler:)]; @@ -378,6 +379,15 @@ void UIDelegate::UIClient::runJavaScriptPrompt(WebPageProxy& page, const WTF::St }).get()]; } +void UIDelegate::UIClient::handleJavaScriptDialog(WebKit::WebPageProxy&, bool accept, const WTF::String& value) { + if (!m_uiDelegate->m_delegateMethods.webViewHandleJavaScriptDialogValue) + return; + auto delegate = m_uiDelegate->m_delegate.get(); + if (!delegate) + return; + [delegate webView:m_uiDelegate->m_webView.get().get() handleJavaScriptDialog:accept value:value]; +} + void UIDelegate::UIClient::requestStorageAccessConfirm(WebPageProxy& webPageProxy, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, CompletionHandler&& completionHandler) { if (!m_uiDelegate) diff --git a/Source/WebKit/UIProcess/Cocoa/WKContactPicker.h b/Source/WebKit/UIProcess/Cocoa/WKContactPicker.h index 7a18a6184a04aa37bb6d328a817b0a0a3e03cb50..92bb58f42cf5ff592b6d465f16ffcf283f381462 100644 --- a/Source/WebKit/UIProcess/Cocoa/WKContactPicker.h +++ b/Source/WebKit/UIProcess/Cocoa/WKContactPicker.h @@ -27,6 +27,7 @@ #if HAVE(CONTACTSUI) +#include #include @class WKWebView; diff --git a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm index cfa56853fe99116fbfefd5e33933c80967703de1..e0c81fdda03199d968a405cd91ae41665872aef7 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm @@ -34,6 +34,7 @@ #import "InsertTextOptions.h" #import "LoadParameters.h" #import "PageClient.h" +#import "PasteboardTypes.h" #import "QuickLookThumbnailLoader.h" #import "SafeBrowsingSPI.h" #import "SafeBrowsingWarning.h" @@ -224,9 +225,66 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting() void WebPageProxy::startDrag(const DragItem& dragItem, const ShareableBitmap::Handle& dragImageHandle) { + if (m_interceptDrags) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName: m_overrideDragPasteboardName]; + + m_dragSelectionData = String([pasteboard name]); + grantAccessToCurrentPasteboardData(String([pasteboard name])); + m_dragSourceOperationMask = WebCore::anyDragOperation(); + + if (auto& info = dragItem.promisedAttachmentInfo) { + auto attachment = attachmentForIdentifier(info.attachmentIdentifier); + if (!attachment) { + dragCancelled(); + return; + } + NSString *utiType = attachment->utiType(); + if (!utiType.length) { + dragCancelled(); + return; + } + + ASSERT(info.additionalTypes.size() == info.additionalData.size()); + if (info.additionalTypes.size() == info.additionalData.size()) { + for (size_t index = 0; index < info.additionalTypes.size(); ++index) { + auto nsData = info.additionalData[index]->createNSData(); + [pasteboard setData:nsData.get() forType:info.additionalTypes[index]]; + } + } + } else { + [pasteboard setString:@"" forType:PasteboardTypes::WebDummyPboardType]; + } + didStartDrag(); + return; + } + pageClient().startDrag(dragItem, dragImageHandle); } +void WebPageProxy::releaseInspectorDragPasteboard() { + if (!!m_dragSelectionData) + m_dragSelectionData = std::nullopt; + if (!m_overrideDragPasteboardName.isEmpty()) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; + [pasteboard releaseGlobally]; + m_overrideDragPasteboardName = ""; + } +} + + +void WebPageProxy::setInterceptDrags(bool shouldIntercept) { + m_interceptDrags = shouldIntercept; + if (m_interceptDrags) { + if (m_overrideDragPasteboardName.isEmpty()) { + NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName]; + m_overrideDragPasteboardName = String([pasteboard name]); + } + send(Messages::WebPage::SetDragPasteboardName(m_overrideDragPasteboardName)); + } else { + send(Messages::WebPage::SetDragPasteboardName("")); + } +} + // FIXME: Move these functions to WebPageProxyIOS.mm. #if PLATFORM(IOS_FAMILY) diff --git a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm index b05fc82bd0d7201418dd69ea47158954cf25f0f4..b5d4e6f170309ca2e687f067fae9aa309f27bec6 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm @@ -408,7 +408,7 @@ void WebProcessPool::platformInitializeWebProcess(const WebProcessProxy& process auto screenProperties = WebCore::collectScreenProperties(); parameters.screenProperties = WTFMove(screenProperties); #if PLATFORM(MAC) - parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); + parameters.useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); #endif #if PLATFORM(IOS) @@ -692,8 +692,8 @@ void WebProcessPool::registerNotificationObservers() }]; m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { - auto scrollbarStyle = [NSScroller preferredScrollerStyle]; - sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(scrollbarStyle)); + bool useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay); + sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(useOverlayScrollbars)); }]; m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) { diff --git a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h index 82e3828037b064f5bd36b7dd536c60a0a2933aa0..074a542e01e838e244ea82f0f559056e52d221b1 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h +++ b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h @@ -513,6 +513,9 @@ public: void provideDataForPasteboard(NSPasteboard *, NSString *type); NSArray *namesOfPromisedFilesDroppedAtDestination(NSURL *dropDestination); +// Paywright begin + RetainPtr takeSnapshotForAutomation(); +// Paywright end RefPtr takeViewSnapshot(); void saveBackForwardSnapshotForCurrentItem(); void saveBackForwardSnapshotForItem(WebBackForwardListItem&); diff --git a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm index 5fbeba4f16e31677eb1dfeda2096387fc64da6cc..89ca92c286e92e2fc82224e694f8606b5f1338bc 100644 --- a/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm +++ b/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm @@ -2607,6 +2607,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace() if (!m_colorSpace) m_colorSpace = [NSColorSpace sRGBColorSpace]; } + // Playwright begin + // window.colorSpace is sometimes null on popup windows in headless mode + if (!m_colorSpace) + return DestinationColorSpace::SRGB(); + // Playwright end ASSERT(m_colorSpace); return WebCore::DestinationColorSpace { [m_colorSpace CGColorSpace] }; @@ -4685,6 +4690,18 @@ static RetainPtr takeWindowSnapshot(CGSWindowID windowID, bool captu return adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions)); } +// Paywright begin +RetainPtr WebViewImpl::takeSnapshotForAutomation() { + NSWindow *window = [m_view window]; + + CGSWindowID windowID = (CGSWindowID)window.windowNumber; + if (!windowID || !window.isVisible) + return nullptr; + + return takeWindowSnapshot(windowID, true); +} +// Paywright end + RefPtr WebViewImpl::takeViewSnapshot() { NSWindow *window = [m_view window]; diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp index 038d9ee2f41cdeba4ae7b597311b663a58b6d629..5be10b7bbdc8b28db255baf7a4187cfd761fa83d 100644 --- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp +++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp @@ -32,13 +32,16 @@ #include "DrawingAreaProxyMessages.h" #include "LayerTreeContext.h" #include "UpdateInfo.h" +#include "WebPageInspectorController.h" #include "WebPageProxy.h" #include "WebPreferences.h" #include "WebProcessProxy.h" #include #include +#include #if PLATFORM(GTK) +#include "WebKitWebViewBasePrivate.h" #include #endif @@ -51,6 +54,13 @@ #include #endif +#if PLATFORM(WIN) +#include +#include +#include +#include +#endif + namespace WebKit { using namespace WebCore; @@ -119,6 +129,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 +147,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange() backingStoreStateDidChange(RespondImmediately); } +void DrawingAreaProxyCoordinatedGraphics::waitForSizeUpdate(Function&& callback) +{ + m_callbacks.append(WTFMove(callback)); +} + void DrawingAreaProxyCoordinatedGraphics::waitForBackingStoreUpdateOnNextPaint() { m_hasReceivedFirstUpdate = true; @@ -250,6 +269,45 @@ void DrawingAreaProxyCoordinatedGraphics::updateAcceleratedCompositingMode(uint6 updateAcceleratedCompositingMode(layerTreeContext); } +#if PLATFORM(WIN) +void DrawingAreaProxyCoordinatedGraphics::didChangeAcceleratedCompositingMode(bool enabled) +{ + m_isInAcceleratedCompositingMode = enabled; +} +#endif + +#if !PLATFORM(WPE) +void DrawingAreaProxyCoordinatedGraphics::captureFrame() +{ + RefPtr surface; +#if PLATFORM(WIN) + HWndDC dc; + if (m_isInAcceleratedCompositingMode) { + dc.setHWnd(m_webPageProxy.viewWidget()); + surface = adoptRef(cairo_win32_surface_create(dc)); +#else + if (isInAcceleratedCompositingMode()) { +# if PLATFORM(GTK) + AcceleratedBackingStore* backingStore = webkitWebViewBaseGetAcceleratedBackingStore(WEBKIT_WEB_VIEW_BASE(m_webPageProxy.viewWidget())); + if (!backingStore) + return; + + surface = backingStore->surface(); +# else + fprintf(stderr, "captureFrame() is not supported in accelerated compositing mode on this platform.\n"); +# endif +#endif + } else if (m_backingStore) { + surface = m_backingStore->surface(); + } + + if (!surface) + return; + + m_webPageProxy.inspectorController().didPaint(surface.get()); +} +#endif + #if !PLATFORM(WPE) void DrawingAreaProxyCoordinatedGraphics::incorporateUpdate(const UpdateInfo& updateInfo) { diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h index b23a45ff7d313317d8ba64fb430ebba3b6adef71..8419b69c5e278cf88a3ab6b98c335eddeea44e53 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,10 @@ public: bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); } const LayerTreeContext& layerTreeContext() const { return m_layerTreeContext; } + void waitForSizeUpdate(Function&&); +#if !PLATFORM(WPE) + void captureFrame(); +#endif private: // DrawingAreaProxy @@ -68,6 +73,9 @@ private: void enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) override; void exitAcceleratedCompositingMode(uint64_t backingStoreStateID, const UpdateInfo&) override; void updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) override; +#if PLATFORM(WIN) + void didChangeAcceleratedCompositingMode(bool enabled) override; +#endif #if !PLATFORM(WPE) void incorporateUpdate(const UpdateInfo&); @@ -131,12 +139,18 @@ 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; RunLoop::Timer m_discardBackingStoreTimer; #endif std::unique_ptr m_drawingMonitor; + +#if PLATFORM(WIN) + bool m_isInAcceleratedCompositingMode { false }; +#endif }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp index c61bb3fd2ee046f3824c40ab99181c0fcee2a197..c0cf2a03b51dc58d76b1cf7e9d7c3fffdc264836 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp @@ -42,8 +42,10 @@ #include #include #include +#include #include #include +#include namespace WebKit { using namespace WebCore; @@ -56,7 +58,10 @@ DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebsiteDataStor , m_request(resourceRequest) , m_originatingPage(makeWeakPtr(originatingPage)) , m_frameInfo(API::FrameInfo::create(FrameInfoData { frameInfoData }, originatingPage)) + , m_uuid(createCanonicalUUIDString()) { + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadCreated(m_uuid, m_request, frameInfoData, originatingPage, this); } DownloadProxy::~DownloadProxy() @@ -75,9 +80,12 @@ static RefPtr createData(const IPC::DataReference& data) void DownloadProxy::cancel(CompletionHandler&& completionHandler) { if (m_dataStore) { - m_dataStore->networkProcess().sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (const IPC::DataReference& resumeData) mutable { + auto* instrumentation = m_dataStore->downloadInstrumentation(); + m_dataStore->networkProcess().sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler), instrumentation] (const IPC::DataReference& resumeData) mutable { m_legacyResumeData = createData(resumeData); completionHandler(m_legacyResumeData.get()); + if (instrumentation) + instrumentation->downloadFinished(m_uuid, "canceled"_s); m_downloadProxyMap.downloadFinished(*this); }); } else @@ -161,6 +169,20 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour suggestedFilename = m_suggestedFilename; suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType()); + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFilenameSuggested(m_uuid, suggestedFilename); + + if (m_dataStore->allowDownloadForAutomation()) { + SandboxExtension::Handle sandboxExtensionHandle; + String destination; + if (*m_dataStore->allowDownloadForAutomation()) { + destination = FileSystem::pathByAppendingComponent(m_dataStore->downloadPathForAutomation(), m_uuid); + SandboxExtension::createHandle(destination, SandboxExtension::Type::ReadWrite, sandboxExtensionHandle); + } + completionHandler(destination, WTFMove(sandboxExtensionHandle), AllowOverwrite::Yes); + return; + } + m_client->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable { SandboxExtension::Handle sandboxExtensionHandle; if (!destination.isNull()) @@ -179,6 +201,8 @@ void DownloadProxy::didCreateDestination(const String& path) void DownloadProxy::didFinish() { m_client->didFinish(*this); + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFinished(m_uuid, String()); // This can cause the DownloadProxy object to be deleted. m_downloadProxyMap.downloadFinished(*this); @@ -189,6 +213,8 @@ void DownloadProxy::didFail(const ResourceError& error, const IPC::DataReference m_legacyResumeData = createData(resumeData); m_client->didFail(*this, error, m_legacyResumeData.get()); + if (auto* instrumentation = m_dataStore->downloadInstrumentation()) + instrumentation->downloadFinished(m_uuid, error.localizedDescription()); // This can cause the DownloadProxy object to be deleted. m_downloadProxyMap.downloadFinished(*this); diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h index 4b9e12c40517fb84cb23d2de3e2adaa66c69da59..f56879a5a799115ef7353c060b00b842b8702408 100644 --- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h +++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h @@ -146,6 +146,7 @@ private: #if PLATFORM(COCOA) RetainPtr m_progress; #endif + String m_uuid; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.h b/Source/WebKit/UIProcess/DrawingAreaProxy.h index 826c417c6c9ba1c7e6c2c32a6ab0f3ab8d72f0e0..641f418f78c56aba25740586bb982231997b6bf5 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.h +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h @@ -75,6 +75,7 @@ public: const WebCore::IntSize& size() const { return m_size; } bool setSize(const WebCore::IntSize&, const WebCore::IntSize& scrollOffset = { }); + void waitForSizeUpdate(Function&&); #if USE(COORDINATED_GRAPHICS) || USE(TEXTURE_MAPPER) // The timeout we use when waiting for a DidUpdateGeometry message. @@ -160,6 +161,9 @@ private: virtual void update(uint64_t /* backingStoreStateID */, const UpdateInfo&) { } virtual void didUpdateBackingStoreState(uint64_t /* backingStoreStateID */, const UpdateInfo&, const LayerTreeContext&) { } virtual void exitAcceleratedCompositingMode(uint64_t /* backingStoreStateID */, const UpdateInfo&) { } +#endif +#if PLATFORM(WIN) + virtual void didChangeAcceleratedCompositingMode(bool) { } #endif bool m_startedReceivingMessages { false }; }; diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in b/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in index b0722e7da81e56530deb570b82ed7cfece970362..05ec3e3ea97ba49135a27d7f9b91f14c507d9318 100644 --- a/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in +++ b/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in @@ -36,4 +36,7 @@ messages -> DrawingAreaProxy NotRefCounted { DidUpdateBackingStoreState(uint64_t backingStoreStateID, WebKit::UpdateInfo updateInfo, WebKit::LayerTreeContext context) ExitAcceleratedCompositingMode(uint64_t backingStoreStateID, WebKit::UpdateInfo updateInfo) #endif +#if PLATFORM(WIN) + DidChangeAcceleratedCompositingMode(bool enabled) +#endif } diff --git a/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9426d9eed59f433eac62b8eb6a16139b84079949 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.cpp @@ -0,0 +1,244 @@ +/* Copyright 2018 Bernhard R. Fischer, 4096R/8E24F29D + * + * This file is part of Cairo_JPG. + * + * Cairo_JPG is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Cairo_JPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Cairo_JPG. If not, see . + */ + +/*! \file cairo_jpg.c + * This file contains two functions for reading and writing JPEG files from + * and to Cairo image surfaces. It uses the functions from the libjpeg. + * Most of the code is directly derived from the online example at + * http://libjpeg-turbo.virtualgl.org/Documentation/Documentation + * + * All prototypes are defined in cairo_jpg.h All functions and their parameters + * and return values are described below directly at the functions. You may + * also have a look at the preprocessor macros defined below. + * + * To compile this code you need to have installed the packages libcairo2-dev + * and libjpeg-dev. Compile with the following to create an object file to link + * with your code: + * gcc -std=c99 -Wall -c `pkg-config cairo libjpeg --cflags --libs` cairo_jpg.c + * Use the following command to include the main() function and create an + * executable for testing of this code: + * gcc -std=c99 -Wall -o cairo_jpg -DCAIRO_JPEG_MAIN `pkg-config cairo libjpeg --cflags --libs` cairo_jpg.c + * + * @author Bernhard R. Fischer, 4096R/8E24F29D bf@abenteuerland.at + * @version 2020/01/18 + * @license LGPL3. + */ + +#if USE(CAIRO) + +#include "CairoJpegEncoder.h" + +#include +#include +#include +#include +#include +#include +extern "C" { +#include "jpeglib.h" +} + +/*! Macro to activate main() function. This is only used for testing. Comment + * it out (#undef) if you link this file to your own program. + */ +//#define CAIRO_JPEG_MAIN +// +/*! Define this to use an alternate implementation of + * cairo_image_surface_create_from_jpeg() which fstat(3)s the file before + * reading (see below). For huge files this /may/ be slightly faster. + */ +#undef CAIRO_JPEG_USE_FSTAT + +/*! This is the read block size for the stream reader + * cairo_image_surface_create_from_jpeg_stream(). + */ +#ifdef USE_CAIRO_READ_FUNC_LEN_T +#define CAIRO_JPEG_IO_BLOCK_SIZE 4096 +#else +/*! Block size has to be one if cairo_read_func_t is in use because of the lack + * to detect EOF (truncated reads). + */ +#define CAIRO_JPEG_IO_BLOCK_SIZE 1 +/*! In case of original cairo_read_func_t is used fstat() should be used for + * performance reasons (see CAIRO_JPEG_USE_FSTAT above). + */ +#define CAIRO_JPEG_USE_FSTAT +#endif + +/*! Define this to test jpeg creation with non-image surfaces. This is only for + * testing and is to be used together with CAIRO_JPEG_MAIN. + */ +#undef CAIRO_JPEG_TEST_SIMILAR +#if defined(CAIRO_JPEG_TEST_SIMILAR) && defined(CAIRO_JPEG_MAIN) +#include +#endif + + +#ifndef LIBJPEG_TURBO_VERSION +/*! This function makes a covnersion for "odd" pixel sizes which typically is a + * conversion from a 3-byte to a 4-byte (or more) pixel size or vice versa. + * The conversion is done from the source buffer src to the destination buffer + * dst. The caller MUST ensure that src and dst have the correct memory size. + * This is dw * num for dst and sw * num for src. src and dst may point to the + * same memory address. + * @param dst Pointer to destination buffer. + * @param dw Pixel width (in bytes) of pixels in destination buffer, dw >= 3. + * @param src Pointer to source buffer. + * @param sw Pixel width (in bytes) of pixels in source buffer, sw >= 3. + * @param num Number of pixels to convert, num >= 1; + */ +static void pix_conv(unsigned char *dst, int dw, const unsigned char *src, int sw, int num) +{ + int si, di; + + // safety check + if (dw < 3 || sw < 3 || dst == NULL || src == NULL) + return; + + num--; + for (si = num * sw, di = num * dw; si >= 0; si -= sw, di -= dw) + { +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + dst[di + 2] = src[si ]; + dst[di + 1] = src[si + 1]; + dst[di + 0] = src[si + 2]; +#else + // FIXME: This is untested, it may be wrong. + dst[di - 3] = src[si - 3]; + dst[di - 2] = src[si - 2]; + dst[di - 1] = src[si - 1]; +#endif + } +} +#endif + + +/*! This function creates a JPEG file in memory from a Cairo image surface. + * @param sfc Pointer to a Cairo surface. It should be an image surface of + * either CAIRO_FORMAT_ARGB32 or CAIRO_FORMAT_RGB24. Other formats are + * converted to CAIRO_FORMAT_RGB24 before compression. + * Please note that this may give unexpected results because JPEG does not + * support transparency. Thus, default background color is used to replace + * transparent regions. The default background color is black if not specified + * explicitly. Thus converting e.g. PDF surfaces without having any specific + * background color set will apear with black background and not white as you + * might expect. In such cases it is suggested to manually convert the surface + * to RGB24 before calling this function. + * @param data Pointer to a memory pointer. This parameter receives a pointer + * to the memory area where the final JPEG data is found in memory. This + * function reserves the memory properly and it has to be freed by the caller + * with free(3). + * @param len Pointer to a variable of type size_t which will receive the final + * lenght of the memory buffer. + * @param quality Compression quality, 0-100. + * @return On success the function returns CAIRO_STATUS_SUCCESS. In case of + * error CAIRO_STATUS_INVALID_FORMAT is returned. + */ +cairo_status_t cairo_image_surface_write_to_jpeg_mem(cairo_surface_t *sfc, unsigned char **data, size_t *len, int quality) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + JSAMPROW row_pointer[1]; + cairo_surface_t *other = NULL; + + // check valid input format (must be IMAGE_SURFACE && (ARGB32 || RGB24)) + if (cairo_surface_get_type(sfc) != CAIRO_SURFACE_TYPE_IMAGE || + (cairo_image_surface_get_format(sfc) != CAIRO_FORMAT_ARGB32 && + cairo_image_surface_get_format(sfc) != CAIRO_FORMAT_RGB24)) + { + // create a similar surface with a proper format if supplied input format + // does not fulfill the requirements + double x1, y1, x2, y2; + other = sfc; + cairo_t *ctx = cairo_create(other); + // get extents of original surface + cairo_clip_extents(ctx, &x1, &y1, &x2, &y2); + cairo_destroy(ctx); + + // create new image surface + sfc = cairo_surface_create_similar_image(other, CAIRO_FORMAT_RGB24, x2 - x1, y2 - y1); + if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_INVALID_FORMAT; + + // paint original surface to new surface + ctx = cairo_create(sfc); + cairo_set_source_surface(ctx, other, 0, 0); + cairo_paint(ctx); + cairo_destroy(ctx); + } + + // finish queued drawing operations + cairo_surface_flush(sfc); + + // init jpeg compression structures + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + + // set compression parameters + unsigned long targetSize; + jpeg_mem_dest(&cinfo, data, &targetSize); + + cinfo.image_width = cairo_image_surface_get_width(sfc); + cinfo.image_height = cairo_image_surface_get_height(sfc); +#ifdef LIBJPEG_TURBO_VERSION +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + //cinfo.in_color_space = JCS_EXT_BGRX; + cinfo.in_color_space = cairo_image_surface_get_format(sfc) == CAIRO_FORMAT_ARGB32 ? JCS_EXT_BGRA : JCS_EXT_BGRX; +#else + //cinfo.in_color_space = JCS_EXT_XRGB; + cinfo.in_color_space = cairo_image_surface_get_format(sfc) == CAIRO_FORMAT_ARGB32 ? JCS_EXT_ARGB : JCS_EXT_XRGB; +#endif + cinfo.input_components = 4; +#else + cinfo.in_color_space = JCS_RGB; + cinfo.input_components = 3; +#endif + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + + // start compressor + jpeg_start_compress(&cinfo, TRUE); + + // loop over all lines and compress + while (cinfo.next_scanline < cinfo.image_height) + { +#ifdef LIBJPEG_TURBO_VERSION + row_pointer[0] = cairo_image_surface_get_data(sfc) + (cinfo.next_scanline + * cairo_image_surface_get_stride(sfc)); +#else + unsigned char row_buf[3 * cinfo.image_width]; + pix_conv(row_buf, 3, cairo_image_surface_get_data(sfc) + + (cinfo.next_scanline * cairo_image_surface_get_stride(sfc)), 4, cinfo.image_width); + row_pointer[0] = row_buf; +#endif + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + // finalize and close everything + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + // destroy temporary image surface (if available) + if (other != NULL) + cairo_surface_destroy(sfc); + + *len = targetSize; + return CAIRO_STATUS_SUCCESS; +} + +#endif diff --git a/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.h new file mode 100644 index 0000000000000000000000000000000000000000..4ec8b96bbbddf8a7b042f53a8068754a384fc7ad --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) Microsoft. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +cairo_status_t cairo_image_surface_write_to_jpeg_mem(cairo_surface_t *sfc, unsigned char **data, size_t *len, int quality); diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..20122bd89c3ba0ec4ff878ac895bddd497cc9789 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorScreencastAgent.h" + +#include "GenericCallback.h" +#include "PageClient.h" +#include "ScreencastEncoder.h" +#include "WebPageInspectorController.h" +#include "WebPageProxy.h" +#include "WebsiteDataStore.h" +#include +#include +#include +#include +#include + +#if USE(CAIRO) +#include "CairoJpegEncoder.h" +#include "DrawingAreaProxyCoordinatedGraphics.h" +#include "DrawingAreaProxy.h" +#endif + +#if PLATFORM(MAC) +#include +#endif + +namespace WebKit { + +const int kMaxFramesInFlight = 1; + +using namespace Inspector; + +InspectorScreencastAgent::InspectorScreencastAgent(BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page) + : InspectorAgentBase("Screencast"_s) + , m_frontendDispatcher(makeUnique(frontendRouter)) + , m_backendDispatcher(ScreencastBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +InspectorScreencastAgent::~InspectorScreencastAgent() +{ +} + +void InspectorScreencastAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ +} + +void InspectorScreencastAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ + if (!m_encoder) + return; + + // The agent may be destroyed when the callback is invoked. + m_encoder->finish([sessionID = m_page.websiteDataStore().sessionID(), screencastID = WTFMove(m_currentScreencastID)] { + if (WebPageInspectorController::observer()) + WebPageInspectorController::observer()->didFinishScreencast(sessionID, screencastID); + }); + + m_encoder = nullptr; +} + +#if USE(CAIRO) +void InspectorScreencastAgent::didPaint(cairo_surface_t* surface) +{ + if (m_encoder) + m_encoder->encodeFrame(surface, m_page.drawingArea()->size()); + if (m_screencast) { + if (m_screencastFramesInFlight > kMaxFramesInFlight) + return; + // Scale image to fit width / height + WebCore::IntSize displaySize = m_page.drawingArea()->size(); + double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height()); + RefPtr scaledSurface; + if (scale < 1) { + WebCore::IntSize scaledSize = displaySize; + scaledSize.scale(scale); + cairo_matrix_t transform; + cairo_matrix_init_scale(&transform, scale, scale); + scaledSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, scaledSize.width(), scaledSize.height())); + RefPtr cr = adoptRef(cairo_create(scaledSurface.get())); + cairo_transform(cr.get(), &transform); + cairo_set_source_surface(cr.get(), surface, 0, 0); + cairo_paint(cr.get()); + surface = scaledSurface.get(); + } + unsigned char *data = nullptr; + size_t len = 0; + cairo_image_surface_write_to_jpeg_mem(surface, &data, &len, m_screencastQuality); + String result = base64EncodeToString(data, len); + ++m_screencastFramesInFlight; + m_frontendDispatcher->screencastFrame(result, displaySize.width(), displaySize.height()); + } +} +#endif + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::startVideo(const String& file, int width, int height, int toolbarHeight, std::optional&& scale) +{ + if (m_encoder) + return makeUnexpected("Already recording"_s); + + if (width < 10 || width > 10000 || height < 10 || height > 10000) + return makeUnexpected("Invalid size"_s); + + if (scale && (*scale <= 0 || *scale > 1)) + return makeUnexpected("Unsupported scale"_s); + + String errorString; + m_encoder = ScreencastEncoder::create(errorString, file, WebCore::IntSize(width, height), WTFMove(scale)); + if (!m_encoder) + return makeUnexpected(errorString); + + m_currentScreencastID = createCanonicalUUIDString(); + +#if PLATFORM(MAC) + m_encoder->setOffsetTop(toolbarHeight); +#endif + + kickFramesStarted(); + return { { m_currentScreencastID } }; +} + +void InspectorScreencastAgent::stopVideo(Ref&& callback) +{ + if (!m_encoder) { + callback->sendFailure("Not recording"_s); + return; + } + + // The agent may be destroyed when the callback is invoked. + m_encoder->finish([sessionID = m_page.websiteDataStore().sessionID(), screencastID = WTFMove(m_currentScreencastID), callback = WTFMove(callback)] { + if (WebPageInspectorController::observer()) + WebPageInspectorController::observer()->didFinishScreencast(sessionID, screencastID); + callback->sendSuccess(); + }); + m_encoder = nullptr; + if (!m_screencast) + m_framesAreGoing = false; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::startScreencast(int width, int height, int toolbarHeight, int quality) +{ + if (m_screencast) + return makeUnexpected("Already screencasting"_s); + m_screencast = true; + m_screencastWidth = width; + m_screencastHeight = height; + m_screencastQuality = quality; + m_screencastToolbarHeight = toolbarHeight; + m_screencastFramesInFlight = 0; + ++m_screencastGeneration; + kickFramesStarted(); + return m_screencastGeneration; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::screencastFrameAck(int generation) +{ + if (m_screencastGeneration != generation) + return { }; + --m_screencastFramesInFlight; + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorScreencastAgent::stopScreencast() +{ + if (!m_screencast) + return makeUnexpected("Not screencasting"_s); + m_screencast = false; + if (!m_encoder) + m_framesAreGoing = false; + return { }; +} + +void InspectorScreencastAgent::kickFramesStarted() +{ + if (!m_framesAreGoing) { + m_framesAreGoing = true; +#if !PLATFORM(WPE) + scheduleFrameEncoding(); +#endif + } + m_page.forceRepaint([] { }); +} + +#if !PLATFORM(WPE) +void InspectorScreencastAgent::scheduleFrameEncoding() +{ + if (!m_encoder && !m_screencast) + return; + + RunLoop::main().dispatchAfter(Seconds(1.0 / ScreencastEncoder::fps), [agent = makeWeakPtr(this)]() mutable { + if (!agent) + return; + + agent->encodeFrame(); + agent->scheduleFrameEncoding(); + }); +} +#endif + +#if PLATFORM(MAC) +void InspectorScreencastAgent::encodeFrame() +{ + if (!m_encoder && !m_screencast) + return; + RetainPtr imageRef = m_page.pageClient().takeSnapshotForAutomation(); + if (m_screencast && m_screencastFramesInFlight <= kMaxFramesInFlight) { + CGImage* imagePtr = imageRef.get(); + WebCore::IntSize imageSize(CGImageGetWidth(imagePtr), CGImageGetHeight(imagePtr)); + WebCore::IntSize displaySize = imageSize; + displaySize.contract(0, m_screencastToolbarHeight); + double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height()); + RetainPtr scaledImageRef; + if (scale < 1 || m_screencastToolbarHeight) { + WebCore::IntSize screencastSize = displaySize; + screencastSize.scale(scale); + WebCore::IntSize scaledImageSize = imageSize; + scaledImageSize.scale(scale); + auto colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); + auto context = adoptCF(CGBitmapContextCreate(nullptr, screencastSize.width(), screencastSize.height(), 8, 4 * screencastSize.width(), colorSpace.get(), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host)); + CGContextDrawImage(context.get(), CGRectMake(0, 0, scaledImageSize.width(), scaledImageSize.height()), imagePtr); + scaledImageRef = adoptCF(CGBitmapContextCreateImage(context.get())); + imagePtr = scaledImageRef.get(); + } + String base64Data = base64EncodeToString(WebCore::data(imagePtr, WebCore::jpegUTI(), m_screencastQuality * 0.1)); + ++m_screencastFramesInFlight; + m_frontendDispatcher->screencastFrame(base64Data, displaySize.width(), displaySize.height()); + } + if (m_encoder) + m_encoder->encodeFrame(WTFMove(imageRef)); +} +#endif + +#if USE(CAIRO) && !PLATFORM(WPE) +void InspectorScreencastAgent::encodeFrame() +{ + if (!m_encoder && !m_screencast) + return; + + if (auto* drawingArea = m_page.drawingArea()) + static_cast(drawingArea)->captureFrame(); +} +#endif + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..8f2795dbf1323dd8d5f986f18e6fe16431dd7f70 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include + +#if USE(CAIRO) +#include +#endif + +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +class ScreencastFrontendDispatcher; +} + +namespace WebKit { + +class ScreencastEncoder; +class WebPageProxy; + +class InspectorScreencastAgent : public Inspector::InspectorAgentBase, public Inspector::ScreencastBackendDispatcherHandler, public CanMakeWeakPtr { + WTF_MAKE_NONCOPYABLE(InspectorScreencastAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorScreencastAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorScreencastAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + +#if USE(CAIRO) + void didPaint(cairo_surface_t*); +#endif + + Inspector::Protocol::ErrorStringOr startVideo(const String& file, int width, int height, int toolbarHeight, std::optional&& scale) override; + void stopVideo(Ref&&) override; + + Inspector::Protocol::ErrorStringOr startScreencast(int width, int height, int toolbarHeight, int quality) override; + Inspector::Protocol::ErrorStringOr screencastFrameAck(int generation) override; + Inspector::Protocol::ErrorStringOr stopScreencast() override; + +private: +#if !PLATFORM(WPE) + void scheduleFrameEncoding(); + void encodeFrame(); +#endif + + void kickFramesStarted(); + + std::unique_ptr m_frontendDispatcher; + Ref m_backendDispatcher; + WebPageProxy& m_page; + RefPtr m_encoder; + bool m_screencast = false; + bool m_framesAreGoing = false; + double m_screencastWidth = 0; + double m_screencastHeight = 0; + int m_screencastQuality = 0; + int m_screencastToolbarHeight = 0; + int m_screencastGeneration = 0; + int m_screencastFramesInFlight = 0; + String m_currentScreencastID; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62f20814b72e90275eb4fa0e8302fc15abdaaab2 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2010, The WebM Project authors. All rights reserved. + * Copyright (c) 2013 The Chromium Authors. All rights reserved. + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ScreencastEncoder.h" + +#include "WebMFileWriter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if USE(CAIRO) +#include +#endif + +using namespace WebCore; + +namespace WebKit { + +namespace { + +// Number of timebase unints per one frame. +constexpr int timeScale = 1000; + +// Defines the dimension of a macro block. This is used to compute the active +// map for the encoder. +const int kMacroBlockSize = 16; + +void createImage(unsigned int width, unsigned int height, + std::unique_ptr& out_image, + std::unique_ptr& out_image_buffer) { + std::unique_ptr image(new vpx_image_t()); + memset(image.get(), 0, sizeof(vpx_image_t)); + + // libvpx seems to require both to be assigned. + image->d_w = width; + image->w = width; + image->d_h = height; + image->h = height; + + // I420 + image->fmt = VPX_IMG_FMT_YV12; + image->x_chroma_shift = 1; + image->y_chroma_shift = 1; + + // libyuv's fast-path requires 16-byte aligned pointers and strides, so pad + // the Y, U and V planes' strides to multiples of 16 bytes. + const int y_stride = ((image->w - 1) & ~15) + 16; + const int uv_unaligned_stride = y_stride >> image->x_chroma_shift; + const int uv_stride = ((uv_unaligned_stride - 1) & ~15) + 16; + + // libvpx accesses the source image in macro blocks, and will over-read + // if the image is not padded out to the next macroblock: crbug.com/119633. + // Pad the Y, U and V planes' height out to compensate. + // Assuming macroblocks are 16x16, aligning the planes' strides above also + // macroblock aligned them. + static_assert(kMacroBlockSize == 16, "macroblock_size_not_16"); + const int y_rows = ((image->h - 1) & ~(kMacroBlockSize-1)) + kMacroBlockSize; + const int uv_rows = y_rows >> image->y_chroma_shift; + + // Allocate a YUV buffer large enough for the aligned data & padding. + const int buffer_size = y_stride * y_rows + 2*uv_stride * uv_rows; + std::unique_ptr image_buffer(new uint8_t[buffer_size]); + + // Reset image value to 128 so we just need to fill in the y plane. + memset(image_buffer.get(), 128, buffer_size); + + // Fill in the information for |image_|. + unsigned char* uchar_buffer = + reinterpret_cast(image_buffer.get()); + image->planes[0] = uchar_buffer; + image->planes[1] = image->planes[0] + y_stride * y_rows; + image->planes[2] = image->planes[1] + uv_stride * uv_rows; + image->stride[0] = y_stride; + image->stride[1] = uv_stride; + image->stride[2] = uv_stride; + + out_image = std::move(image); + out_image_buffer = std::move(image_buffer); +} + +} // namespace + +class ScreencastEncoder::VPXFrame { + WTF_MAKE_NONCOPYABLE(VPXFrame); + WTF_MAKE_FAST_ALLOCATED; +public: +#if USE(CAIRO) + explicit VPXFrame(RefPtr&& surface) + : m_surface(WTFMove(surface)) + { } +#elif PLATFORM(MAC) + VPXFrame(RetainPtr windowImage, std::optional scale, int offsetTop) + : m_windowImage(WTFMove(windowImage)) + , m_scale(scale) + , m_offsetTop(offsetTop) + { } +#endif + + void setDuration(Seconds duration) { m_duration = duration; } + Seconds duration() const { return m_duration; } + + void convertToVpxImage(vpx_image_t* image) + { +#if USE(CAIRO) + // Convert the updated region to YUV ready for encoding. + const uint8_t* argb_data = cairo_image_surface_get_data(m_surface.get()); + int argb_stride = cairo_image_surface_get_stride(m_surface.get()); +#elif PLATFORM(MAC) + int argb_stride = image->w * 4; + UniqueArray buffer = makeUniqueArray(argb_stride * image->h); + uint8_t* argb_data = buffer.get(); + ScreencastEncoder::imageToARGB(m_windowImage.get(), argb_data, image->w, image->h, m_scale, m_offsetTop); +#endif + const int y_stride = image->stride[0]; + ASSERT(image->stride[1] == image->stride[2]); + const int uv_stride = image->stride[1]; + uint8_t* y_data = image->planes[0]; + uint8_t* u_data = image->planes[1]; + uint8_t* v_data = image->planes[2]; + + // TODO: redraw only damaged regions? + libyuv::ARGBToI420(argb_data, argb_stride, + y_data, y_stride, + u_data, uv_stride, + v_data, uv_stride, + image->w, image->h); + } + +private: +#if USE(CAIRO) + RefPtr m_surface; +#elif PLATFORM(MAC) + RetainPtr m_windowImage; + std::optional m_scale; + int m_offsetTop { 0 }; +#endif + Seconds m_duration; +}; + + +class ScreencastEncoder::VPXCodec { +public: + VPXCodec(vpx_codec_ctx_t codec, vpx_codec_enc_cfg_t cfg, FILE* file) + : m_encoderQueue(WorkQueue::create("Screencast encoder")) + , m_codec(codec) + , m_cfg(cfg) + , m_file(file) + , m_writer(new WebMFileWriter(file, &m_cfg)) + { + createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer); + } + + void encodeFrameAsync(std::unique_ptr&& frame) + { + m_encoderQueue->dispatch([this, frame = WTFMove(frame)] { + frame->convertToVpxImage(m_image.get()); + double frameCount = frame->duration().seconds() * fps; + // For long duration repeat frame at 1 fps to ensure last frame duration is short enough. + // TODO: figure out why simply passing duration doesn't work well. + for (;frameCount > 1.5; frameCount -= 1) { + encodeFrame(m_image.get(), timeScale); + } + encodeFrame(m_image.get(), std::max(1, frameCount * timeScale)); + }); + } + + void finishAsync(Function&& callback) + { + m_encoderQueue->dispatch([this, callback = WTFMove(callback)] { + finish(); + callback(); + }); + } + +private: + bool encodeFrame(vpx_image_t *img, int duration) + { + vpx_codec_iter_t iter = nullptr; + const vpx_codec_cx_pkt_t *pkt = nullptr; + int flags = 0; + const vpx_codec_err_t res = vpx_codec_encode(&m_codec, img, m_pts, duration, flags, VPX_DL_REALTIME); + if (res != VPX_CODEC_OK) { + fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(&m_codec)); + return false; + } + + bool gotPkts = false; + while ((pkt = vpx_codec_get_cx_data(&m_codec, &iter)) != nullptr) { + gotPkts = true; + + if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) { + if (!m_writer->writeFrame(pkt)) { + fprintf(stderr, "Failed to write compressed frame\n"); + return false; + } + ++m_frameCount; + // fprintf(stderr, " #%03d %spts=%" PRId64 " sz=%zd\n", m_frameCount, (pkt->data.frame.flags & VPX_FRAME_IS_KEY) != 0 ? "[K] " : "", pkt->data.frame.pts, pkt->data.frame.sz); + m_pts += pkt->data.frame.duration; + } + } + + return gotPkts; + } + + void finish() + { + // Flush encoder. + while (encodeFrame(nullptr, 1)) + ++m_frameCount; + + m_writer->finish(); + fclose(m_file); + // fprintf(stderr, "ScreencastEncoder::finish %d frames\n", m_frameCount); + } + + Ref m_encoderQueue; + vpx_codec_ctx_t m_codec; + vpx_codec_enc_cfg_t m_cfg; + FILE* m_file { nullptr }; + std::unique_ptr m_writer; + int m_frameCount { 0 }; + int64_t m_pts { 0 }; + std::unique_ptr m_imageBuffer; + std::unique_ptr m_image; +}; + +ScreencastEncoder::ScreencastEncoder(std::unique_ptr&& vpxCodec, IntSize size, std::optional scale) + : m_vpxCodec(WTFMove(vpxCodec)) + , m_size(size) + , m_scale(scale) +{ + ASSERT(!size.isZero()); +} + +ScreencastEncoder::~ScreencastEncoder() +{ +} + +RefPtr ScreencastEncoder::create(String& errorString, const String& filePath, IntSize size, std::optional scale) +{ + vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx(); + if (!codec_interface) { + errorString = "Codec not found."; + return nullptr; + } + + if (size.width() <= 0 || size.height() <= 0 || (size.width() % 2) != 0 || (size.height() % 2) != 0) { + errorString = makeString("Invalid frame size: "_s, size.width(), "x"_s, size.height()); + return nullptr; + } + + vpx_codec_enc_cfg_t cfg; + memset(&cfg, 0, sizeof(cfg)); + vpx_codec_err_t error = vpx_codec_enc_config_default(codec_interface, &cfg, 0); + if (error) { + errorString = makeString("Failed to get default codec config: "_s, vpx_codec_err_to_string(error)); + return nullptr; + } + + cfg.g_w = size.width(); + cfg.g_h = size.height(); + cfg.g_timebase.num = 1; + cfg.g_timebase.den = fps * timeScale; + cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT; + + vpx_codec_ctx_t codec; + if (vpx_codec_enc_init(&codec, codec_interface, &cfg, 0)) { + errorString = makeString("Failed to initialize encoder: "_s, vpx_codec_error(&codec)); + return nullptr; + } + + FILE* file = fopen(filePath.utf8().data(), "wb"); + if (!file) { + errorString = makeString("Failed to open file '", filePath, "' for writing: ", strerror(errno)); + return nullptr; + } + + std::unique_ptr vpxCodec(new VPXCodec(codec, cfg, file)); + // fprintf(stderr, "ScreencastEncoder initialized with: %s\n", vpx_codec_iface_name(codec_interface)); + return adoptRef(new ScreencastEncoder(WTFMove(vpxCodec), size, scale)); +} + +void ScreencastEncoder::flushLastFrame() +{ + MonotonicTime now = MonotonicTime::now(); + if (m_lastFrameTimestamp) { + // If previous frame encoding failed for some rason leave the timestampt intact. + if (!m_lastFrame) + return; + + Seconds seconds = now - m_lastFrameTimestamp; + m_lastFrame->setDuration(seconds); + m_vpxCodec->encodeFrameAsync(WTFMove(m_lastFrame)); + } + m_lastFrameTimestamp = now; +} + +#if USE(CAIRO) +void ScreencastEncoder::encodeFrame(cairo_surface_t* drawingAreaSurface, IntSize size) +{ + // fprintf(stderr, "ScreencastEncoder::encodeFrame\n"); + flushLastFrame(); + // Note that in WPE drawing area size is updated asynchronously and may differ from acutal + // size of the surface. + if (size.isZero()) { + // fprintf(stderr, "Cairo surface size is 0\n"); + return; + } + + // TODO: adjust device scale factor? + RefPtr surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_size.width(), m_size.height())); + { + RefPtr cr = adoptRef(cairo_create(surface.get())); + + // TODO: compare to libyuv scale functions? + cairo_matrix_t transform; + if (m_scale) { + cairo_matrix_init_scale(&transform, *m_scale, *m_scale); + cairo_transform(cr.get(), &transform); + } else if (size.width() > m_size.width() || size.height() > m_size.height()) { + // If no scale is specified shrink to fit the frame. + double scale = std::min(static_cast(m_size.width()) / size.width(), + static_cast(m_size.height()) / size.height()); + cairo_matrix_init_scale(&transform, scale, scale); + cairo_transform(cr.get(), &transform); + } + + // Record top left part of the drawing area that fits into the frame. + cairo_set_source_surface(cr.get(), drawingAreaSurface, 0, 0); + cairo_paint(cr.get()); + } + cairo_surface_flush(surface.get()); + + m_lastFrame = makeUnique(WTFMove(surface)); +} +#elif PLATFORM(MAC) +void ScreencastEncoder::encodeFrame(RetainPtr&& windowImage) +{ + // fprintf(stderr, "ScreencastEncoder::encodeFrame\n"); + flushLastFrame(); + + m_lastFrame = makeUnique(WTFMove(windowImage), m_scale, m_offsetTop); +} +#endif + +void ScreencastEncoder::finish(Function&& callback) +{ + if (!m_vpxCodec) { + callback(); + return; + } + + flushLastFrame(); + m_vpxCodec->finishAsync([protectRef = makeRef(*this), callback = WTFMove(callback)] () mutable { + RunLoop::main().dispatch([callback = WTFMove(callback)] { + callback(); + }); + }); +} + + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h new file mode 100644 index 0000000000000000000000000000000000000000..1683da93db6b9088c3a472472c1b71477b47a7fd --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#if USE(CAIRO) +#include +#endif + +namespace WebKit { + +class WebPageProxy; + +class ScreencastEncoder : public ThreadSafeRefCounted { + WTF_MAKE_NONCOPYABLE(ScreencastEncoder); + WTF_MAKE_FAST_ALLOCATED; +public: + static constexpr int fps = 25; + + static RefPtr create(String& errorString, const String& filePath, WebCore::IntSize, std::optional scale); + + class VPXCodec; + ScreencastEncoder(std::unique_ptr&&, WebCore::IntSize, std::optional scale); + ~ScreencastEncoder(); + +#if USE(CAIRO) + void encodeFrame(cairo_surface_t*, WebCore::IntSize); +#elif PLATFORM(MAC) + void encodeFrame(RetainPtr&&); + void setOffsetTop(int offset) { m_offsetTop = offset;} +#endif + + void finish(Function&& callback); + +private: + void flushLastFrame(); +#if PLATFORM(MAC) + static void imageToARGB(CGImageRef, uint8_t* rgba_data, int width, int height, std::optional scale, int offsetTop); +#endif + + std::unique_ptr m_vpxCodec; + const WebCore::IntSize m_size; + std::optional m_scale; + MonotonicTime m_lastFrameTimestamp; + class VPXFrame; + std::unique_ptr m_lastFrame; +#if PLATFORM(MAC) + int m_offsetTop { 0 }; +#endif +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.cpp b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b269b356e206f0252245a1497adb0d05128c9b4 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014 The WebM project authors. All Rights Reserved. + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebMFileWriter.h" + +#include +#include "mkvmuxer/mkvmuxerutil.h" + +namespace WebKit { + +WebMFileWriter::WebMFileWriter(FILE* file, vpx_codec_enc_cfg_t* cfg) + : m_cfg(cfg) + , m_writer(new mkvmuxer::MkvWriter(file)) + , m_segment(new mkvmuxer::Segment()) { + m_segment->Init(m_writer.get()); + m_segment->set_mode(mkvmuxer::Segment::kFile); + m_segment->OutputCues(true); + + mkvmuxer::SegmentInfo* info = m_segment->GetSegmentInfo(); + std::string version = "Playwright " + std::string(vpx_codec_version_str()); + info->set_writing_app(version.c_str()); + + // Add vp8 track. + m_videoTrackId = m_segment->AddVideoTrack( + static_cast(m_cfg->g_w), static_cast(m_cfg->g_h), 0); + if (!m_videoTrackId) { + fprintf(stderr, "Failed to add video track\n"); + } +} + +WebMFileWriter::~WebMFileWriter() {} + +bool WebMFileWriter::writeFrame(const vpx_codec_cx_pkt_t* pkt) { + int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * m_cfg->g_timebase.num / + m_cfg->g_timebase.den; + return m_segment->AddFrame(static_cast(pkt->data.frame.buf), + pkt->data.frame.sz, m_videoTrackId, pts_ns, + pkt->data.frame.flags & VPX_FRAME_IS_KEY); +} + +void WebMFileWriter::finish() { + m_segment->Finalize(); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.h b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.h new file mode 100644 index 0000000000000000000000000000000000000000..e2ce910f3fd7f587add552275b7e7176cf8b2723 --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/Agents/WebMFileWriter.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include "vpx/vpx_encoder.h" + +#include "mkvmuxer/mkvmuxer.h" +#include "mkvmuxer/mkvwriter.h" + +namespace WebKit { + +class WebMFileWriter { +public: + WebMFileWriter(FILE*, vpx_codec_enc_cfg_t* cfg); + ~WebMFileWriter(); + + bool writeFrame(const vpx_codec_cx_pkt_t* pkt); + void finish(); + +private: + vpx_codec_enc_cfg_t* m_cfg = nullptr; + std::unique_ptr m_writer; + std::unique_ptr m_segment; + uint64_t m_videoTrackId = 0; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp index 6928ca2fbfb6939062e3cd14bb7ba6f2fdc87f5f..621b99e233ed5cf504fedbd3ca3209c03bcd611f 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) { @@ -97,6 +95,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 ed4e6f30b8c35966075573dccee801daceec865e..6e0bf726a6e8e8773940041bc87f3c7e14403d34 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp @@ -26,13 +26,21 @@ #include "config.h" #include "WebPageInspectorController.h" +#include "APINavigation.h" #include "APIUIClient.h" #include "InspectorBrowserAgent.h" +#include "InspectorDialogAgent.h" +#include "InspectorScreencastAgent.h" #include "ProvisionalPageProxy.h" #include "WebFrameProxy.h" #include "WebPageInspectorAgentBase.h" +#include "WebPageInspectorEmulationAgent.h" +#include "WebPageInspectorInputAgent.h" #include "WebPageInspectorTarget.h" #include "WebPageProxy.h" +#include "WebPreferences.h" +#include +#include #include #include #include @@ -49,27 +57,108 @@ static String getTargetID(const ProvisionalPageProxy& provisionalPage) return WebPageInspectorTarget::toTargetID(provisionalPage.webPageID()); } +WebPageInspectorControllerObserver* WebPageInspectorController::s_observer = nullptr; + +void WebPageInspectorController::setObserver(WebPageInspectorControllerObserver* observer) +{ + s_observer = observer; +} + +WebPageInspectorControllerObserver* WebPageInspectorController::observer() { + return s_observer; +} + WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPage) : m_frontendRouter(FrontendRouter::create()) , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) , m_inspectedPage(inspectedPage) { - auto targetAgent = makeUnique(m_frontendRouter.get(), m_backendDispatcher.get()); - m_targetAgent = targetAgent.get(); - m_agents.append(WTFMove(targetAgent)); } 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_inspectedPage); + m_emulationAgent = emulationAgent.get(); + m_agents.append(WTFMove(emulationAgent)); + auto inputAgent = makeUnique(m_backendDispatcher.get(), m_inspectedPage); + m_inputAgent = inputAgent.get(); + m_agents.append(WTFMove(inputAgent)); + m_agents.append(makeUnique(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage)); + auto screencastAgent = makeUnique(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage); + m_screecastAgent = screencastAgent.get(); + m_agents.append(WTFMove(screencastAgent)); + if (s_observer) + s_observer->didCreateInspectorController(m_inspectedPage); + + // window.open will create page with already running process. + if (!m_inspectedPage.hasRunningProcess()) + return; String pageTargetId = WebPageInspectorTarget::toTargetID(m_inspectedPage.webPageID()); createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page); } +void WebPageInspectorController::didFinishAttachingToWebProcess() +{ + String pageTargetID = WebPageInspectorTarget::toTargetID(m_inspectedPage.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_inspectedPage.webPageID()); + destroyInspectorTarget(pageTargetId); + disconnectAllFrontends(); m_agents.discardValues(); + + if (s_observer) + s_observer->willDestroyInspectorController(m_inspectedPage); +} + +bool WebPageInspectorController::pageCrashed(ProcessTerminationReason reason) +{ + if (reason != ProcessTerminationReason::Crash) + return false; + String targetId = WebPageInspectorTarget::toTargetID(m_inspectedPage.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::willCreateNewPage(const WebCore::WindowFeatures& features, const URL& url) +{ + if (s_observer) + s_observer->willCreateNewPage(m_inspectedPage, features, url); +} + +void WebPageInspectorController::didShowPage() +{ + if (m_frontendRouter->hasFrontends()) + m_emulationAgent->didShowPage(); +} + +void WebPageInspectorController::didProcessAllPendingKeyboardEvents() +{ + if (m_frontendRouter->hasFrontends()) + m_inputAgent->didProcessAllPendingKeyboardEvents(); +} + +void WebPageInspectorController::didProcessAllPendingMouseEvents() +{ + if (m_frontendRouter->hasFrontends()) + m_inputAgent->didProcessAllPendingMouseEvents(); } bool WebPageInspectorController::hasLocalFrontend() const @@ -83,6 +172,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) @@ -101,8 +201,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_inspectedPage.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); @@ -125,6 +227,8 @@ void WebPageInspectorController::disconnectAllFrontends() // Disconnect any remaining remote frontends. m_frontendRouter->disconnectAllFrontends(); + m_pendingNavigations.clear(); + m_inspectedPage.didChangeInspectorFrontendCount(m_frontendRouter->frontendCount()); #if ENABLE(REMOTE_INSPECTOR) @@ -151,6 +255,66 @@ void WebPageInspectorController::setIndicating(bool indicating) } #endif +#if USE(CAIRO) +void WebPageInspectorController::didPaint(cairo_surface_t* surface) +{ + if (!m_frontendRouter->hasFrontends()) + return; + + m_screecastAgent->didPaint(surface); +} +#endif + + +void WebPageInspectorController::navigate(WebCore::ResourceRequest&& request, WebFrameProxy* frame, NavigationHandler&& completionHandler) +{ + auto navigation = m_inspectedPage.loadRequestForInspector(WTFMove(request), frame); + if (!navigation) { + completionHandler("Failed to navigate"_s, 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_inspectedPage, navigationID, error.localizedDescription()); +} + void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { addTarget(InspectorTargetProxy::create(m_inspectedPage, targetId, type)); @@ -170,6 +334,32 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta m_targetAgent->sendMessageFromTargetToFrontend(targetId, message); } +void WebPageInspectorController::setPauseOnStart(bool shouldPause) +{ + ASSERT(m_frontendRouter->hasFrontends()); + m_targetAgent->setPauseOnStart(shouldPause); +} + +bool WebPageInspectorController::shouldPauseLoading() const +{ + if (!m_frontendRouter->hasFrontends()) + return false; + + if (!m_inspectedPage.isPageOpenedByDOMShowingInitialEmptyDocument()) + return false; + + auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage.webPageID())); + ASSERT(target); + return target->isPaused(); +} + +void WebPageInspectorController::setContinueLoadingCallback(WTF::Function&& callback) +{ + auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage.webPageID())); + ASSERT(target); + target->setResumeCallback(WTFMove(callback)); +} + bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const { if (!m_frontendRouter->hasFrontends()) @@ -189,7 +379,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) @@ -267,4 +457,27 @@ void WebPageInspectorController::browserExtensionsDisabled(HashSet&& ext m_enabledBrowserAgent->extensionsDisabled(WTFMove(extensionIDs)); } +void WebPageInspectorController::adjustPageSettings() +{ + // Set this to true as otherwise updating any preferences will override its + // value in the Web Process to false (and InspectorController sets it locally + // to true when frontend is connected). + m_inspectedPage.preferences().setDeveloperExtrasEnabled(true); + + // Navigation to cached pages doesn't fire some of the events (e.g. execution context created) + // that inspector depends on. So we disable the cache when front-end connects. + m_inspectedPage.preferences().setUsesBackForwardCache(false); + + // Enable popup debugging. + // TODO: allow to set preferences over the inspector protocol or find a better place for this. + m_inspectedPage.preferences().setJavaScriptCanOpenWindowsAutomatically(true); + + // Enable media stream. + if (!m_inspectedPage.preferences().mediaStreamEnabled()) { + m_inspectedPage.preferences().setMediaDevicesEnabled(true); + m_inspectedPage.preferences().setMediaStreamEnabled(true); + m_inspectedPage.preferences().setPeerConnectionEnabled(true); + } +} + } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h index 8c1339345d451874502b271f6aa2eca3fa0d3faf..331b61c70c7370ace480724bdb53c99a54897374 100644 --- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h +++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h @@ -26,17 +26,35 @@ #pragma once #include "InspectorTargetProxy.h" +#include "ProcessTerminationReason.h" #include #include #include #include #include #include +#include + +#if USE(CAIRO) +#include +#endif namespace Inspector { class BackendDispatcher; class FrontendChannel; class FrontendRouter; +class InspectorTarget; +} + +namespace WebCore { +class ResourceError; +class ResourceRequest; +enum class PolicyAction : uint8_t; +struct WindowFeatures; +} + +namespace PAL { +class SessionID; } namespace WebKit { @@ -44,6 +62,23 @@ namespace WebKit { class InspectorBrowserAgent; struct WebPageAgentContext; +class InspectorScreencastAgent; +class WebFrameProxy; +class WebPageInspectorEmulationAgent; +class WebPageInspectorInputAgent; + +class WebPageInspectorControllerObserver { +public: + virtual void didCreateInspectorController(WebPageProxy&) = 0; + virtual void willDestroyInspectorController(WebPageProxy&) = 0; + virtual void didFailProvisionalLoad(WebPageProxy&, uint64_t navigationID, const String& error) = 0; + virtual void willCreateNewPage(WebPageProxy&, const WebCore::WindowFeatures&, const URL&) = 0; + virtual void didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) = 0; + +protected: + virtual ~WebPageInspectorControllerObserver() = default; +}; + class WebPageInspectorController { WTF_MAKE_NONCOPYABLE(WebPageInspectorController); WTF_MAKE_FAST_ALLOCATED; @@ -51,7 +86,20 @@ public: WebPageInspectorController(WebPageProxy&); void init(); + void didFinishAttachingToWebProcess(); + + static void setObserver(WebPageInspectorControllerObserver*); + static WebPageInspectorControllerObserver* observer(); + void pageClosed(); + bool pageCrashed(ProcessTerminationReason); + + void willCreateNewPage(const WebCore::WindowFeatures&, const URL&); + + void didShowPage(); + + void didProcessAllPendingKeyboardEvents(); + void didProcessAllPendingMouseEvents(); bool hasLocalFrontend() const; @@ -64,11 +112,25 @@ public: #if ENABLE(REMOTE_INSPECTOR) void setIndicating(bool); #endif +#if USE(CAIRO) + void didPaint(cairo_surface_t*); +#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&&); @@ -87,6 +149,7 @@ private: void createLazyAgents(); void addTarget(std::unique_ptr&&); + void adjustPageSettings(); Ref m_frontendRouter; Ref m_backendDispatcher; @@ -95,11 +158,17 @@ private: WebPageProxy& m_inspectedPage; Inspector::InspectorTargetAgent* m_targetAgent { nullptr }; + WebPageInspectorEmulationAgent* m_emulationAgent { nullptr }; + WebPageInspectorInputAgent* m_inputAgent { nullptr }; + InspectorScreencastAgent* m_screecastAgent { nullptr }; HashMap> m_targets; InspectorBrowserAgent* m_enabledBrowserAgent; bool m_didCreateLazyAgents { false }; + HashMap m_pendingNavigations; + + static WebPageInspectorControllerObserver* s_observer; }; } // namespace WebKit diff --git a/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm b/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm new file mode 100644 index 0000000000000000000000000000000000000000..66d1c743de1cb35e29d6fc9b69379d265a59961f --- /dev/null +++ b/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm @@ -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 "ScreencastEncoder.h" + +#include +#include +#include + +namespace WebKit { + +void ScreencastEncoder::imageToARGB(CGImageRef image, uint8_t* argb_data, int width, int height, std::optional scale, int offsetTop) +{ + size_t bitsPerComponent = 8; + size_t bytesPerPixel = 4; + size_t bytesPerRow = bytesPerPixel * width; + RetainPtr colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB()); + RetainPtr context = adoptCF(CGBitmapContextCreate(argb_data, width, height, bitsPerComponent, bytesPerRow, colorSpace.get(), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little)); + double imageWidth = CGImageGetWidth(image); + double imageHeight = CGImageGetHeight(image); + // TODO: exclude controls from original screenshot + double pageHeight = imageHeight - offsetTop; + double ratio = 1; + if (scale) { + ratio = *scale; + } else if (imageWidth > width || pageHeight > height) { + ratio = std::min(width / imageWidth, height / pageHeight); + } + imageWidth *= ratio; + imageHeight *= ratio; + pageHeight *= ratio; + CGContextDrawImage(context.get(), CGRectMake(0, height - pageHeight, imageWidth, imageHeight), image); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..663f92f0df76042cf6385b056f8a917d688259f9 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorDialogAgent.h" + +#include "APINavigation.h" +#include "APIUIClient.h" +#include "WebPageProxy.h" +#include + + +namespace WebKit { + +using namespace Inspector; + +InspectorDialogAgent::InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page) + : InspectorAgentBase("Dialog"_s) + , m_frontendDispatcher(makeUnique(frontendRouter)) + , m_backendDispatcher(DialogBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +InspectorDialogAgent::~InspectorDialogAgent() +{ + disable(); +} + +void InspectorDialogAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) +{ +} + +void InspectorDialogAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason) +{ +} + +Inspector::Protocol::ErrorStringOr InspectorDialogAgent::enable() +{ + if (m_page.inspectorDialogAgent()) + return makeUnexpected("Dialog domain is already enabled."_s); + + m_page.setInspectorDialogAgent(this); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorDialogAgent::disable() +{ + if (m_page.inspectorDialogAgent() != this) + return { }; + + m_page.setInspectorDialogAgent(nullptr); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorDialogAgent::handleJavaScriptDialog(bool accept, const String& value) +{ + m_page.uiClient().handleJavaScriptDialog(m_page, accept, value); + return { }; +} + +void InspectorDialogAgent::javascriptDialogOpening(const String& type, const String& message, const String& defaultValue) { + m_frontendDispatcher->javascriptDialogOpening(type, message, defaultValue); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.h b/Source/WebKit/UIProcess/InspectorDialogAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..d0e11ed81a6257c011df23d5870da7403f8e9fe4 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorDialogAgent.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "WebEvent.h" + +#include +#include +#include + +#include +#include + +namespace Inspector { +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class NativeWebKeyboardEvent; +class WebPageProxy; + +class InspectorDialogAgent : public Inspector::InspectorAgentBase, public Inspector::DialogBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(InspectorDialogAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page); + ~InspectorDialogAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + Inspector::Protocol::ErrorStringOr enable() override; + Inspector::Protocol::ErrorStringOr disable() override; + Inspector::Protocol::ErrorStringOr handleJavaScriptDialog(bool accept, const String& promptText) override; + + void javascriptDialogOpening(const String& type, const String& message, const String& defaultValue = String()); + +private: + void platformHandleJavaScriptDialog(bool accept, const String* promptText); + std::unique_ptr m_frontendDispatcher; + Ref m_backendDispatcher; + WebPageProxy& m_page; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc6dff4a863aea91fd67c51ff24b44943cb46095 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp @@ -0,0 +1,1010 @@ +/* + * 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 "FrameInfoData.h" +#include "InspectorPlaywrightAgentClient.h" +#include "InspectorTargetProxy.h" +#include "NetworkProcessMessages.h" +#include "NetworkProcessProxy.h" +#include "PageClient.h" +#include "StorageNamespaceIdentifier.h" +#include "WebAutomationSession.h" +#include "WebGeolocationManagerProxy.h" +#include "WebGeolocationPosition.h" +#include "WebInspectorUtilities.h" +#include "WebPageGroup.h" +#include "WebPageInspectorController.h" +#include "WebPageInspectorTarget.h" +#include "WebPageProxy.h" +#include "WebProcessPool.h" +#include "WebProcessProxy.h" +#include "WebsiteDataRecord.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace Inspector; + +namespace WebKit { + +class InspectorPlaywrightAgent::PageProxyChannel : public FrontendChannel { + WTF_MAKE_FAST_ALLOCATED; +public: + PageProxyChannel(FrontendChannel& frontendChannel, String browserContextID, String pageProxyID, WebPageProxy& page) + : m_browserContextID(browserContextID) + , m_pageProxyID(pageProxyID) + , m_frontendChannel(frontendChannel) + , m_page(page) + { + } + + ~PageProxyChannel() override = default; + + void dispatchMessageFromFrontend(const String& message) + { + m_page.inspectorController().dispatchMessageFromFrontend(message); + } + + WebPageProxy& page() { return m_page; } + + void disconnect() + { + m_page.inspectorController().disconnectFrontend(*this); + } + +private: + ConnectionType connectionType() const override { return m_frontendChannel.connectionType(); } + void sendMessageToFrontend(const String& message) override + { + m_frontendChannel.sendMessageToFrontend(addTabIdToMessage(message)); + } + + String addTabIdToMessage(const String& message) { + RefPtr parsedMessage = JSON::Value::parseJSON(message); + if (!parsedMessage) + return message; + + RefPtr messageObject = parsedMessage->asObject(); + if (!messageObject) + return message; + + messageObject->setString("browserContextId"_s, m_browserContextID); + messageObject->setString("pageProxyId"_s, m_pageProxyID); + return messageObject->toJSONString(); + } + + String m_browserContextID; + String m_pageProxyID; + FrontendChannel& m_frontendChannel; + WebPageProxy& m_page; +}; + +namespace { + +String toBrowserContextIDProtocolString(const PAL::SessionID& sessionID) +{ + StringBuilder builder; + builder.append(hex(sessionID.toUInt64(), 16)); + return builder.toString(); +} + +String toPageProxyIDProtocolString(const WebPageProxy& page) +{ + return makeString(page.identifier().toUInt64()); +} + + +static Ref> getEnabledWindowFeatures(const WebCore::WindowFeatures& features) { + auto result = JSON::ArrayOf::create(); + if (features.x) + result->addItem("left=" + String::number(*features.x)); + if (features.y) + result->addItem("top=" + String::number(*features.y)); + if (features.width) + result->addItem("width=" + String::number(*features.width)); + if (features.height) + result->addItem("height=" + String::number(*features.height)); + if (features.menuBarVisible) + result->addItem("menubar"); + if (features.toolBarVisible) + result->addItem("toolbar"); + if (features.statusBarVisible) + result->addItem("status"); + if (features.locationBarVisible) + result->addItem("location"); + if (features.scrollbarsVisible) + result->addItem("scrollbars"); + if (features.resizable) + result->addItem("resizable"); + if (features.fullscreen) + result->addItem("fullscreen"); + if (features.dialog) + result->addItem("dialog"); + if (features.noopener) + result->addItem("noopener"); + if (features.noreferrer) + result->addItem("noreferrer"); + for (const auto& additionalFeature : features.additionalFeatures) + result->addItem(additionalFeature); + return result; +} + +Inspector::Protocol::Playwright::CookieSameSitePolicy cookieSameSitePolicy(WebCore::Cookie::SameSitePolicy policy) +{ + switch (policy) { + case WebCore::Cookie::SameSitePolicy::None: + return Inspector::Protocol::Playwright::CookieSameSitePolicy::None; + case WebCore::Cookie::SameSitePolicy::Lax: + return Inspector::Protocol::Playwright::CookieSameSitePolicy::Lax; + case WebCore::Cookie::SameSitePolicy::Strict: + return Inspector::Protocol::Playwright::CookieSameSitePolicy::Strict; + } + ASSERT_NOT_REACHED(); + return Inspector::Protocol::Playwright::CookieSameSitePolicy::None; +} + +Ref buildObjectForCookie(const WebCore::Cookie& cookie) +{ + return Inspector::Protocol::Playwright::Cookie::create() + .setName(cookie.name) + .setValue(cookie.value) + .setDomain(cookie.domain) + .setPath(cookie.path) + .setExpires(cookie.expires.value_or(-1)) + .setHttpOnly(cookie.httpOnly) + .setSecure(cookie.secure) + .setSession(cookie.session) + .setSameSite(cookieSameSitePolicy(cookie.sameSite)) + .release(); +} + +} // namespace + +BrowserContext::BrowserContext() = default; + +BrowserContext::~BrowserContext() = default; + +class InspectorPlaywrightAgent::BrowserContextDeletion { + WTF_MAKE_NONCOPYABLE(BrowserContextDeletion); + WTF_MAKE_FAST_ALLOCATED; +public: + BrowserContextDeletion(std::unique_ptr&& context, size_t numberOfPages, Ref&& callback) + : m_browserContext(WTFMove(context)) + , m_numberOfPages(numberOfPages) + , m_callback(WTFMove(callback)) { } + + void didDestroyPage(const WebPageProxy& page) + { + ASSERT(m_browserContext->dataStore->sessionID() == page.sessionID()); + // Check if new pages have been created during the context destruction and + // close all of them if necessary. + if (m_numberOfPages == 1) { + auto pages = m_browserContext->pages; + size_t numberOfPages = pages.size(); + if (numberOfPages > 1) { + m_numberOfPages = numberOfPages; + for (auto* existingPage : pages) { + if (existingPage != &page) + existingPage->closePage(); + } + } + } + --m_numberOfPages; + if (m_numberOfPages) + return; + m_callback->sendSuccess(); + } + + bool isFinished() const { return !m_numberOfPages; } + + BrowserContext* context() const { return m_browserContext.get(); } + +private: + std::unique_ptr m_browserContext; + size_t m_numberOfPages; + Ref m_callback; +}; + + +InspectorPlaywrightAgent::InspectorPlaywrightAgent(std::unique_ptr client) + : m_frontendChannel(nullptr) + , m_frontendRouter(FrontendRouter::create()) + , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef())) + , m_client(std::move(client)) + , m_frontendDispatcher(makeUnique(m_frontendRouter)) + , m_playwrightDispatcher(PlaywrightBackendDispatcher::create(m_backendDispatcher.get(), this)) +{ +} + +InspectorPlaywrightAgent::~InspectorPlaywrightAgent() +{ + if (m_frontendChannel) + disconnectFrontend(); +} + +void InspectorPlaywrightAgent::connectFrontend(FrontendChannel& frontendChannel) +{ + ASSERT(!m_frontendChannel); + m_frontendChannel = &frontendChannel; + WebPageInspectorController::setObserver(this); + + m_frontendRouter->connectFrontend(frontendChannel); +} + +void InspectorPlaywrightAgent::disconnectFrontend() +{ + if (!m_frontendChannel) + return; + + disable(); + + m_frontendRouter->disconnectFrontend(*m_frontendChannel); + ASSERT(!m_frontendRouter->hasFrontends()); + + WebPageInspectorController::setObserver(nullptr); + m_frontendChannel = nullptr; + + closeImpl([](String error){}); +} + +void InspectorPlaywrightAgent::dispatchMessageFromFrontend(const String& message) +{ + m_backendDispatcher->dispatch(message, [&](const RefPtr& messageObject) { + RefPtr idValue; + if (!messageObject->getValue("id"_s, idValue)) + return BackendDispatcher::InterceptionResult::Continue; + RefPtr pageProxyIDValue; + if (!messageObject->getValue("pageProxyId"_s, pageProxyIDValue)) + return BackendDispatcher::InterceptionResult::Continue; + + String pageProxyID; + if (!pageProxyIDValue->asString(pageProxyID)) { + m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidRequest, "The type of 'pageProxyId' must be string"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::InterceptionResult::Intercepted; + } + + if (auto pageProxyChannel = m_pageProxyChannels.get(pageProxyID)) { + pageProxyChannel->dispatchMessageFromFrontend(message); + return BackendDispatcher::InterceptionResult::Intercepted; + } + + std::optional requestId = idValue->asInteger(); + if (!requestId) { + m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidRequest, "The type of 'id' must be number"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::InterceptionResult::Intercepted; + } + + m_backendDispatcher->reportProtocolError(*requestId, BackendDispatcher::InvalidParams, "Cannot find page proxy with provided 'pageProxyId'"_s); + m_backendDispatcher->sendPendingErrors(); + return BackendDispatcher::InterceptionResult::Intercepted; + }); +} + +void InspectorPlaywrightAgent::didCreateInspectorController(WebPageProxy& page) +{ + if (!m_isEnabled) + return; + + if (isInspectorProcessPool(page.process().processPool())) + return; + + ASSERT(m_frontendChannel); + + String browserContextID = toBrowserContextIDProtocolString(page.sessionID()); + String pageProxyID = toPageProxyIDProtocolString(page); + auto* opener = page.configuration().relatedPage(); + String openerId; + if (opener) + openerId = toPageProxyIDProtocolString(*opener); + + BrowserContext* browserContext = getExistingBrowserContext(browserContextID); + browserContext->pages.add(&page); + m_frontendDispatcher->pageProxyCreated(browserContextID, pageProxyID, openerId); + + // Auto-connect to all new pages. + auto pageProxyChannel = makeUnique(*m_frontendChannel, browserContextID, pageProxyID, page); + page.inspectorController().connectFrontend(*pageProxyChannel); + // Always pause new targets if controlled remotely. + page.inspectorController().setPauseOnStart(true); + m_pageProxyChannels.set(pageProxyID, WTFMove(pageProxyChannel)); +} + +void InspectorPlaywrightAgent::willDestroyInspectorController(WebPageProxy& page) +{ + if (!m_isEnabled) + return; + + if (isInspectorProcessPool(page.process().processPool())) + return; + + String browserContextID = toBrowserContextIDProtocolString(page.sessionID()); + BrowserContext* browserContext = getExistingBrowserContext(browserContextID); + browserContext->pages.remove(&page); + m_frontendDispatcher->pageProxyDestroyed(toPageProxyIDProtocolString(page)); + + auto it = m_browserContextDeletions.find(browserContextID); + if (it != m_browserContextDeletions.end()) { + it->value->didDestroyPage(page); + if (it->value->isFinished()) + m_browserContextDeletions.remove(it); + } + + String pageProxyID = toPageProxyIDProtocolString(page); + auto channelIt = m_pageProxyChannels.find(pageProxyID); + ASSERT(channelIt != m_pageProxyChannels.end()); + channelIt->value->disconnect(); + m_pageProxyChannels.remove(channelIt); +} + +void InspectorPlaywrightAgent::didFailProvisionalLoad(WebPageProxy& page, uint64_t navigationID, const String& error) +{ + if (!m_isEnabled) + return; + + m_frontendDispatcher->provisionalLoadFailed( + toPageProxyIDProtocolString(page), + String::number(navigationID), error); +} + +void InspectorPlaywrightAgent::willCreateNewPage(WebPageProxy& page, const WebCore::WindowFeatures& features, const URL& url) +{ + if (!m_isEnabled) + return; + + m_frontendDispatcher->windowOpen( + toPageProxyIDProtocolString(page), + url.string(), + getEnabledWindowFeatures(features)); +} + +void InspectorPlaywrightAgent::didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) +{ + if (!m_isEnabled) + return; + + m_frontendDispatcher->screencastFinished(screencastID); +} + +static WebsiteDataStore* findDefaultWebsiteDataStore() { + WebsiteDataStore* result = nullptr; + WebsiteDataStore::forEachWebsiteDataStore([&result] (WebsiteDataStore& dataStore) { + if (dataStore.isPersistent()) { + RELEASE_ASSERT(result == nullptr); + result = &dataStore; + } + }); + return result; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::enable() +{ + if (m_isEnabled) + return { }; + + m_isEnabled = true; + + auto* defaultDataStore = findDefaultWebsiteDataStore(); + if (!m_defaultContext && defaultDataStore) { + auto context = std::make_unique(); + m_defaultContext = context.get(); + context->processPool = WebProcessPool::allProcessPools().first().ptr(); + context->dataStore = defaultDataStore; + // Add default context to the map so that we can easily find it for + // created/deleted pages. + PAL::SessionID sessionID = context->dataStore->sessionID(); + m_browserContexts.set(toBrowserContextIDProtocolString(sessionID), WTFMove(context)); + } + + WebsiteDataStore::forEachWebsiteDataStore([this] (WebsiteDataStore& dataStore) { + dataStore.setDownloadInstrumentation(this); + }); + for (auto& pool : WebProcessPool::allProcessPools()) { + for (auto& process : pool->processes()) { + for (auto* page : process->pages()) + didCreateInspectorController(*page); + } + } + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::disable() +{ + if (!m_isEnabled) + return { }; + + m_isEnabled = false; + + for (auto it = m_pageProxyChannels.begin(); it != m_pageProxyChannels.end(); ++it) + it->value->disconnect(); + m_pageProxyChannels.clear(); + + WebsiteDataStore::forEachWebsiteDataStore([] (WebsiteDataStore& dataStore) { + dataStore.setDownloadInstrumentation(nullptr); + dataStore.setDownloadForAutomation(std::optional(), String()); + }); + for (auto& it : m_browserContexts) { + it.value->dataStore->setDownloadInstrumentation(nullptr); + it.value->pages.clear(); + } + m_browserContextDeletions.clear(); + return { }; +} + +void InspectorPlaywrightAgent::close(Ref&& callback) +{ + closeImpl([callback = WTFMove(callback)] (String error) { + if (!callback->isActive()) + return; + if (error.isNull()) + callback->sendSuccess(); + else + callback->sendFailure(error); + }); +} + +void InspectorPlaywrightAgent::closeImpl(Function&& callback) +{ + Vector pages; + // If Web Process crashed it will be disconnected from its pool until + // the page reloads. So we cannot discover such processes and the pages + // by traversing all process pools and their processes. Instead we look at + // all existing Web Processes wether in a pool or not. + for (auto* process : WebProcessProxy::allProcessesForInspector()) { + for (auto* page : process->pages()) + pages.append(page); + } + for (auto* page : pages) + page->closePage(); + + if (!m_defaultContext) { + m_client->closeBrowser(); + callback(String()); + return; + } + + m_defaultContext->dataStore->syncLocalStorage([this, callback = WTFMove(callback)] () { + if (m_client == nullptr) { + callback("no platform delegate to close browser"); + } else { + m_client->closeBrowser(); + callback(String()); + } + }); + +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::createContext(const String& proxyServer, const String& proxyBypassList) +{ + String errorString; + std::unique_ptr browserContext = m_client->createBrowserContext(errorString, proxyServer, proxyBypassList); + if (!browserContext) + return makeUnexpected(errorString); + + // Ensure network process. + browserContext->dataStore->networkProcess(); + browserContext->dataStore->setDownloadInstrumentation(this); + + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + String browserContextID = toBrowserContextIDProtocolString(sessionID); + m_browserContexts.set(browserContextID, WTFMove(browserContext)); + return browserContextID; +} + +void InspectorPlaywrightAgent::deleteContext(const String& browserContextID, Ref&& callback) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!lookupBrowserContext(errorString, browserContextID)) { + callback->sendFailure(errorString); + return; + } + + if (browserContext == m_defaultContext) { + callback->sendFailure("Cannot delete default context"_s); + return; + } + + auto pages = browserContext->pages; + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + auto contextHolder = m_browserContexts.take(browserContextID); + if (pages.isEmpty()) { + callback->sendSuccess(); + } else { + m_browserContextDeletions.set(browserContextID, makeUnique(WTFMove(contextHolder), pages.size(), WTFMove(callback))); + for (auto* page : pages) + page->closePage(); + } + m_client->deleteBrowserContext(errorString, sessionID); +} + +void InspectorPlaywrightAgent::getLocalStorageData(const String& browserContextID, Ref&& callback) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!lookupBrowserContext(errorString, browserContextID)) { + callback->sendFailure(errorString); + return; + } + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + NetworkProcessProxy& networkProcess = browserContext->dataStore->networkProcess(); + networkProcess.sendWithAsyncReply(Messages::NetworkProcess::GetLocalStorageData(sessionID), + [callback = WTFMove(callback)](Vector>>&& data) { + if (!callback->isActive()) + return; + auto origins = JSON::ArrayOf::create(); + for (const auto& originData : data) { + auto items = JSON::ArrayOf::create(); + for (const auto& entry : originData.second) { + items->addItem(Inspector::Protocol::Playwright::NameValue::create() + .setName(entry.key) + .setValue(entry.value) + .release()); + } + origins->addItem(Inspector::Protocol::Playwright::OriginStorage::create() + .setOrigin(originData.first.toString()) + .setItems(WTFMove(items)) + .release()); + } + callback->sendSuccess(WTFMove(origins)); + }, 0); +} + +void InspectorPlaywrightAgent::setLocalStorageData(const String& browserContextID, Ref&& origins, Ref&& callback) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!lookupBrowserContext(errorString, browserContextID)) { + callback->sendFailure(errorString); + return; + } + + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + NetworkProcessProxy& networkProcess = browserContext->dataStore->networkProcess(); + if (!networkProcess.hasConnection()) { + callback->sendFailure("No connection to the nework process"); + return; + } + + uint64_t pageGroupID = browserContext->processPool->defaultPageGroup().pageGroupID(); + StorageNamespaceIdentifier storageNamespaceID = makeObjectIdentifier(pageGroupID); + + Vector>> data; + for (const auto& value : origins.get()) { + auto obj = value->asObject(); + if (!obj) { + callback->sendFailure("Invalid OriginStorage format"_s); + return; + } + + String origin = obj->getString("origin"); + if (origin.isEmpty()) { + callback->sendFailure("Empty origin"_s); + return; + } + + auto url = URL(URL(), origin); + if (!url.isValid()) { + callback->sendFailure("Invalid origin URL"_s); + return; + } + + auto items = obj->getArray("items"); + if (!items) { + callback->sendFailure("Invalid item array format"_s); + return; + } + + HashMap map; + for (const auto& item : *items) { + auto itemObj = item->asObject(); + if (!itemObj) { + callback->sendFailure("Invalid item format"_s); + return; + } + + String name = itemObj->getString("name"); + String value = itemObj->getString("value");; + if (name.isEmpty()) { + callback->sendFailure("Item name cannot be empty"_s); + return; + } + + map.set(name, value); + } + data.append({ WebCore::SecurityOriginData::fromURL(url), WTFMove(map) }); + } + + networkProcess.sendWithAsyncReply(Messages::NetworkProcess::SetLocalStorageData(sessionID, storageNamespaceID, data), [callback = WTFMove(callback)] (const String& error) { + if (error.isEmpty()) + callback->sendSuccess(); + else + callback->sendFailure(error); + }); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::createPage(const String& browserContextID) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!browserContext) + return makeUnexpected(errorString); + + RefPtr page = m_client->createPage(errorString, *browserContext); + if (!page) + return makeUnexpected(errorString); + + return toPageProxyIDProtocolString(*page); +} + +WebFrameProxy* InspectorPlaywrightAgent::frameForID(const String& frameID, String& error) +{ + 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) +{ + auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID); + if (!pageProxyChannel) { + callback->sendFailure("Cannot find page proxy with provided 'pageProxyId'"_s); + return; + } + + WebCore::ResourceRequest resourceRequest { url }; + + if (!!referrer) + resourceRequest.setHTTPReferrer(referrer); + + if (!resourceRequest.url().isValid()) { + callback->sendFailure("Cannot navigate to invalid URL"_s); + return; + } + + WebFrameProxy* frame = nullptr; + if (!!frameID) { + String error; + frame = frameForID(frameID, error); + if (!frame) { + callback->sendFailure(error); + return; + } + + if (frame->page() != &pageProxyChannel->page()) { + callback->sendFailure("Frame with specified is not from the specified page"_s); + return; + } + } + + pageProxyChannel->page().inspectorController().navigate(WTFMove(resourceRequest), frame, [callback = WTFMove(callback)](const String& error, uint64_t navigationID) { + if (!error.isEmpty()) { + callback->sendFailure(error); + return; + } + + String navigationIDString; + if (navigationID) + navigationIDString = String::number(navigationID); + callback->sendSuccess(navigationIDString); + }); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setIgnoreCertificateErrors(const String& browserContextID, bool ignore) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + PAL::SessionID sessionID = browserContext->dataStore->sessionID(); + NetworkProcessProxy& networkProcess = browserContext->dataStore->networkProcess(); + networkProcess.send(Messages::NetworkProcess::SetIgnoreCertificateErrors(sessionID, ignore), 0); + return { }; +} + +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->dataStore->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, Ref&& in_cookies, Ref&& callback) { + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) { + callback->sendFailure(errorString); + return; + } + + NetworkProcessProxy& networkProcess = browserContext->dataStore->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 = item->asObject(); + if (!obj) { + callback->sendFailure("Invalid cookie payload format"_s); + return; + } + + WebCore::Cookie cookie; + cookie.name = obj->getString("name"); + cookie.value = obj->getString("value"); + cookie.domain = obj->getString("domain"); + cookie.path = obj->getString("path"); + if (!cookie.name || !cookie.value || !cookie.domain || !cookie.path) { + callback->sendFailure("Invalid file payload format"_s); + return; + } + + std::optional expires = obj->getDouble("expires"); + if (expires && *expires != -1) + cookie.expires = *expires; + if (std::optional value = obj->getBoolean("httpOnly")) + cookie.httpOnly = *value; + if (std::optional value = obj->getBoolean("secure")) + cookie.secure = *value; + if (std::optional value = obj->getBoolean("session")) + cookie.session = *value; + 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->dataStore->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); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setLanguages(Ref&& languages, const String& browserContextID) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + Vector items; + for (const auto& value : languages.get()) { + String language; + if (!value->asString(language)) + return makeUnexpected("Language must be a string"_s); + + items.append(language); + } + + browserContext->dataStore->setLanguagesForAutomation(WTFMove(items)); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setDownloadBehavior(const String& behavior, const String& downloadPath, const String& browserContextID) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + std::optional allow; + if (behavior == "allow"_s) + allow = true; + if (behavior == "deny"_s) + allow = false; + browserContext->dataStore->setDownloadForAutomation(allow, downloadPath); + return { }; +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::setGeolocationOverride(const String& browserContextID, RefPtr&& geolocation) +{ + String errorString; + BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID); + if (!errorString.isEmpty()) + return makeUnexpected(errorString); + + auto* geoManager = browserContext->processPool->supplement(); + if (!geoManager) + return makeUnexpected("Internal error: geolocation manager is not available."_s); + + if (geolocation) { + std::optional timestamp = geolocation->getDouble("timestamp"); + std::optional latitude = geolocation->getDouble("latitude"); + std::optional longitude = geolocation->getDouble("longitude"); + std::optional accuracy = geolocation->getDouble("accuracy"); + if (!timestamp || !latitude || !longitude || !accuracy) + return makeUnexpected("Invalid geolocation format"_s); + + auto position = WebGeolocationPosition::create(WebCore::GeolocationPositionData(*timestamp, *latitude, *longitude, *accuracy)); + geoManager->providerDidChangePosition(&position.get()); + } else { + geoManager->providerDidFailToDeterminePosition("Position unavailable"_s); + } + return { }; +} + +void InspectorPlaywrightAgent::downloadCreated(const String& uuid, const WebCore::ResourceRequest& request, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr download) +{ + if (!m_isEnabled) + return; + String frameID = WebCore::InspectorPageAgent::makeFrameID(page->process().coreProcessIdentifier(), frameInfoData.frameID ? *frameInfoData.frameID : page->mainFrame()->frameID()); + m_downloads.set(uuid, download); + m_frontendDispatcher->downloadCreated( + toPageProxyIDProtocolString(*page), + frameID, + uuid, request.url().string()); +} + +void InspectorPlaywrightAgent::downloadFilenameSuggested(const String& uuid, const String& suggestedFilename) +{ + if (!m_isEnabled) + return; + m_frontendDispatcher->downloadFilenameSuggested(uuid, suggestedFilename); +} + +void InspectorPlaywrightAgent::downloadFinished(const String& uuid, const String& error) +{ + if (!m_isEnabled) + return; + m_frontendDispatcher->downloadFinished(uuid, error); + m_downloads.remove(uuid); +} + +Inspector::Protocol::ErrorStringOr InspectorPlaywrightAgent::cancelDownload(const String& uuid) +{ + if (!m_isEnabled) + return { }; + auto download = m_downloads.get(uuid); + if (!download) + return { }; + download->cancel([] (auto*) {}); + return { }; +} + +BrowserContext* InspectorPlaywrightAgent::getExistingBrowserContext(const String& browserContextID) +{ + BrowserContext* browserContext = m_browserContexts.get(browserContextID); + if (browserContext) + return browserContext; + + auto it = m_browserContextDeletions.find(browserContextID); + RELEASE_ASSERT(it != m_browserContextDeletions.end()); + return it->value->context(); +} + +BrowserContext* InspectorPlaywrightAgent::lookupBrowserContext(ErrorString& errorString, const String& browserContextID) +{ + if (!browserContextID) { + if (!m_defaultContext) + errorString = "Browser started with no default context"_s; + return m_defaultContext; + } + + BrowserContext* browserContext = m_browserContexts.get(browserContextID); + if (!browserContext) + errorString = "Could not find browser context for given id"_s; + return browserContext; +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..1d1f360f01740c001507acac6b1ba90598934917 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include "WebPageInspectorController.h" +#include "WebProcessPool.h" +#include "DownloadProxy.h" +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +class PlaywrightFrontendDispatcher; +} + +namespace PAL { +class SessionID; +} + +namespace WebKit { + +class WebFrameProxy; + +class InspectorPlaywrightAgent final + : public WebPageInspectorControllerObserver + , public Inspector::PlaywrightBackendDispatcherHandler + , public DownloadInstrumentation { + WTF_MAKE_NONCOPYABLE(InspectorPlaywrightAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + explicit InspectorPlaywrightAgent(std::unique_ptr client); + ~InspectorPlaywrightAgent() override; + + // Transport + void connectFrontend(Inspector::FrontendChannel&); + void disconnectFrontend(); + void dispatchMessageFromFrontend(const String& message); + +private: + class BrowserContextDeletion; + class PageProxyChannel; + class TargetHandler; + + // WebPageInspectorControllerObserver + void didCreateInspectorController(WebPageProxy&) override; + void willDestroyInspectorController(WebPageProxy&) override; + void didFailProvisionalLoad(WebPageProxy&, uint64_t navigationID, const String& error) override; + void willCreateNewPage(WebPageProxy&, const WebCore::WindowFeatures&, const URL&) override; + void didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) override; + + // PlaywrightDispatcherHandler + Inspector::Protocol::ErrorStringOr enable() override; + Inspector::Protocol::ErrorStringOr disable() override; + void close(Ref&&) override; + Inspector::Protocol::ErrorStringOr createContext(const String& proxyServer, const String& proxyBypassList) override; + void deleteContext(const String& browserContextID, Ref&& callback) override; + Inspector::Protocol::ErrorStringOr createPage(const String& browserContextID) override; + void navigate(const String& url, const String& pageProxyID, const String& frameId, const String& referrer, Ref&&) override; + Inspector::Protocol::ErrorStringOr setIgnoreCertificateErrors(const String& browserContextID, bool ignore) override; + + void getAllCookies(const String& browserContextID, Ref&&) override; + void setCookies(const String& browserContextID, Ref&& in_cookies, Ref&&) override; + void deleteAllCookies(const String& browserContextID, Ref&&) override; + + void getLocalStorageData(const String& browserContextID, Ref&&) override; + void setLocalStorageData(const String& browserContextID, Ref&& origins, Ref&&) override; + + Inspector::Protocol::ErrorStringOr setGeolocationOverride(const String& browserContextID, RefPtr&& geolocation) override; + Inspector::Protocol::ErrorStringOr setLanguages(Ref&& languages, const String& browserContextID) override; + Inspector::Protocol::ErrorStringOr setDownloadBehavior(const String& behavior, const String& downloadPath, const String& browserContextID) override; + Inspector::Protocol::ErrorStringOr cancelDownload(const String& uuid) override; + + // DownloadInstrumentation + void downloadCreated(const String& uuid, const WebCore::ResourceRequest&, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr download) override; + void downloadFilenameSuggested(const String& uuid, const String& suggestedFilename) override; + void downloadFinished(const String& uuid, const String& error) override; + + BrowserContext* getExistingBrowserContext(const String& browserContextID); + BrowserContext* lookupBrowserContext(Inspector::ErrorString&, const String& browserContextID); + WebFrameProxy* frameForID(const String& frameID, String& error); + void closeImpl(Function&&); + + Inspector::FrontendChannel* m_frontendChannel { nullptr }; + Ref m_frontendRouter; + Ref m_backendDispatcher; + std::unique_ptr m_client; + std::unique_ptr m_frontendDispatcher; + Ref m_playwrightDispatcher; + HashMap> m_pageProxyChannels; + BrowserContext* m_defaultContext; + HashMap> m_downloads; + HashMap> m_browserContexts; + HashMap> m_browserContextDeletions; + bool m_isEnabled { false }; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h new file mode 100644 index 0000000000000000000000000000000000000000..11c8eadafca764aa549cb27c24967e15e6975774 --- /dev/null +++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include +#include +#include +#include +#include + +namespace WebKit { + +class WebsiteDataStore; +class WebPageProxy; +class WebProcessPool; + +class BrowserContext { + WTF_MAKE_NONCOPYABLE(BrowserContext); + WTF_MAKE_FAST_ALLOCATED; +public: + BrowserContext(); + ~BrowserContext(); + + RefPtr dataStore; + RefPtr processPool; + HashSet pages; +}; + +class InspectorPlaywrightAgentClient { +public: + virtual ~InspectorPlaywrightAgentClient() = default; + virtual RefPtr createPage(WTF::String& error, const BrowserContext& context) = 0; + virtual void closeBrowser() = 0; + virtual std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) = 0; + virtual void deleteBrowserContext(WTF::String& error, PAL::SessionID) = 0; +}; + +} // 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 7a14cfba15c103a2d4fe263fa49d25af3c396ec2..3ee0e154349661632799057c71f1d1f1551c2d69 100644 --- a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp +++ b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp @@ -96,8 +96,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/PageClient.h b/Source/WebKit/UIProcess/PageClient.h index 08cc289039924d337489368f36c505cc68896745..ac9688f8bdb31e0011ab6830695f81bb477a24d3 100644 --- a/Source/WebKit/UIProcess/PageClient.h +++ b/Source/WebKit/UIProcess/PageClient.h @@ -319,6 +319,11 @@ public: virtual void selectionDidChange() = 0; #endif +// Paywright begin +#if PLATFORM(COCOA) + virtual RetainPtr takeSnapshotForAutomation() = 0; +#endif +// Paywright end #if PLATFORM(COCOA) || PLATFORM(GTK) virtual RefPtr takeViewSnapshot(std::optional&&) = 0; #endif diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp index c97552f4e63b5923c6cb1c9043dfb2b2c5cf23c6..16b9f932794144ca2ecf48a63f9a9cfc04be39ab 100644 --- a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp +++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp @@ -598,3 +598,5 @@ bool ProvisionalPageProxy::sendMessage(UniqueRef&& encoder, Option } } // namespace WebKit + +#undef MESSAGE_CHECK diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd8b28e692dca4078eb710b2a97e61716126a4cb --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RemoteInspectorPipe.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgent.h" +#include +#include +#include +#include +#include +#include + +#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(InspectorPlaywrightAgent& playwrightAgent) + : m_playwrightAgent(playwrightAgent) +{ + m_remoteFrontendChannel = makeUnique(); + start(); +} + +RemoteInspectorPipe::~RemoteInspectorPipe() +{ + stop(); +} + +bool RemoteInspectorPipe::start() +{ + if (m_receiverThread) + return true; + +#if PLATFORM(WIN) + readHandle = reinterpret_cast(_get_osfhandle(readFD)); + writeHandle = reinterpret_cast(_get_osfhandle(writeFD)); +#endif + + m_playwrightAgent.connectFrontend(*m_remoteFrontendChannel); + m_terminated = false; + m_receiverThread = Thread::create("Inspector pipe reader", [this] { + workerRun(); + }); + return true; +} + +void RemoteInspectorPipe::stop() +{ + if (!m_receiverThread) + return; + + m_playwrightAgent.disconnectFrontend(); + + m_terminated = true; + m_receiverThread->waitForCompletion(); + m_receiverThread = nullptr; +} + +void RemoteInspectorPipe::workerRun() +{ + const size_t bufSize = 256 * 1024; + auto buffer = makeUniqueArray(bufSize); + Vector line; + while (!m_terminated) { + size_t size = ReadBytes(buffer.get(), bufSize, false); + if (!size) { + RunLoop::main().dispatch([this] { + if (!m_terminated) + m_playwrightAgent.disconnectFrontend(); + }); + break; + } + size_t start = 0; + size_t end = line.size(); + line.append(buffer.get(), size); + while (true) { + for (; end < line.size(); ++end) { + if (line[end] == '\0') + break; + } + if (end == line.size()) + break; + + if (end > start) { + String message = String::fromUTF8(line.data() + start, end - start); + RunLoop::main().dispatch([this, message = WTFMove(message)] { + if (!m_terminated) + m_playwrightAgent.dispatchMessageFromFrontend(message); + }); + } + ++end; + start = end; + } + if (start != 0 && start < line.size()) + memmove(line.data(), line.data() + start, line.size() - start); + line.shrink(line.size() - start); + } +} + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.h b/Source/WebKit/UIProcess/RemoteInspectorPipe.h new file mode 100644 index 0000000000000000000000000000000000000000..6d04f9290135069359ce6bf8726546482fd1dc95 --- /dev/null +++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include +#include +#include + +namespace Inspector { +class FrontendChannel; +} + +namespace WebKit { + +class InspectorPlaywrightAgent; + +class RemoteInspectorPipe { + WTF_MAKE_NONCOPYABLE(RemoteInspectorPipe); + WTF_MAKE_FAST_ALLOCATED; +public: + explicit RemoteInspectorPipe(InspectorPlaywrightAgent&); + ~RemoteInspectorPipe(); + +private: + class RemoteFrontendChannel; + + bool start(); + void stop(); + + void workerRun(); + + RefPtr m_receiverThread; + std::atomic m_terminated { false }; + std::unique_ptr m_remoteFrontendChannel; + InspectorPlaywrightAgent& m_playwrightAgent; +}; + +} // namespace WebKit + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/SpeechRecognitionRemoteRealtimeMediaSource.cpp b/Source/WebKit/UIProcess/SpeechRecognitionRemoteRealtimeMediaSource.cpp index e42dbf1281d36fef2e303e707d5b5baf166ee152..80fab5d4ac007f0d2da9f58bee03a5ab3c845b83 100644 --- a/Source/WebKit/UIProcess/SpeechRecognitionRemoteRealtimeMediaSource.cpp +++ b/Source/WebKit/UIProcess/SpeechRecognitionRemoteRealtimeMediaSource.cpp @@ -37,6 +37,8 @@ #include #endif +using namespace WebCore; + namespace WebKit { Ref SpeechRecognitionRemoteRealtimeMediaSource::create(SpeechRecognitionRemoteRealtimeMediaSourceManager& manager, const WebCore::CaptureDevice& captureDevice) diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockLocalConnection.h index 684b9616573761123fbcc0d94be29de519ecced6..51ff18323ece0ee15c87d63a1d6fd604377ee968 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/WebContextMenuProxy.h b/Source/WebKit/UIProcess/WebContextMenuProxy.h index 630bf1170da176dcc65d659c1fdf7c05185910e5..ec12ef12dfc7e7c00ed69e2afb10367cb02a1edf 100644 --- a/Source/WebKit/UIProcess/WebContextMenuProxy.h +++ b/Source/WebKit/UIProcess/WebContextMenuProxy.h @@ -37,6 +37,7 @@ #include "QuickLookPreviewActivity.h" #endif +OBJC_CLASS NSArray; OBJC_CLASS NSMenu; namespace WebKit { @@ -49,6 +50,7 @@ public: virtual ~WebContextMenuProxy(); virtual void show(); + virtual void hide() {} WebPageProxy* page() const { return m_page.get(); } 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..ae45b4212bdb3f6a004cc80a1d91146b540f86f5 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorEmulationAgent.h" + +#include "APIPageConfiguration.h" +#include "WebPageProxy.h" +#include "WebPreferences.h" +#include "PageClient.h" +#include +#include + + +namespace WebKit { + +using namespace Inspector; + +WebPageInspectorEmulationAgent::WebPageInspectorEmulationAgent(BackendDispatcher& backendDispatcher, WebPageProxy& page) + : InspectorAgentBase("Emulation"_s) + , m_backendDispatcher(EmulationBackendDispatcher::create(backendDispatcher, this)) + , m_page(page) +{ +} + +WebPageInspectorEmulationAgent::~WebPageInspectorEmulationAgent() +{ +} + +void WebPageInspectorEmulationAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) +{ +} + +void WebPageInspectorEmulationAgent::willDestroyFrontendAndBackend(DisconnectReason) +{ + m_commandsToRunWhenShown.clear(); +} + +void WebPageInspectorEmulationAgent::setDeviceMetricsOverride(int width, int height, bool fixedlayout, std::optional&& deviceScaleFactor, Ref&& callback) +{ +#if PLATFORM(GTK) + // On gtk, fixed layout doesn't work with compositing enabled + // FIXME: This turns off compositing forever, even if fixedLayout is disabled. + if (fixedlayout) { + auto copy = m_page.preferences().copy(); + copy->setAcceleratedCompositingEnabled(false); + m_page.setPreferences(copy); + } +#endif + + if (deviceScaleFactor) + m_page.setCustomDeviceScaleFactor(deviceScaleFactor.value()); + m_page.setUseFixedLayout(fixedlayout); + if (!m_page.pageClient().isViewVisible() && m_page.configuration().relatedPage()) { + m_commandsToRunWhenShown.append([this, width, height, callback = WTFMove(callback)]() mutable { + setSize(width, height, WTFMove(callback)); + }); + } else { + setSize(width, height, WTFMove(callback)); + } +} + +void WebPageInspectorEmulationAgent::setSize(int width, int height, Ref&& callback) +{ + platformSetSize(width, height, [callback = WTFMove(callback)](const String& error) { + if (error.isEmpty()) + callback->sendSuccess(); + else + callback->sendFailure(error); + }); +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setJavaScriptEnabled(bool enabled) +{ + auto copy = m_page.preferences().copy(); + copy->setJavaScriptEnabled(enabled); + m_page.setPreferences(copy); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setAuthCredentials(const String& username, const String& password) +{ + if (!!username && !!password) + m_page.setAuthCredentialsForAutomation(WebCore::Credential(username, password, CredentialPersistencePermanent)); + else + m_page.setAuthCredentialsForAutomation(std::optional()); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::setActiveAndFocused(std::optional&& active) +{ + m_page.setActiveForAutomation(WTFMove(active)); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::grantPermissions(const String& origin, Ref&& values) +{ + HashSet set; + for (const auto& value : values.get()) { + String name; + if (!value->asString(name)) + return makeUnexpected("Permission must be a string"_s); + + set.add(name); + } + m_permissions.set(origin, WTFMove(set)); + m_page.setPermissionsForAutomation(m_permissions); + return { }; +} + +Inspector::Protocol::ErrorStringOr WebPageInspectorEmulationAgent::resetPermissions() +{ + m_permissions.clear(); + m_page.setPermissionsForAutomation(m_permissions); + return { }; +} + +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..b3bb4880a866ee6132b8b26acf8dad81afe14d85 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class WebPageProxy; + +class WebPageInspectorEmulationAgent : public Inspector::InspectorAgentBase, public Inspector::EmulationBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(WebPageInspectorEmulationAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + WebPageInspectorEmulationAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorEmulationAgent() override; + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + void setDeviceMetricsOverride(int width, int height, bool fixedlayout, std::optional&& deviceScaleFactor, Ref&&) override; + Inspector::Protocol::ErrorStringOr setJavaScriptEnabled(bool enabled) override; + Inspector::Protocol::ErrorStringOr setAuthCredentials(const String&, const String&) override; + Inspector::Protocol::ErrorStringOr setActiveAndFocused(std::optional&&) override; + Inspector::Protocol::ErrorStringOr grantPermissions(const String& origin, Ref&& permissions) override; + Inspector::Protocol::ErrorStringOr resetPermissions() 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; + HashMap> m_permissions; +}; + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eb16b3aa8912b4cc26a2e555669c27682b76378d --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp @@ -0,0 +1,288 @@ +/* + * 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 +#include + +#include "WebPageMessages.h" + +namespace WebKit { + +using namespace Inspector; + +namespace { + +template +class CallbackList { + WTF_MAKE_FAST_ALLOCATED; +public: + ~CallbackList() + { + for (const auto& callback : m_callbacks) + callback->sendFailure("Page closed"); + } + + 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_page.setInterceptDrags(false); + 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; +} + +static String keyIdentifierForKey(const String& key) +{ + if (key.length() == 1) + return makeString("U+", hex(toASCIIUpper(key.characterAt(0)), 4)); + if (key == "Delete") + return "U+007F"; + if (key == "Backspace") + return "U+0008"; + if (key == "ArrowUp") + return "Up"; + if (key == "ArrowDown") + return "Down"; + if (key == "ArrowLeft") + return "Left"; + if (key == "ArrowRight") + return "Right"; + if (key == "Tab") + return "U+0009"; + if (key == "Pause") + return "Pause"; + if (key == "ScrollLock") + return "Scroll"; + return key; +} + +void WebPageInspectorInputAgent::dispatchKeyEvent(const String& type, std::optional&& modifiers, const String& text, const String& unmodifiedText, const String& code, const String& key, std::optional&& windowsVirtualKeyCode, std::optional&& nativeVirtualKeyCode, std::optional&& autoRepeat, std::optional&& isKeypad, std::optional&& isSystemKey, RefPtr&& commands, Ref&& callback) +{ + 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); + 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); + } + } + + String keyIdentifier = keyIdentifierForKey(key); + + bool eventIsAutoRepeat = false; + if (autoRepeat) + eventIsAutoRepeat = *autoRepeat; + bool eventIsKeypad = false; + if (isKeypad) + eventIsKeypad = *isKeypad; + bool eventIsSystemKey = false; + if (isSystemKey) + eventIsSystemKey = *isSystemKey; + WallTime timestamp = WallTime::now(); + + // cancel any active drag on Escape + if (eventType == WebKit::WebEvent::KeyDown && key == "Escape" && m_page.cancelDragIfNeeded()) { + callback->sendSuccess(); + return; + } + + m_keyboardCallbacks->append(WTFMove(callback)); + platformDispatchKeyEvent( + eventType, + text, + unmodifiedText, + key, + code, + keyIdentifier, + eventWindowsVirtualKeyCode, + eventNativeVirtualKeyCode, + eventIsAutoRepeat, + eventIsKeypad, + eventIsSystemKey, + eventModifiers, + eventCommands, + timestamp); +} + +void WebPageInspectorInputAgent::dispatchMouseEvent(const String& type, int x, int y, std::optional&& modifiers, const String& button, std::optional&& buttons, std::optional&& clickCount, std::optional&& deltaX, std::optional&& deltaY, Ref&& callback) +{ + 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)); + + // We intercept any drags generated by this mouse event + // to prevent them from creating actual drags in the host + // operating system. This is turned off in the callback. + m_page.setInterceptDrags(true); +#if PLATFORM(MAC) + platformDispatchMouseEvent(type, x, y, WTFMove(modifiers), button, WTFMove(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 +} + +void WebPageInspectorInputAgent::dispatchTapEvent(int x, int y, std::optional&& modifiers, Ref&& callback) { + m_page.sendWithAsyncReply(Messages::WebPage::FakeTouchTap(WebCore::IntPoint(x, y), modifiers ? *modifiers : 0), [callback]() { + callback->sendSuccess(); + }); +} +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h new file mode 100644 index 0000000000000000000000000000000000000000..94e9f24353337169992724e2fcdf7086dd888fa6 --- /dev/null +++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.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 + +#include "WebEvent.h" +#include "WebKeyboardEvent.h" +#include "WebMouseEvent.h" +#include +#include +#include +#include + +namespace Inspector { +class BackendDispatcher; +class FrontendChannel; +class FrontendRouter; +} + +namespace WebKit { + +class NativeWebKeyboardEvent; +class WebPageProxy; + +class WebPageInspectorInputAgent : public Inspector::InspectorAgentBase, public Inspector::InputBackendDispatcherHandler { + WTF_MAKE_NONCOPYABLE(WebPageInspectorInputAgent); + WTF_MAKE_FAST_ALLOCATED; +public: + WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page); + ~WebPageInspectorInputAgent() override; + + void didProcessAllPendingKeyboardEvents(); + void didProcessAllPendingMouseEvents(); + + void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override; + void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override; + + // Protocol handler + void dispatchKeyEvent(const String& type, std::optional&& modifiers, const String& text, const String& unmodifiedText, const String& code, const String& key, std::optional&& windowsVirtualKeyCode, std::optional&& nativeVirtualKeyCode, std::optional&& autoRepeat, std::optional&& isKeypad, std::optional&& isSystemKey, RefPtr&&, Ref&& callback) override; + void dispatchMouseEvent(const String& type, int x, int y, std::optional&& modifiers, const String& button, std::optional&& buttons, std::optional&& clickCount, std::optional&& deltaX, std::optional&& deltaY, Ref&& callback) override; + void dispatchTapEvent(int x, int y, std::optional&& modifiers, Ref&& callback) override; + +private: + void platformDispatchKeyEvent(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, 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, std::optional&& modifier, const String& button, std::optional&& 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 0f0cb6da22484e0decfc29293215b55833663104..979bb6e4bb6a3c5e81808a4b423856e47892a7eb 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.cpp +++ b/Source/WebKit/UIProcess/WebPageProxy.cpp @@ -241,7 +241,7 @@ #include "ViewSnapshotStore.h" #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) #include #endif @@ -612,6 +612,10 @@ WebPageProxy::~WebPageProxy() #if ENABLE(MEDIA_SESSION_COORDINATOR) && HAVE(GROUP_ACTIVITIES) GroupActivitiesSessionNotifier::sharedNotifier().removeWebPage(*this); #endif + +#if PLATFORM(COCOA) + releaseInspectorDragPasteboard(); +#endif } // FIXME: Should return a const PageClient& and add a separate non-const @@ -994,6 +998,7 @@ void WebPageProxy::finishAttachingToWebProcess(ProcessLaunchReason reason) m_pageLoadState.didSwapWebProcesses(); if (reason != ProcessLaunchReason::InitialProcess) m_drawingArea->waitForBackingStoreUpdateOnNextPaint(); + m_inspectorController->didFinishAttachingToWebProcess(); } void WebPageProxy::didAttachToRunningProcess() @@ -1323,6 +1328,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) @@ -1853,6 +1873,31 @@ void WebPageProxy::setControlledByAutomation(bool controlled) websiteDataStore().networkProcess().send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0); } +void WebPageProxy::setAuthCredentialsForAutomation(std::optional&& credentials) +{ + m_credentialsForAutomation = WTFMove(credentials); +} + +void WebPageProxy::setPermissionsForAutomation(const HashMap>& permissions) +{ + m_permissionsForAutomation = permissions; +} + +void WebPageProxy::setActiveForAutomation(std::optional active) { + m_activeForAutomation = active; + OptionSet state; + state.add(ActivityState::IsFocused); + state.add(ActivityState::WindowIsActive); + state.add(ActivityState::IsVisible); + state.add(ActivityState::IsVisibleOrOccluded); + activityStateDidChange(state); +} + +void WebPageProxy::logToStderr(const String& str) +{ + fprintf(stderr, "RENDERER: %s\n", str.utf8().data()); +} + void WebPageProxy::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type) { MESSAGE_CHECK(m_process, !targetId.isEmpty()); @@ -2043,6 +2088,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()) @@ -2615,6 +2679,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag { if (!hasRunningProcess()) return; + if (action == DragControllerAction::Entered || action == DragControllerAction::Updated) + m_dragEventsQueued++; #if PLATFORM(GTK) UNUSED_PARAM(dragStorageName); UNUSED_PARAM(sandboxExtensionHandle); @@ -2625,6 +2691,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag m_process->assumeReadAccessToBaseURL(*this, url); ASSERT(dragData.platformData()); +#endif +#if PLATFORM(GTK) || PLATFORM(WPE) send(Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags())); #else send(Messages::WebPage::PerformDragControllerAction(action, dragData, sandboxExtensionHandle, sandboxExtensionsForUpload)); @@ -2640,18 +2708,41 @@ void WebPageProxy::didPerformDragControllerAction(std::optionaldidProcessAllPendingMouseEvents(); + } -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) void WebPageProxy::startDrag(SelectionData&& selectionData, OptionSet dragOperationMask, const ShareableBitmap::Handle& dragImageHandle) { - RefPtr dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr; - pageClient().startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage)); + if (m_interceptDrags) { + m_dragSelectionData = WTFMove(selectionData); + m_dragSourceOperationMask = dragOperationMask; + } else { +#if PLATFORM(GTK) + RefPtr dragImage = !dragImageHandle.isNull() ? ShareableBitmap::create(dragImageHandle) : nullptr; + pageClient().startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage)); +#endif + } + + didStartDrag(); +} +#endif +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) +void WebPageProxy::startDrag(WebCore::DragDataMap& dragDataMap) +{ + if (m_interceptDrags) { + m_dragSelectionData = dragDataMap; + m_dragSourceOperationMask = WebCore::anyDragOperation(); + } didStartDrag(); } #endif + void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet dragOperationMask) { if (!hasRunningProcess()) @@ -2660,6 +2751,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo setDragCaretRect({ }); } +bool WebPageProxy::cancelDragIfNeeded() { + if (!m_dragSelectionData) + return false; + m_dragSelectionData = std::nullopt; +#if PLATFORM(COCOA) + releaseInspectorDragPasteboard(); +#endif + + dragEnded(m_lastMousePositionForDrag, IntPoint(), m_dragSourceOperationMask); + return true; +} + +#if !PLATFORM(COCOA) +void WebPageProxy::setInterceptDrags(bool shouldIntercept) { + m_interceptDrags = shouldIntercept; +} +#endif + void WebPageProxy::didPerformDragOperation(bool handled) { pageClient().didPerformDragOperation(handled); @@ -2672,8 +2781,18 @@ void WebPageProxy::didStartDrag() discardQueuedMouseEvents(); send(Messages::WebPage::DidStartDrag()); + + if (m_interceptDrags) { +#if PLATFORM(WIN) || PLATFORM(COCOA) + DragData dragData(*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask); +#else + DragData dragData(&*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask); +#endif + dragEntered(dragData); + dragUpdated(dragData); + } } - + void WebPageProxy::dragCancelled() { if (hasRunningProcess()) @@ -2778,16 +2897,38 @@ void WebPageProxy::processNextQueuedMouseEvent() m_process->startResponsivenessTimer(); } - std::optional sandboxExtensions; + m_lastMousePositionForDrag = event.position(); + if (!m_dragSelectionData) { + std::optional sandboxExtensions; #if PLATFORM(MAC) - bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEvent::MouseMove && event.button() != WebMouseEvent::Button::NoButton; - if (eventMayStartDrag) - sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, std::nullopt); + bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEvent::MouseMove && event.button() != WebMouseEvent::Button::NoButton; + if (eventMayStartDrag) + sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, std::nullopt); #endif - - LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size()); - send(Messages::WebPage::MouseEvent(event, sandboxExtensions)); + + LOG(MouseHandling, "UIProcess: sent mouse event %s (queue size %zu)", webMouseEventTypeString(eventType), m_mouseEventQueue.size()); + send(Messages::WebPage::MouseEvent(event, sandboxExtensions)); + } else { +#if PLATFORM(WIN) || PLATFORM(COCOA) + DragData dragData(*m_dragSelectionData, event.position(), event.globalPosition(), m_dragSourceOperationMask); +#else + DragData dragData(&*m_dragSelectionData, event.position(), event.globalPosition(), m_dragSourceOperationMask); +#endif + if (eventType == WebEvent::MouseMove) { + dragUpdated(dragData); + } else if (eventType == WebEvent::MouseUp) { + if (m_currentDragOperation && m_dragSourceOperationMask.containsAny(m_currentDragOperation.value())) { + SandboxExtension::Handle sandboxExtensionHandle; + SandboxExtension::HandleArray sandboxExtensionsForUpload; + + performDragOperation(dragData, "", WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload)); + } + m_dragSelectionData = std::nullopt; + dragEnded(event.position(), event.globalPosition(), m_dragSourceOperationMask); + } + didReceiveEvent(eventType, true); + } } void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function&& action) @@ -3007,7 +3148,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(); @@ -3040,7 +3181,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 @@ -3423,6 +3564,8 @@ void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, A policyAction = PolicyAction::Download; if (policyAction != PolicyAction::Use || !frame.isMainFrame() || !navigation) { + if (policyAction == PolicyAction::Download && navigation) + m_decidePolicyForResponseRequest = navigation->currentRequest(); receivedPolicyDecision(policyAction, navigation, WTFMove(policies), WTFMove(navigationAction), WTFMove(sender)); return; } @@ -3489,6 +3632,7 @@ void WebPageProxy::receivedNavigationPolicyDecision(PolicyAction policyAction, A void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr&& websitePolicies, Variant, Ref>&& navigationActionOrResponse, Ref&& sender, std::optional sandboxExtensionHandle, WillContinueLoadInNewProcess willContinueLoadInNewProcess) { + m_inspectorController->didReceivePolicyDecision(action, navigation ? navigation->navigationID() : 0); if (!hasRunningProcess()) { sender->send(PolicyDecision { sender->identifier(), isNavigatingToAppBoundDomain(), PolicyAction::Ignore, 0, std::nullopt, std::nullopt }); return; @@ -4227,6 +4371,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; @@ -4559,6 +4708,7 @@ void WebPageProxy::didDestroyNavigation(uint64_t navigationID) return; 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) @@ -4781,6 +4931,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; @@ -5223,7 +5375,14 @@ void WebPageProxy::decidePolicyForNavigationActionAsync(FrameIdentifier frameID, NavigationActionData&& navigationActionData, FrameInfoData&& originatingFrameInfo, std::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, @@ -5736,6 +5895,7 @@ void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, WebPa auto* originatingPage = m_process->webPage(originatingPageID); auto originatingFrameInfo = API::FrameInfo::create(WTFMove(originatingFrameInfoData), originatingPage); auto mainFrameURL = m_mainFrame ? m_mainFrame->url() : URL(); + m_inspectorController->willCreateNewPage(windowFeatures, request.url()); auto completionHandler = [this, protectedThis = makeRef(*this), mainFrameURL, request, reply = WTFMove(reply), privateClickMeasurement = navigationActionData.privateClickMeasurement] (RefPtr newPage) mutable { if (!newPage) { reply(std::nullopt, std::nullopt); @@ -5776,6 +5936,7 @@ void WebPageProxy::createNewPage(FrameInfoData&& originatingFrameInfoData, WebPa void WebPageProxy::showPage() { m_uiClient->showPage(this); + m_inspectorController->didShowPage(); } void WebPageProxy::exitFullscreenImmediately() @@ -5811,6 +5972,10 @@ void WebPageProxy::closePage() if (isClosed()) return; +#if ENABLE(CONTEXT_MENUS) + if (m_activeContextMenu) + m_activeContextMenu->hide(); +#endif WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:"); pageClient().clearAllEditCommands(); m_uiClient->close(this); @@ -5847,6 +6012,8 @@ void WebPageProxy::runJavaScriptAlert(FrameIdentifier frameID, FrameInfoData&& f } runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { + if (page.m_inspectorDialogAgent) + page.m_inspectorDialogAgent->javascriptDialogOpening("alert"_s, message); page.m_uiClient->runJavaScriptAlert(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)]() mutable { reply(); completion(); @@ -5868,6 +6035,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); runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { page.m_uiClient->runJavaScriptConfirm(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](bool result) mutable { @@ -5891,6 +6060,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); runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply), defaultValue](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler&& completion) mutable { page.m_uiClient->runJavaScriptPrompt(page, message, defaultValue, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](auto& result) mutable { @@ -6051,6 +6222,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(); @@ -7258,6 +7431,8 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) if (auto* automationSession = process().processPool().automationSession()) automationSession->mouseEventsFlushedForPage(*this); didFinishProcessingAllPendingMouseEvents(); + if (m_dragEventsQueued == 0) + m_inspectorController->didProcessAllPendingMouseEvents(); } break; } @@ -7284,7 +7459,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()); auto event = m_keyEventQueue.takeFirst(); MESSAGE_CHECK(m_process, type == event.type()); @@ -7303,7 +7477,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); @@ -7312,6 +7485,7 @@ void WebPageProxy::didReceiveEvent(uint32_t opaqueType, bool handled) if (!canProcessMoreKeyEvents) { if (auto* automationSession = process().processPool().automationSession()) automationSession->keyboardEventsFlushedForPage(*this); + m_inspectorController->didProcessAllPendingKeyboardEvents(); } break; } @@ -7642,7 +7816,10 @@ void WebPageProxy::dispatchProcessDidTerminate(ProcessTerminationReason reason) { WEBPAGEPROXY_RELEASE_LOG_ERROR(Loading, "dispatchProcessDidTerminate: reason=%d", reason); - bool handledByClient = false; + bool handledByClient = m_inspectorController->pageCrashed(reason); + if (handledByClient) + return; + if (m_loaderClient) handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); else @@ -8015,6 +8192,7 @@ static const Vector& mediaRelatedIOKitClasses() WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& process, DrawingAreaProxy& drawingArea, RefPtr&& websitePolicies) { + WebPageCreationParameters parameters; parameters.processDisplayName = configuration().processDisplayName(); @@ -8207,6 +8385,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc parameters.shouldRelaxThirdPartyCookieBlocking = m_configuration->shouldRelaxThirdPartyCookieBlocking(); parameters.canUseCredentialStorage = m_canUseCredentialStorage; + parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseLoading(); + #if PLATFORM(GTK) parameters.themeName = pageClient().themeName(); #endif @@ -8283,6 +8463,14 @@ void WebPageProxy::gamepadActivity(const Vector& gamepadDatas, Even void WebPageProxy::didReceiveAuthenticationChallengeProxy(Ref&& authenticationChallenge, NegotiatedLegacyTLS negotiatedLegacyTLS) { + if (m_credentialsForAutomation.has_value()) { + 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] (bool shouldAllowLegacyTLS) { if (shouldAllowLegacyTLS) @@ -8376,6 +8564,15 @@ void WebPageProxy::requestGeolocationPermissionForFrame(GeolocationIdentifier ge request->deny(); }; + auto securityOrigin = frameInfo.securityOrigin.securityOrigin(); + 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 a964e62763a1d964eee6f464aa2e3a06c0637640..9160f8b7430d9d9e8031b23bf2bb8c1df2879099 100644 --- a/Source/WebKit/UIProcess/WebPageProxy.h +++ b/Source/WebKit/UIProcess/WebPageProxy.h @@ -38,6 +38,7 @@ #include "GeolocationIdentifier.h" #include "GeolocationPermissionRequestManagerProxy.h" #include "HiddenPageThrottlingAutoIncreasesCounter.h" +#include "InspectorDialogAgent.h" #include "LayerTreeContext.h" #include "MediaKeySystemPermissionRequestManagerProxy.h" #include "MediaPlaybackState.h" @@ -141,8 +142,11 @@ #include "EndowmentStateTracker.h" #endif +OBJC_CLASS NSPasteboard; + #if ENABLE(DRAG_SUPPORT) #include +#include #endif #if ENABLE(TOUCH_EVENTS) @@ -164,6 +168,14 @@ #include "ArgumentCodersGtk.h" #endif +#if PLATFORM(WPE) +#include "ArgumentCodersWPE.h" +#endif + +#if PLATFORM(GTK) || PLATFORM(WPE) +#include +#endif + #if ENABLE(WIRELESS_PLAYBACK_TARGET) && !PLATFORM(IOS_FAMILY) #include #include @@ -243,6 +255,7 @@ class AuthenticationChallenge; class CertificateInfo; class Cursor; class DragData; +typedef HashMap> DragDataMap; class FloatRect; class FontAttributeChanges; class FontChanges; @@ -250,7 +263,6 @@ class GraphicsLayer; class IntSize; class ProtectionSpace; class RunLoopObserver; -class SelectionData; class SharedBuffer; class SpeechRecognitionRequest; class TextIndicator; @@ -529,6 +541,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(); @@ -611,6 +625,11 @@ public: void setPageLoadStateObserver(std::unique_ptr&&); + void setAuthCredentialsForAutomation(std::optional&&); + void setPermissionsForAutomation(const HashMap>&); + void setActiveForAutomation(std::optional active); + void logToStderr(const String& str); + void initializeWebPage(); void setDrawingArea(std::unique_ptr&&); @@ -638,6 +657,7 @@ public: void closePage(); void addPlatformLoadParameters(WebProcessProxy&, LoadParameters&); + RefPtr loadRequestForInspector(WebCore::ResourceRequest&&, WebFrameProxy*); RefPtr loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemesButNotAppLinks, 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); @@ -1152,6 +1172,7 @@ public: #endif void pageScaleFactorDidChange(double); + void viewScaleFactorDidChange(double); void pluginScaleFactorDidChange(double); void pluginZoomFactorDidChange(double); @@ -1226,14 +1247,20 @@ public: void didStartDrag(); void dragCancelled(); void setDragCaretRect(const WebCore::IntRect&); + void setInterceptDrags(bool shouldIntercept); + bool cancelDragIfNeeded(); #if PLATFORM(COCOA) void startDrag(const WebCore::DragItem&, const ShareableBitmap::Handle& dragImageHandle); void setPromisedDataForImage(const String& pasteboardName, const SharedMemory::IPCHandle& imageHandle, const String& filename, const String& extension, const String& title, const String& url, const String& visibleURL, const SharedMemory::IPCHandle& archiveHandle, const String& originIdentifier); + void releaseInspectorDragPasteboard(); #endif -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) void startDrag(WebCore::SelectionData&&, OptionSet, const ShareableBitmap::Handle& dragImage); #endif +#if PLATFORM(WIN) + void startDrag(WebCore::DragDataMap& dragDataMap); +#endif #endif void processDidBecomeUnresponsive(); @@ -1475,6 +1502,8 @@ public: #if PLATFORM(COCOA) || PLATFORM(GTK) RefPtr takeViewSnapshot(std::optional&&); +#elif PLATFORM(WPE) + RefPtr takeViewSnapshot(std::optional&&) { return nullptr; } #endif #if ENABLE(WEB_CRYPTO) @@ -2568,6 +2597,7 @@ private: String m_overrideContentSecurityPolicy; RefPtr m_inspector; + InspectorDialogAgent* m_inspectorDialogAgent { nullptr }; #if PLATFORM(COCOA) WeakObjCPtr m_cocoaView; @@ -2821,6 +2851,20 @@ private: unsigned m_currentDragNumberOfFilesToBeAccepted { 0 }; WebCore::IntRect m_currentDragCaretRect; WebCore::IntRect m_currentDragCaretEditableElementRect; + bool m_interceptDrags { false }; + OptionSet m_dragSourceOperationMask; + WebCore::IntPoint m_lastMousePositionForDrag; + int m_dragEventsQueued = 0; +#if PLATFORM(COCOA) + std::optional m_dragSelectionData; + String m_overrideDragPasteboardName; +#endif +#if PLATFORM(GTK) || PLATFORM(WPE) + std::optional m_dragSelectionData; +#endif +#if PLATFORM(WIN) + std::optional m_dragSelectionData; +#endif #endif PageLoadState m_pageLoadState; @@ -3034,6 +3078,9 @@ private: RefPtr messageBody; }; Vector m_pendingInjectedBundleMessages; + std::optional m_credentialsForAutomation; + HashMap> m_permissionsForAutomation; + std::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 db5b56ef235209ea1739469a9116140e2976d96e..3a0c71d0d38c37daefa3a18b5c12f8ba08f946d8 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) @@ -181,6 +182,7 @@ messages -> WebPageProxy { #endif PageScaleFactorDidChange(double scaleFactor) + ViewScaleFactorDidChange(double scaleFactor) PluginScaleFactorDidChange(double zoomFactor) PluginZoomFactorDidChange(double zoomFactor) @@ -311,10 +313,12 @@ messages -> WebPageProxy { StartDrag(struct WebCore::DragItem dragItem, WebKit::ShareableBitmap::Handle dragImage) SetPromisedDataForImage(String pasteboardName, WebKit::SharedMemory::IPCHandle imageHandle, String filename, String extension, String title, String url, String visibleURL, WebKit::SharedMemory::IPCHandle archiveHandle, String originIdentifier) #endif -#if PLATFORM(GTK) && ENABLE(DRAG_SUPPORT) +#if (PLATFORM(GTK) || PLATFORM(WPE)) && ENABLE(DRAG_SUPPORT) StartDrag(WebCore::SelectionData selectionData, OptionSet dragOperationMask, WebKit::ShareableBitmap::Handle dragImage) #endif - +#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT) + StartDrag(HashMap> dragDataMap) +#endif #if ENABLE(DRAG_SUPPORT) DidPerformDragOperation(bool handled) #endif diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp index 2eab6bcb89b8b79a7dcf3cdcd49c06d5acd212b3..5db9888b36e24819dc85d15dc787f22b077dacee 100644 --- a/Source/WebKit/UIProcess/WebProcessPool.cpp +++ b/Source/WebKit/UIProcess/WebProcessPool.cpp @@ -509,6 +509,14 @@ void WebProcessPool::establishWorkerContextConnectionToNetworkProcess(NetworkPro // Arbitrarily choose the first process pool to host the service worker process. auto* processPool = processPools()[0]; + // Playwright begin + for (auto& process : websiteDataStore->processes()) { + if (process.processPoolIfExists()) { + processPool = process.processPoolIfExists(); + break; + } + } + // Playwright end ASSERT(processPool); WebProcessProxy* serviceWorkerProcessProxy { nullptr }; @@ -751,7 +759,10 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa #endif parameters.cacheModel = LegacyGlobalSettings::singleton().cacheModel(); - parameters.overrideLanguages = configuration().overrideLanguages(); + if (websiteDataStore && websiteDataStore->languagesForAutomation().size()) + parameters.overrideLanguages = websiteDataStore->languagesForAutomation(); + else + parameters.overrideLanguages = configuration().overrideLanguages(); parameters.urlSchemesRegisteredAsEmptyDocument = copyToVector(m_schemesToRegisterAsEmptyDocument); parameters.urlSchemesRegisteredAsSecure = copyToVector(LegacyGlobalSettings::singleton().schemesToRegisterAsSecure()); diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp index 30fa4237cbde8f7c006386f9b573d8ead918d958..01eaa27437987693d6a99091a6814fde189ef90f 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.cpp +++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp @@ -126,6 +126,11 @@ HashMap& WebProcessProxy::allProcesses() return map; } +Vector WebProcessProxy::allProcessesForInspector() +{ + return copyToVector(allProcesses().values()); +} + WebProcessProxy* WebProcessProxy::processForIdentifier(ProcessIdentifier identifier) { return allProcesses().get(identifier); diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h index 790d76594ec5fc5f43aefb3e224a492d4658e536..33f5868d33e897318f4828edf4c3a2fafa1763b1 100644 --- a/Source/WebKit/UIProcess/WebProcessProxy.h +++ b/Source/WebKit/UIProcess/WebProcessProxy.h @@ -141,6 +141,7 @@ public: ~WebProcessProxy(); static void forWebPagesWithOrigin(PAL::SessionID, const WebCore::SecurityOriginData&, const Function&); + static Vector allProcessesForInspector(); WebConnection* webConnection() const { return m_webConnection.get(); } diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp index dc443ad5ac9163a662477c2af08e74383201619d..af7722bb9ec218845ce9b15d7c6551dbf4f9e8cb 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp @@ -2127,6 +2127,17 @@ void WebsiteDataStore::renameOriginInWebsiteData(URL&& oldName, URL&& newName, O networkProcess().renameOriginInWebsiteData(m_sessionID, oldName, newName, dataTypes, WTFMove(completionHandler)); } +void WebsiteDataStore::setLanguagesForAutomation(Vector&& languages) +{ + m_languagesForAutomation = WTFMove(languages); +} + +void WebsiteDataStore::setDownloadForAutomation(std::optional allow, const String& downloadPath) +{ + m_allowDownloadForAutomation = allow; + m_downloadPathForAutomation = downloadPath; +} + #if ENABLE(APP_BOUND_DOMAINS) void WebsiteDataStore::hasAppBoundSession(CompletionHandler&& completionHandler) const { diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h index 30b217a27eb2137577efa291932adf55e2a64d38..a9104d10486accc89b6648c31a4ce5810a55101e 100644 --- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h +++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h @@ -84,6 +84,7 @@ class DeviceIdHashSaltStorage; class NetworkProcessProxy; class SOAuthorizationCoordinator; class WebCertificateInfo; +class DownloadProxy; class WebPageProxy; class WebProcessPool; class WebProcessProxy; @@ -92,6 +93,7 @@ enum class CacheModel : uint8_t; enum class WebsiteDataFetchOption : uint8_t; enum class WebsiteDataType : uint32_t; +struct FrameInfoData; struct NetworkProcessConnectionInfo; struct WebsiteDataRecord; struct WebsiteDataStoreParameters; @@ -106,6 +108,16 @@ enum class StorageAccessPromptStatus; struct PluginModuleInfo; #endif +class WebsiteDataStore; + +class DownloadInstrumentation { +public: + virtual void downloadCreated(const String& uuid, const WebCore::ResourceRequest&, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr download) = 0; + virtual void downloadFilenameSuggested(const String& uuid, const String& suggestedFilename) = 0; + virtual void downloadFinished(const String& uuid, const String& error) = 0; + virtual ~DownloadInstrumentation() = default; +}; + class WebsiteDataStore : public API::ObjectImpl, public Identified, public CanMakeWeakPtr { public: static Ref defaultDataStore(); @@ -283,11 +295,13 @@ public: const WebCore::CurlProxySettings& networkProxySettings() const { return m_proxySettings; } #endif -#if USE(SOUP) +#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN) void setPersistentCredentialStorageEnabled(bool); bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled && isPersistent(); } void setIgnoreTLSErrors(bool); bool ignoreTLSErrors() const { return m_ignoreTLSErrors; } +#endif +#if USE(SOUP) void setNetworkProxySettings(WebCore::SoupNetworkProxySettings&&); const WebCore::SoupNetworkProxySettings& networkProxySettings() const { return m_networkProxySettings; } #endif @@ -343,6 +357,14 @@ public: static WTF::String defaultJavaScriptConfigurationDirectory(); static bool http3Enabled(); + void setLanguagesForAutomation(Vector&&); + Vector& languagesForAutomation() { return m_languagesForAutomation; }; + void setDownloadForAutomation(std::optional allow, const String& downloadPath); + std::optional allowDownloadForAutomation() { return m_allowDownloadForAutomation; }; + String downloadPathForAutomation() { return m_downloadPathForAutomation; }; + void setDownloadInstrumentation(DownloadInstrumentation* instrumentation) { m_downloadInstrumentation = instrumentation; }; + DownloadInstrumentation* downloadInstrumentation() { return m_downloadInstrumentation; }; + void resetQuota(CompletionHandler&&); #if ENABLE(APP_BOUND_DOMAINS) @@ -429,9 +451,11 @@ private: WebCore::CurlProxySettings m_proxySettings; #endif -#if USE(SOUP) +#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN) bool m_persistentCredentialStorageEnabled { true }; bool m_ignoreTLSErrors { true }; +#endif +#if USE(SOUP) WebCore::SoupNetworkProxySettings m_networkProxySettings; #endif @@ -456,6 +480,11 @@ private: RefPtr m_cookieStore; RefPtr m_networkProcess; + Vector m_languagesForAutomation; + std::optional m_allowDownloadForAutomation; + String m_downloadPathForAutomation; + DownloadInstrumentation* m_downloadInstrumentation { nullptr }; + #if HAVE(APP_SSO) UniqueRef m_soAuthorizationCoordinator; #endif diff --git a/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp b/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp index 0b2fc0019ffa2c05383dc4b4e480b4d380aa9fd5..79773452d246f3bcdf42122a3bf8f67685e45fdc 100644 --- a/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp +++ b/Source/WebKit/UIProcess/cairo/BackingStoreCairo.cpp @@ -27,9 +27,11 @@ #include "config.h" #include "BackingStore.h" +#include "DrawingAreaProxyCoordinatedGraphics.h" #include "ShareableBitmap.h" #include "UpdateInfo.h" #include "WebPageProxy.h" +#include "WebPageInspectorController.h" #include #include #include @@ -61,6 +63,13 @@ std::unique_ptr BackingStore::createBackend() return makeUnique(m_size, m_deviceScaleFactor); } +cairo_surface_t* BackingStore::surface() const { + if (!m_backend) + return nullptr; + + return m_backend->surface(); +} + void BackingStore::paint(cairo_t* context, const IntRect& rect) { ASSERT(m_backend); diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp index 692a45a48fa027f9221338d74f5351bef4baf00f..db8c761c71cc7009be66255c2668de4eff36dee0 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 b5e48e6c61a8a3f4b40b84112c4010101c4d5f41..46747b1d78bfe0270178609867c0d710807fa668 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..31a4e32d4cf8442049f0bea04c817a40b801c1f7 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp @@ -0,0 +1,147 @@ +/* + * 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 { + +static WebCore::SoupNetworkProxySettings parseRawProxySettings(const String& proxyServer, const char* const* ignoreHosts) +{ + WebCore::SoupNetworkProxySettings settings; + if (proxyServer.isEmpty()) + return settings; + + settings.mode = WebCore::SoupNetworkProxySettings::Mode::Custom; + settings.defaultProxyURL = proxyServer.utf8(); + settings.ignoreHosts.reset(g_strdupv(const_cast(ignoreHosts))); + return settings; +} + +static WebCore::SoupNetworkProxySettings parseProxySettings(const String& proxyServer, const String& proxyBypassList) +{ + Vector ignoreHosts; + if (!proxyBypassList.isEmpty()) { + Vector tokens = proxyBypassList.split(','); + Vector protectTokens; + for (String token : tokens) { + CString cstr = token.utf8(); + ignoreHosts.append(cstr.data()); + protectTokens.append(WTFMove(cstr)); + } + } + ignoreHosts.append(nullptr); + return parseRawProxySettings(proxyServer, ignoreHosts.data()); +} + +InspectorPlaywrightAgentClientGlib::InspectorPlaywrightAgentClientGlib(const WTF::String& proxyURI, const char* const* ignoreHosts) + : m_proxySettings(parseRawProxySettings(proxyURI, ignoreHosts)) +{ +} + +RefPtr InspectorPlaywrightAgentClientGlib::createPage(WTF::String& error, const BrowserContext& browserContext) +{ + auto sessionID = browserContext.dataStore->sessionID(); + WebKitWebContext* context = m_idToContext.get(sessionID); + if (!context && !browserContext.dataStore->isPersistent()) { + ASSERT_NOT_REACHED(); + error = "Context with provided id not found"; + 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(); + webkitBrowserInspectorQuitApplication(); + if (webkitWebContextExistingCount() > 1) + fprintf(stderr, "LEAK: %d contexts are still alive when closing browser\n", webkitWebContextExistingCount()); +} + +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(); +} + +std::unique_ptr InspectorPlaywrightAgentClientGlib::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) +{ + 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 nullptr; + } + auto browserContext = std::make_unique(); + browserContext->processPool = &webkitWebContextGetProcessPool(context.get()); + browserContext->dataStore = &webkitWebsiteDataManagerGetDataStore(data_manager.get()); + PAL::SessionID sessionID = sessionIDFromContext(context.get()); + m_idToContext.set(sessionID, WTFMove(context)); + + if (!proxyServer.isEmpty()) { + WebCore::SoupNetworkProxySettings contextProxySettings = parseProxySettings(proxyServer, proxyBypassList); + browserContext->dataStore->setNetworkProxySettings(WTFMove(contextProxySettings)); + } else { + browserContext->dataStore->setNetworkProxySettings(WebCore::SoupNetworkProxySettings(m_proxySettings)); + } + return browserContext; +} + +void InspectorPlaywrightAgentClientGlib::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + m_idToContext.remove(sessionID); +} + +} // 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..8006336003a4512b4c63bc8272d4b3507bb63159 --- /dev/null +++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h @@ -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. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include "WebKitWebContext.h" +#include +#include +#include +#include + +namespace WebKit { + +class InspectorPlaywrightAgentClientGlib : public InspectorPlaywrightAgentClient { + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorPlaywrightAgentClientGlib(const WTF::String& proxyURI, const char* const* ignoreHosts); + ~InspectorPlaywrightAgentClientGlib() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + WebKitWebContext* findContext(WTF::String& error, PAL::SessionID); + + HashMap> m_idToContext; + WebCore::SoupNetworkProxySettings m_proxySettings; +}; + +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/glib/WebPageProxyGLib.cpp b/Source/WebKit/UIProcess/glib/WebPageProxyGLib.cpp index 521df7840ab6d376c25130e87ea500942398c8b6..c733d9d5cd304889640e5af4423860717be94725 100644 --- a/Source/WebKit/UIProcess/glib/WebPageProxyGLib.cpp +++ b/Source/WebKit/UIProcess/glib/WebPageProxyGLib.cpp @@ -57,4 +57,34 @@ void WebPageProxy::loadRecentSearches(const String&, CompletionHandler typedef struct _cairo cairo_t; +typedef struct _cairo_surface cairo_surface_t; #if USE(GTK4) typedef struct _GdkSnapshot GdkSnapshot; @@ -56,6 +57,8 @@ public: #else virtual bool paint(cairo_t*, const WebCore::IntRect&) = 0; #endif + virtual cairo_surface_t* surface() { return nullptr; } + virtual void realize() { }; virtual void unrealize() { }; virtual bool makeContextCurrent() { return false; } diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.h index 054e80bd900cf16d69801e8102ca989ff0563e1d..8245d7ed58008dbb6152e55e619e4331d30ae674 100644 --- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.h +++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreX11.h @@ -52,6 +52,7 @@ private: #else bool paint(cairo_t*, const WebCore::IntRect&) override; #endif + cairo_surface_t* surface() override { return m_surface.get(); } RefPtr m_surface; WebCore::XUniqueDamage m_damage; 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/WebDateTimePickerGtk.cpp b/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp index 2ac15c9d7f1f19947b449794862555e913e211b7..111cd5464a19b81e73ba1bd02a2d76918cb40612 100644 --- a/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp +++ b/Source/WebKit/UIProcess/gtk/WebDateTimePickerGtk.cpp @@ -34,6 +34,8 @@ #include #include +using namespace WebCore; + namespace WebKit { Ref WebDateTimePickerGtk::create(WebPageProxy& page) 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..d0f9827544994e450e24e3f7a427c35eeff94d67 --- /dev/null +++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp @@ -0,0 +1,105 @@ +/* + * 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, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& macCommands, WallTime timestamp) +{ + Vector commands; + const guint keyVal = WebCore::PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(windowsVirtualKeyCode); + if (keyVal) { + 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); + } + 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 fb7112c81fe3a514f7d872b3185748d8c7617ec3..f924351e98068eccdcd48f462f86cd66a530d79b 100644 --- a/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm +++ b/Source/WebKit/UIProcess/ios/PageClientImplIOS.mm @@ -442,6 +442,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..a16815a6759da61a6a61e3d79058228af887fd7c --- /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; + std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + _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..8e588f7b8c8c29fb53dd37ea41d46f3d753077fd --- /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]; +} + +std::unique_ptr InspectorPlaywrightAgentClientMac::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) +{ + _WKBrowserContext* wkBrowserContext = [[delegate_ createBrowserContext:proxyServer WithBypassList:proxyBypassList] autorelease]; + auto browserContext = std::make_unique(); + browserContext->processPool = &static_cast([[wkBrowserContext processPool] _apiObject]); + browserContext->dataStore = &static_cast([[wkBrowserContext dataStore] _apiObject]); + return browserContext; +} + +void InspectorPlaywrightAgentClientMac::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID) +{ + [delegate_ deleteBrowserContext:sessionID.toUInt64()]; +} + +} // 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 6c5c4e39c61483dae90e692cc78669dab749e5da..3a559999da9fa8c7765f3bff63eab63fee1df8b8 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(); @@ -165,6 +167,9 @@ private: void updateAcceleratedCompositingMode(const LayerTreeContext&) override; void didFirstLayerFlush(const LayerTreeContext&) override; +// Paywright begin + RetainPtr takeSnapshotForAutomation() override; +// Paywright end RefPtr takeViewSnapshot(std::optional&&) override; void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override; #if ENABLE(MAC_GESTURE_EVENTS) @@ -219,6 +224,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 8b74b4545d897a999294f815c7c1f67b38fd3c2c..b58607377d21a7593c7b890321f81ab53e167688 100644 --- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm +++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm @@ -81,6 +81,7 @@ #import #import #import +#import #import #import #import @@ -107,6 +108,13 @@ namespace WebKit { using namespace WebCore; +static bool _headless = false; + +// static +void PageClientImpl::setHeadless(bool headless) { + _headless = headless; +} + PageClientImpl::PageClientImpl(NSView *view, WKWebView *webView) : PageClientImplCocoa(webView) , m_view(view) @@ -160,6 +168,9 @@ NSWindow *PageClientImpl::activeWindow() const bool PageClientImpl::isViewWindowActive() { + if (_headless) + return true; + ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer)); NSWindow *activeViewWindow = activeWindow(); return activeViewWindow.isKeyWindow || (activeViewWindow && [NSApp keyWindow] == activeViewWindow); @@ -167,6 +178,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) @@ -190,6 +204,9 @@ void PageClientImpl::makeFirstResponder() bool PageClientImpl::isViewVisible() { + if (_headless) + return true; + NSView *activeView = this->activeView(); NSWindow *activeViewWindow = activeWindow(); @@ -273,7 +290,8 @@ void PageClientImpl::didRelaunchProcess() void PageClientImpl::preferencesDidChange() { - m_impl->preferencesDidChange(); + if (m_impl) + m_impl->preferencesDidChange(); } void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip) @@ -475,6 +493,8 @@ IntRect PageClientImpl::rootViewToAccessibilityScreen(const IntRect& rect) void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool eventWasHandled) { + if (!event.nativeEvent()) + return; m_impl->doneWithKeyEvent(event.nativeEvent(), eventWasHandled); } @@ -494,6 +514,8 @@ void PageClientImpl::computeHasImageAnalysisResults(const URL& imageURL, Shareab RefPtr PageClientImpl::createPopupMenuProxy(WebPageProxy& page) { + if (_headless) + return nullptr; return WebPopupMenuProxyMac::create(m_view, page); } @@ -625,6 +647,12 @@ CALayer *PageClientImpl::acceleratedCompositingRootLayer() const return m_impl->acceleratedCompositingRootLayer(); } +// Paywright begin +RetainPtr PageClientImpl::takeSnapshotForAutomation() { + return m_impl->takeSnapshotForAutomation(); +} +// Paywright begin + RefPtr PageClientImpl::takeViewSnapshot(std::optional&&) { return m_impl->takeViewSnapshot(); @@ -803,6 +831,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); @@ -974,6 +1009,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/WebContextMenuProxyMac.h b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h index 34e2d00746ebb079719becbe781f5bc6cea1d480..bf496a6327b962f8f40c207c9e2023d2152aded1 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h @@ -70,6 +70,7 @@ private: void show() override; void showContextMenuWithItems(Vector>&&) override; void useContextMenuItems(Vector>&&) override; + void hide() override; void getContextMenuItem(const WebContextMenuItemData&, CompletionHandler&&); void getContextMenuFromItems(const Vector&, CompletionHandler&&); diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm index 3e0090b5875b34887c3aeed45eb3333e3452a413..4293eb5e02a93d7b2feedc47810164b4e6ac5e44 100644 --- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm +++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm @@ -362,6 +362,12 @@ void WebContextMenuProxyMac::getShareMenuItem(CompletionHandler&& 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..e6e2c8c2769e4657c01f1452e554fd6f6d457279 --- /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" + +namespace WebKit { + +using namespace WebCore; + +void WebPageInspectorInputAgent::platformDispatchMouseEvent(const String& type, int x, int y, std::optional&& optionalModifiers, const String& button, std::optional&& 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, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& commands, WallTime timestamp) +{ + Vector macCommands; + for (const String& command : commands) { + m_page.registerKeypressCommandName(command); + macCommands.append(WebCore::KeypressCommand(command.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..dd7fe0604188bb025f361f1c44685e38bbf935ca --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorPlaywrightAgentClientWin.h" + +#if ENABLE(REMOTE_INSPECTOR) + +#include "APIPageConfiguration.h" +#include "APIProcessPoolConfiguration.h" +#include "InspectorPlaywrightAgent.h" +#include "WebPageProxy.h" +#include "WebsiteDataStore.h" +#include "WebPreferences.h" +#include "WebProcessPool.h" +#include "WebView.h" +#include "WKAPICast.h" +#include +#include +#include +#include +#include + +namespace WebKit { + +InspectorPlaywrightAgentClientWin::InspectorPlaywrightAgentClientWin(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit) + : m_configureDataStore(configureDataStore) + , m_createPage(createPage) + , m_quit(quit) +{ +} + +RefPtr InspectorPlaywrightAgentClientWin::createPage(WTF::String& error, const BrowserContext& context) +{ + auto conf = API::PageConfiguration::create(); + conf->setProcessPool(context.processPool.get()); + conf->setWebsiteDataStore(context.dataStore.get()); + return toImpl(m_createPage(toAPI(&conf.get()))); +} + +void InspectorPlaywrightAgentClientWin::closeBrowser() +{ + m_quit(); +} + +std::unique_ptr InspectorPlaywrightAgentClientWin::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) +{ + auto config = API::ProcessPoolConfiguration::create(); + auto browserContext = std::make_unique(); + browserContext->processPool = WebKit::WebProcessPool::create(config); + browserContext->dataStore = WebKit::WebsiteDataStore::createNonPersistent(); + m_configureDataStore(toAPI(browserContext->dataStore.get())); + if (!proxyServer.isEmpty()) { + URL proxyURL = URL(URL(), proxyServer); + WebCore::CurlProxySettings settings(WTFMove(proxyURL), String(proxyBypassList)); + browserContext->dataStore->setNetworkProxySettings(WTFMove(settings)); + } + 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..df18883b2b7d22d73540cb084d3dd5291231097d --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#if ENABLE(REMOTE_INSPECTOR) + +#include "InspectorPlaywrightAgentClient.h" +#include +#include +#include + +typedef void (*ConfigureDataStoreCallback)(WKWebsiteDataStoreRef dataStore); +typedef WKPageRef (*CreatePageCallback)(WKPageConfigurationRef configuration); +typedef void (*QuitCallback)(); + +namespace WebKit { + +class InspectorPlaywrightAgentClientWin : public InspectorPlaywrightAgentClient { + WTF_MAKE_FAST_ALLOCATED; +public: + InspectorPlaywrightAgentClientWin(ConfigureDataStoreCallback, CreatePageCallback, QuitCallback); + ~InspectorPlaywrightAgentClientWin() override = default; + + RefPtr createPage(WTF::String& error, const BrowserContext&) override; + void closeBrowser() override; + std::unique_ptr createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override; + void deleteBrowserContext(WTF::String& error, PAL::SessionID) override; + +private: + ConfigureDataStoreCallback m_configureDataStore; + CreatePageCallback m_createPage; + QuitCallback m_quit; +}; + +} // namespace API + +#endif // ENABLE(REMOTE_INSPECTOR) diff --git a/Source/WebKit/UIProcess/win/InspectorTargetProxyWin.cpp b/Source/WebKit/UIProcess/win/InspectorTargetProxyWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..135a60361fa8fbf907382625e7c8dd4ea64ceb94 --- /dev/null +++ b/Source/WebKit/UIProcess/win/InspectorTargetProxyWin.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2020 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorTargetProxy.h" +#include "WebPageProxy.h" + +namespace WebKit { + +void InspectorTargetProxy::platformActivate(String& error) const +{ +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp index 3dcd0ec35c92e37239208a8f5d4f461fbeaac3ce..84ba07c57f2abac1bd0ca5d0af2e7366ad036892 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp +++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp @@ -112,5 +112,11 @@ WebContextMenuProxyWin::~WebContextMenuProxyWin() ::DestroyMenu(m_menu); } +void WebContextMenuProxyWin::hide() +{ + if (m_menu) + ::EndMenu(); +} + } // namespace WebKit #endif // ENABLE(CONTEXT_MENUS) diff --git a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h index 0c80d970c3f9a987faf620081c909f6c7021970d..1467e5481f7417913c0d12a1cb492d02b2a7d1b7 100644 --- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h +++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h @@ -47,6 +47,7 @@ public: private: WebContextMenuProxyWin(WebPageProxy&, ContextMenuContextData&&, const UserData&); void showContextMenuWithItems(Vector>&&) override; + void hide() override; HMENU m_menu; }; diff --git a/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62b841fe1d0de2296e1c61e328cff564f5aa1c0f --- /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_NOCOPYBITS | SWP_NOSENDCHANGING | 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..5cf8a010e9809e6a95741cdb7c2cbeb445ab638b --- /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, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet modifiers, Vector& macCommands, WallTime timestamp) +{ + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/UIProcess/wpe/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..c3d7cacea987ba2b094d5022c670705ef6ced129 --- /dev/null +++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2019 Microsoft Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebPageInspectorInputAgent.h" + +#include "NativeWebKeyboardEvent.h" +#include "WebPageProxy.h" +#include +#include + +namespace WebKit { + +void WebPageInspectorInputAgent::platformDispatchKeyEvent(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, Vector& macCommands, WallTime timestamp) +{ + NativeWebKeyboardEvent event( + type, + text, + unmodifiedText, + key, + code, + keyIdentifier, + windowsVirtualKeyCode, + nativeVirtualKeyCode, + isAutoRepeat, + isKeypad, + isSystemKey, + modifiers, + timestamp); + m_page.handleKeyboardEvent(event); +} + +} // namespace WebKit diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj index 904f8b27c8448ca284b26339d0e4e0dd37e9a39e..4584471f3080fbbc96b815eaddbfa0e8efa1ed49 100644 --- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj +++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj @@ -1960,6 +1960,18 @@ DF0C5F28252ECB8E00D921DB /* WKDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F24252ECB8D00D921DB /* WKDownload.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2A252ECB8E00D921DB /* WKDownloadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; DF0C5F2B252ED44000D921DB /* WKDownloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */; }; + D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */; }; + D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */; }; + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */; }; + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */; }; + D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */; }; + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94492372290B002C4D9E /* _WKBrowserInspector.h */; settings = {ATTRIBUTES = (Private, ); }; }; + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */; }; + D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D76D6887238DBD80008D314B /* InspectorDialogAgent.h */; }; + D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */; }; + D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */; }; + D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */; }; + D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */; }; DF462E0F23F22F5500EFF35F /* WKHTTPCookieStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF462E1223F338BE00EFF35F /* WKContentWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; DF84CEE4249AA24D009096F6 /* WKPDFHUDView.mm in Sources */ = {isa = PBXBuildFile; fileRef = DF84CEE2249AA21F009096F6 /* WKPDFHUDView.mm */; }; @@ -2016,6 +2028,9 @@ E5BEF6822130C48000F31111 /* WebDataListSuggestionsDropdownIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = E5BEF6802130C47F00F31111 /* WebDataListSuggestionsDropdownIOS.h */; }; E5CB07DC20E1678F0022C183 /* WKFormColorControl.h in Headers */ = {isa = PBXBuildFile; fileRef = E5CB07DA20E1678F0022C183 /* WKFormColorControl.h */; }; ED82A7F2128C6FAF004477B3 /* WKBundlePageOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A22F0FF1289FCD90085E74F /* WKBundlePageOverlay.h */; settings = {ATTRIBUTES = (Private, ); }; }; + F303B849249A8D640031DE5C /* ScreencastEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = F303B848249A8D3A0031DE5C /* ScreencastEncoder.h */; }; + F33C7AC7249AD79C0018BE41 /* libwebrtc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */; }; + F3867F0A24607D4E008F0F31 /* InspectorScreencastAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */; }; F4094CBD2553053D003D73E3 /* DisplayListReaderHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = F4094CBB255304AF003D73E3 /* DisplayListReaderHandle.h */; }; F4094CBE25530540003D73E3 /* DisplayListWriterHandle.h in Headers */ = {isa = PBXBuildFile; fileRef = F4094CB92553047E003D73E3 /* DisplayListWriterHandle.h */; }; F409BA181E6E64BC009DA28E /* WKDragDestinationAction.h in Headers */ = {isa = PBXBuildFile; fileRef = F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -5862,6 +5877,19 @@ DF0C5F24252ECB8D00D921DB /* WKDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownload.h; sourceTree = ""; }; DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadInternal.h; sourceTree = ""; }; DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadDelegate.h; sourceTree = ""; }; + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBrowserInspector.h; sourceTree = ""; }; + D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorPlaywrightAgentClientMac.h; sourceTree = ""; }; + D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorPlaywrightAgentClient.h; sourceTree = ""; }; + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorPipe.h; sourceTree = ""; }; + D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorEmulationAgent.h; sourceTree = ""; }; + D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorInputAgent.h; sourceTree = ""; }; + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKBrowserInspector.h; sourceTree = ""; }; + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserInspectorPipe.h; sourceTree = ""; }; + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDialogAgent.h; sourceTree = ""; }; + D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorEmulationAgentMac.mm; sourceTree = ""; }; + D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorTargetProxyMac.mm; sourceTree = ""; }; + D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorInputAgentMac.mm; sourceTree = ""; }; + D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorPlaywrightAgentClientMac.mm; sourceTree = ""; }; DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKHTTPCookieStorePrivate.h; sourceTree = ""; }; DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKContentWorldPrivate.h; sourceTree = ""; }; DF58C6311371AC5800F9A37C /* NativeWebWheelEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebWheelEvent.h; sourceTree = ""; }; @@ -5980,6 +6008,14 @@ ECA680D31E6904B500731D20 /* ExtraPrivateSymbolsForTAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExtraPrivateSymbolsForTAPI.h; sourceTree = ""; }; ECBFC1DB1E6A4D66000300C7 /* ExtraPublicSymbolsForTAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExtraPublicSymbolsForTAPI.h; sourceTree = ""; }; F036978715F4BF0500C3A80E /* WebColorPicker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebColorPicker.cpp; sourceTree = ""; }; + F303B847249A8D3A0031DE5C /* ScreencastEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScreencastEncoder.cpp; sourceTree = ""; }; + F303B848249A8D3A0031DE5C /* ScreencastEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreencastEncoder.h; sourceTree = ""; }; + F31E2DA424C76E4B004B2775 /* WebMFileWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebMFileWriter.cpp; sourceTree = ""; }; + F31E2DA524C76E4C004B2775 /* WebMFileWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMFileWriter.h; sourceTree = ""; }; + F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; path = libwebrtc.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + F3867F0324607D2B008F0F31 /* InspectorScreencastAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorScreencastAgent.cpp; sourceTree = ""; }; + F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorScreencastAgent.h; sourceTree = ""; }; + F3970344249BD4CE003E1A22 /* ScreencastEncoderMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreencastEncoderMac.mm; sourceTree = ""; }; F4094CB92553047E003D73E3 /* DisplayListWriterHandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayListWriterHandle.h; sourceTree = ""; }; F4094CBA2553047E003D73E3 /* DisplayListWriterHandle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayListWriterHandle.cpp; sourceTree = ""; }; F4094CBB255304AF003D73E3 /* DisplayListReaderHandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayListReaderHandle.h; sourceTree = ""; }; @@ -6094,6 +6130,7 @@ 3766F9EF189A1244003CF19B /* QuartzCore.framework in Frameworks */, 37694525184FC6B600CDE21F /* Security.framework in Frameworks */, 37BEC4DD1948FC6A008B4286 /* WebCore.framework in Frameworks */, + F33C7AC7249AD79C0018BE41 /* libwebrtc.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -7969,6 +8006,7 @@ 37C4C08318149C2A003688B9 /* Cocoa */ = { isa = PBXGroup; children = ( + D71A94492372290B002C4D9E /* _WKBrowserInspector.h */, 1A43E826188F38E2009E4D30 /* Deprecated */, 37A5E01218BBF937000A081E /* _WKActivatedElementInfo.h */, 37A5E01118BBF937000A081E /* _WKActivatedElementInfo.mm */, @@ -9034,6 +9072,7 @@ isa = PBXGroup; children = ( 57A9FF15252C6AEF006A2040 /* libWTF.a */, + F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */, 5750F32A2032D4E500389347 /* LocalAuthentication.framework */, 570DAAB0230273D200E8FC04 /* NearField.framework */, ); @@ -9469,6 +9508,12 @@ children = ( 9197940423DBC4BB00257892 /* InspectorBrowserAgent.cpp */, 9197940323DBC4BB00257892 /* InspectorBrowserAgent.h */, + F3867F0324607D2B008F0F31 /* InspectorScreencastAgent.cpp */, + F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */, + F303B847249A8D3A0031DE5C /* ScreencastEncoder.cpp */, + F303B848249A8D3A0031DE5C /* ScreencastEncoder.h */, + F31E2DA424C76E4B004B2775 /* WebMFileWriter.cpp */, + F31E2DA524C76E4C004B2775 /* WebMFileWriter.h */, ); path = Agents; sourceTree = ""; @@ -9477,6 +9522,7 @@ isa = PBXGroup; children = ( A5D3504D1D78F0D2005124A9 /* RemoteWebInspectorUIProxyMac.mm */, + F3970344249BD4CE003E1A22 /* ScreencastEncoderMac.mm */, 1CA8B935127C774E00576C2B /* WebInspectorUIProxyMac.mm */, 99A7ACE326012919006D57FD /* WKInspectorResourceURLSchemeHandler.h */, 99A7ACE42601291A006D57FD /* WKInspectorResourceURLSchemeHandler.mm */, @@ -9968,6 +10014,12 @@ BC032DC310F438260058C15A /* UIProcess */ = { isa = PBXGroup; children = ( + D76D6887238DBD80008D314B /* InspectorDialogAgent.h */, + D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */, + D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */, + D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */, + D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */, + D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */, BC032DC410F4387C0058C15A /* API */, 512F588D12A8836F00629530 /* Authentication */, 9955A6E81C79809000EB6A93 /* Automation */, @@ -10266,6 +10318,7 @@ BC0C376610F807660076D7CB /* C */ = { isa = PBXGroup; children = ( + D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */, 5123CF18133D25E60056F800 /* cg */, 6EE849C41368D9040038D481 /* mac */, BCB63477116BF10600603215 /* WebKit2_C.h */, @@ -10861,6 +10914,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 */, @@ -11710,6 +11768,7 @@ 99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */, 990D28AC1C6420CF00986977 /* _WKAutomationSessionDelegate.h in Headers */, 990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */, + D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */, 5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */, 5C4609E8224317BB009943C2 /* _WKContentRuleListActionInternal.h in Headers */, 1A5704F81BE01FF400874AF1 /* _WKContextMenuElementInfo.h in Headers */, @@ -12008,6 +12067,7 @@ 1A14F8E21D74C834006CBEC6 /* FrameInfoData.h in Headers */, 1AE00D611831792100087DD7 /* FrameLoadState.h in Headers */, 5C121E842410208D00486F9B /* FrameTreeNodeData.h in Headers */, + F303B849249A8D640031DE5C /* ScreencastEncoder.h in Headers */, 2D4AF0892044C3C4006C8817 /* FrontBoardServicesSPI.h in Headers */, CD78E1151DB7D7ED0014A2DE /* FullscreenClient.h in Headers */, CD19D2EA2046406F0017074A /* FullscreenTouchSecheuristic.h in Headers */, @@ -12023,6 +12083,7 @@ 4614F13225DED875007006E7 /* GPUProcessConnectionParameters.h in Headers */, F40BBB41257FF46E0067463A /* GPUProcessWakeupMessageArguments.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 */, @@ -12169,6 +12230,7 @@ 413075AC1DE85F370039EC69 /* NetworkRTCMonitor.h in Headers */, 41DC45961E3D6E2200B11F51 /* NetworkRTCProvider.h in Headers */, 5C20CBA01BB1ECD800895BB1 /* NetworkSession.h in Headers */, + D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */, 532159551DBAE7290054AA3C /* NetworkSessionCocoa.h in Headers */, 417915B92257046F00D6F97E /* NetworkSocketChannel.h in Headers */, 5183247C26168C62003F239E /* NetworkURLSchemeHandler.h in Headers */, @@ -12257,6 +12319,7 @@ BC1A7C581136E19C00FB7167 /* ProcessLauncher.h in Headers */, 463FD4821EB94EC000A2982C /* ProcessTerminationReason.h in Headers */, 86E67A251910B9D100004AB7 /* ProcessThrottler.h in Headers */, + D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */, 83048AE61ACA45DC0082C832 /* ProcessThrottlerClient.h in Headers */, 2D279E1926955768004B3EEB /* PrototypeToolsSPI.h in Headers */, A1E688701F6E2BAB007006A6 /* QuarantineSPI.h in Headers */, @@ -12278,6 +12341,7 @@ CDAC20B423FB58F20021DEE3 /* RemoteCDMInstanceProxy.h in Headers */, CDAC20CA23FC2F750021DEE3 /* RemoteCDMInstanceSession.h in Headers */, CDAC20C923FC2F750021DEE3 /* RemoteCDMInstanceSessionIdentifier.h in Headers */, + D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */, 2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */, 2DDF731518E95060004F5A66 /* RemoteLayerBackingStoreCollection.h in Headers */, 1AB16AEA164B3A8800290D62 /* RemoteLayerTreeContext.h in Headers */, @@ -12593,6 +12657,7 @@ A543E30D215C8A9000279CD9 /* WebPageInspectorTargetController.h in Headers */, A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */, C0CE72A11247E71D00BC0EC4 /* WebPageMessages.h in Headers */, + F3867F0A24607D4E008F0F31 /* InspectorScreencastAgent.h in Headers */, 2D5C9D0619C81D8F00B3C5C1 /* WebPageOverlay.h in Headers */, 46C392292316EC4D008EED9B /* WebPageProxyIdentifier.h in Headers */, BCBD3915125BB1A800D2C29F /* WebPageProxyMessages.h in Headers */, @@ -12722,6 +12787,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 */, @@ -12775,6 +12841,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 */, @@ -12931,6 +12998,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 */, @@ -14163,6 +14231,7 @@ C1A152D724E5A29A00978C8B /* HandleXPCEndpointMessages.mm in Sources */, 2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */, 2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */, + D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */, 9BF5EC642541145600984E77 /* JSIPCBinding.cpp in Sources */, 2D913441212CF9F000128AFD /* JSNPMethod.cpp in Sources */, 2D913442212CF9F000128AFD /* JSNPObject.cpp in Sources */, @@ -14181,6 +14250,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 */, @@ -14205,6 +14275,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 */, @@ -14510,6 +14581,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 c42d2c00f7982ea3fe19401cd076c24a0b649ebf..50da344e6bd20b85e122c3c36aebcab2b7765bc2 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp @@ -231,6 +231,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou } #endif + if (m_emulateOfflineState) { + scheduleInternallyFailedLoad(resourceLoader); + return; + } + if (!tryLoadingUsingURLSchemeHandler(resourceLoader, trackingParameters)) { WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: URL will be scheduled with the NetworkProcess"); @@ -288,7 +293,8 @@ static void addParametersShared(const Frame* frame, NetworkResourceLoadParameter } } -void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime) +// static +bool WebLoaderStrategy::fillParametersForNetworkProcessLoad(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime, NetworkResourceLoadParameters& loadParameters) { ResourceLoadIdentifier identifier = resourceLoader.identifier(); ASSERT(identifier); @@ -301,7 +307,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL auto* frame = resourceLoader.frame(); - NetworkResourceLoadParameters loadParameters; loadParameters.identifier = identifier; loadParameters.webPageProxyID = trackingParameters.webPageProxyID; loadParameters.webPageID = trackingParameters.pageID; @@ -380,14 +385,11 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL if (loadParameters.options.mode != FetchOptions::Mode::Navigate) { ASSERT(loadParameters.sourceOrigin); - if (!loadParameters.sourceOrigin) { - WEBLOADERSTRATEGY_RELEASE_LOG_ERROR("scheduleLoad: no sourceOrigin (priority=%d)", static_cast(resourceLoader.request().priority())); - scheduleInternallyFailedLoad(resourceLoader); - return; - } + if (!loadParameters.sourceOrigin) + return false; } - loadParameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks(); + loadParameters.shouldRestrictHTTPResponseAccess = RuntimeEnabledFeatures::sharedFeatures().restrictedHTTPResponseAccess(); loadParameters.isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate; @@ -403,6 +405,17 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } ASSERT((loadParameters.webPageID && loadParameters.webFrameID) || loadParameters.clientCredentialPolicy == ClientCredentialPolicy::CannotAskClientForCredentials); + return true; +} + +void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime) +{ + NetworkResourceLoadParameters loadParameters; + if (!fillParametersForNetworkProcessLoad(resourceLoader, request, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime, loadParameters)) { + WEBLOADERSTRATEGY_RELEASE_LOG_ERROR("scheduleLoad: no sourceOrigin (priority=%d)", static_cast(resourceLoader.request().priority())); + scheduleInternallyFailedLoad(resourceLoader); + return; + } WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: Resource is being scheduled with the NetworkProcess (priority=%d)", static_cast(resourceLoader.request().priority())); if (!WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::ScheduleResourceLoad(loadParameters), 0)) { @@ -414,7 +427,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL } auto loader = WebResourceLoader::create(resourceLoader, trackingParameters); - m_webResourceLoaders.set(identifier, WTFMove(loader)); + m_webResourceLoaders.set(resourceLoader.identifier(), WTFMove(loader)); } void WebLoaderStrategy::scheduleInternallyFailedLoad(WebCore::ResourceLoader& resourceLoader) @@ -813,7 +826,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) @@ -833,6 +846,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet void WebLoaderStrategy::setOnLineState(bool isOnLine) { + if (m_emulateOfflineState) { + m_isOnLine = isOnLine; + return; + } + if (m_isOnLine == isOnLine) return; @@ -841,6 +859,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 ca2349958666a801b0e0a6bd767dbbcccfb716ae..b5529ff5a2e2fa97bccc21f88689624b3d5a3624 100644 --- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h +++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h @@ -40,6 +40,7 @@ struct FetchOptions; namespace WebKit { class NetworkProcessConnection; +class NetworkResourceLoadParameters; class WebFrame; class WebPage; class WebURLSchemeTaskProxy; @@ -88,8 +89,10 @@ public: bool isOnLine() const final; void addOnlineStateChangeListener(Function&&) final; void setOnLineState(bool); + void setEmulateOfflineState(bool) final; static uint64_t generateLoadIdentifier(); + static bool fillParametersForNetworkProcessLoad(WebCore::ResourceLoader&, const WebCore::ResourceRequest&, const WebResourceLoader::TrackingParameters&, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime, NetworkResourceLoadParameters&); private: void scheduleLoad(WebCore::ResourceLoader&, WebCore::CachedResource*, bool shouldClearReferrerOnHTTPSToHTTPRedirect); @@ -134,6 +137,7 @@ private: HashMap m_preconnectCompletionHandlers; Vector> m_onlineStateChangeListeners; bool m_isOnLine { true }; + bool m_emulateOfflineState { false }; }; } // namespace WebKit diff --git a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp index ecd4052eac038028255a786236e1969853afa1d8..2adc87a59c12d15c651909e67670ac354b59092b 100644 --- a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp +++ b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp @@ -196,6 +196,7 @@ void WebResourceLoader::didReceiveData(const IPC::DataReference& data, int64_t e if (UNLIKELY(m_interceptController.isIntercepting(m_coreLoader->identifier()))) { auto buffer = SharedBuffer::create(data.data(), data.size()); + InspectorInstrumentationWebKit::interceptDidReceiveData(m_coreLoader->frame(), m_coreLoader->identifier(), buffer.get()); m_interceptController.defer(m_coreLoader->identifier(), [this, protectedThis = makeRef(*this), buffer = WTFMove(buffer), encodedDataLength]() mutable { if (m_coreLoader) didReceiveData({ buffer->data(), buffer->size() }, encodedDataLength); @@ -216,6 +217,7 @@ void WebResourceLoader::didFinishResourceLoad(const NetworkLoadMetrics& networkL WEBRESOURCELOADER_RELEASE_LOG("didFinishResourceLoad: (length=%zd)", m_numBytesReceived); if (UNLIKELY(m_interceptController.isIntercepting(m_coreLoader->identifier()))) { + InspectorInstrumentationWebKit::interceptDidFinishResourceLoad(m_coreLoader->frame(), m_coreLoader->identifier()); m_interceptController.defer(m_coreLoader->identifier(), [this, protectedThis = makeRef(*this), networkLoadMetrics]() mutable { if (m_coreLoader) didFinishResourceLoad(networkLoadMetrics); @@ -259,6 +261,7 @@ void WebResourceLoader::didFailResourceLoad(const ResourceError& error) WEBRESOURCELOADER_RELEASE_LOG("didFailResourceLoad:"); if (UNLIKELY(m_interceptController.isIntercepting(m_coreLoader->identifier()))) { + InspectorInstrumentationWebKit::interceptDidFailResourceLoad(m_coreLoader->frame(), m_coreLoader->identifier(), error); m_interceptController.defer(m_coreLoader->identifier(), [this, protectedThis = makeRef(*this), error]() mutable { if (m_coreLoader) didFailResourceLoad(error); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp index 89f05d5cc7064acee45cf09a530143b5e3a2fe1d..0fc6b88966d9d9df624e65119224fd54dcdfc50b 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp @@ -398,6 +398,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); } @@ -831,6 +833,13 @@ std::unique_ptr WebChromeClient::createDateTimeChooser(DateTime #endif +#if ENABLE(ORIENTATION_EVENTS) && !PLATFORM(IOS_FAMILY) +int WebChromeClient::deviceOrientation() const { + // Only overrides are supported for non-iOS platforms. + return 0; +} +#endif + void WebChromeClient::runOpenPanel(Frame& frame, FileChooser& fileChooser) { if (m_page.activeOpenPanelResultListener()) diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp index 2eb0886f13ed035a53b8eaa60605de4dfe53fbe3..c46393209cb4f80704bbc9268fad4371347d5b30 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp @@ -29,6 +29,13 @@ #if ENABLE(DRAG_SUPPORT) #include "WebPage.h" +#include +#include +#include "ShareableBitmap.h" + +#if PLATFORM(WPE) +#include "ArgumentCodersWPE.h" +#endif namespace WebKit { using namespace WebCore; @@ -50,7 +57,7 @@ OptionSet WebDragClient::dragSourceActionMaskForPoint(const In return m_page->allowedDragSourceActions(); } -#if !PLATFORM(COCOA) && !PLATFORM(GTK) +#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE) && !PLATFORM(WIN) void WebDragClient::startDrag(DragItem, DataTransfer&, Frame&) { } diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp index 6c904c9862dce939273e25063f1ac83ce6558cd0..4166ea3112a537257e976fa800266fdc4ddf2d15 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp +++ b/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp @@ -1569,13 +1569,6 @@ void WebFrameLoaderClient::transitionToCommittedForNewPage() if (webPage->scrollPinningBehavior() != DoNotPin) view->setScrollPinningBehavior(webPage->scrollPinningBehavior()); -#if USE(COORDINATED_GRAPHICS) - if (shouldUseFixedLayout) { - view->setDelegatesScrolling(shouldUseFixedLayout); - view->setPaintsEntireContents(shouldUseFixedLayout); - return; - } -#endif } void WebFrameLoaderClient::didRestoreFromBackForwardCache() diff --git a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm index e9f2b2237b1d8a1b21ad28e0fa309b80252b5ebd..b2d3ca7cc093ed428f95df992c208b1b9491067d 100644 --- a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm +++ b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm @@ -127,7 +127,8 @@ static WebCore::CachedImage* cachedImage(Element& element) void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, Element& element, const URL& url, const String& label, Frame*) { ALLOW_DEPRECATED_DECLARATIONS_BEGIN - ASSERT(pasteboardName == String(NSDragPboard)); + if (pasteboardName != String(NSDragPboard)) + return; ALLOW_DEPRECATED_DECLARATIONS_END WebCore::CachedImage* image = cachedImage(element); diff --git a/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2606914d22e85affd9b2f71c361c9db3a14da4f3 --- /dev/null +++ b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebDragClient.h" + +#if ENABLE(DRAG_SUPPORT) + +//#include "ArgumentCodersWPE.h" +#include "ShareableBitmap.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include +#include +#include +#include +#include + +//#include + +namespace WebKit { +using namespace WebCore; + +void WebDragClient::didConcludeEditDrag() +{ +} + +void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame& frame) +{ + m_page->willStartDrag(); + m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().createDragDataMap())); +} + +}; // namespace WebKit. + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp b/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b413bb8150a1633d29b6e2606127c9c1d02442b --- /dev/null +++ b/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "WebDragClient.h" + +#if ENABLE(DRAG_SUPPORT) + +#include "ArgumentCodersWPE.h" +#include "ShareableBitmap.h" +#include "WebPage.h" +#include "WebPageProxyMessages.h" +#include +#include +#include +#include + +namespace WebKit { +using namespace WebCore; + +void WebDragClient::didConcludeEditDrag() +{ +} + +void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame&) +{ + m_page->willStartDrag(); + + ShareableBitmap::Handle handle; + m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().selectionData(), dataTransfer.sourceOperationMask(), handle)); +} + +}; // namespace WebKit. + +#endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp index 4a087235e7bcf915f6e9d4daf8ad48b748ce3b91..3ea0a7106906f4cda63f1b0ce7c595496326e1c3 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp @@ -36,7 +36,9 @@ #include "WebPageCreationParameters.h" #include "WebPreferencesKeys.h" #include +#include #include +#include #include #include #include @@ -123,6 +125,16 @@ void DrawingAreaCoordinatedGraphics::scroll(const IntRect& scrollRect, const Int ASSERT(m_scrollRect.isEmpty()); ASSERT(m_scrollOffset.isEmpty()); ASSERT(m_dirtyRegion.isEmpty()); +// Playwright begin +#if !PLATFORM(WIN) + if (m_webPage.mainFrameView() && m_webPage.mainFrameView()->useFixedLayout()) { + IntRect visibleRect = IntRect(m_layerTreeHost->viewportController().visibleContentsRect()); + visibleRect.move(-scrollDelta.width(), -scrollDelta.height()); + m_layerTreeHost->scrollNonCompositedContents(visibleRect); + return; + } +#endif +// Playwright end m_layerTreeHost->scrollNonCompositedContents(scrollRect); return; } @@ -253,6 +265,7 @@ void DrawingAreaCoordinatedGraphics::updatePreferences(const WebPreferencesStore settings.setAcceleratedCompositingEnabled(false); } #endif + 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. @@ -666,6 +679,11 @@ void DrawingAreaCoordinatedGraphics::enterAcceleratedCompositingMode(GraphicsLay m_scrollOffset = IntSize(); m_displayTimer.stop(); m_isWaitingForDidUpdate = false; +// Playwright begin +#if PLATFORM(WIN) + didChangeAcceleratedCompositingMode(true); +#endif +// Playwright end } void DrawingAreaCoordinatedGraphics::exitAcceleratedCompositingMode() @@ -715,6 +733,11 @@ void DrawingAreaCoordinatedGraphics::exitAcceleratedCompositingMode() // UI process, we still need to let it know about the new contents, so send an Update message. send(Messages::DrawingAreaProxy::Update(m_backingStoreStateID, updateInfo)); } +// Playwright begin +#if PLATFORM(WIN) + didChangeAcceleratedCompositingMode(false); +#endif +// Playwright end } void DrawingAreaCoordinatedGraphics::scheduleDisplay() diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp index 91226dd76b3f18b1eb5aabd99cd840509bf309f4..71db76c7fa649de2dd19e2c6e7f307cb9810049b 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.cpp @@ -183,8 +183,16 @@ void LayerTreeHost::setViewOverlayRootLayer(GraphicsLayer* viewOverlayRootLayer) void LayerTreeHost::scrollNonCompositedContents(const IntRect& rect) { auto* frameView = m_webPage.mainFrameView(); + +// Playwright begin +#if PLATFORM(WIN) if (!frameView || !frameView->delegatesScrolling()) + return +#else + if (!frameView) return; +#endif +// Playwright end m_viewportController.didScroll(rect.location()); if (m_isDiscardable) @@ -313,6 +321,10 @@ void LayerTreeHost::didChangeViewport() if (!view->useFixedLayout()) view->notifyScrollPositionChanged(m_lastScrollPosition); +// Playwright begin + else + m_viewportController.didScroll(m_lastScrollPosition); +// Playwright end } if (m_lastPageScaleFactor != pageScale) { diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h index 4943393a2c351f91147e1e2369870b42439e2ff1..e2bc9cd5cfc6e906fd8931c2525f6dba6f53441a 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h @@ -105,6 +105,13 @@ public: void adjustTransientZoom(double, WebCore::FloatPoint); void commitTransientZoom(double, WebCore::FloatPoint); #endif + +// Playwright begin +#if USE(COORDINATED_GRAPHICS) + const SimpleViewportController& viewportController() const { return m_viewportController; } +#endif +// Playwright end + private: #if USE(COORDINATED_GRAPHICS) void layerFlushTimerFired(); diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHostTextureMapper.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHostTextureMapper.cpp index be37cb482bccc92412701ba41951c3da57cb7e2e..aebb82d4e149c192bc28383fc722ae1b0a2f5d14 100644 --- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHostTextureMapper.cpp +++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHostTextureMapper.cpp @@ -29,6 +29,7 @@ #if USE(GRAPHICS_LAYER_TEXTURE_MAPPER) +#include "DrawingArea.h" #include "WebPage.h" #include #include diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp index cdba5ae658de5bda9ef87a2b6ebc99a44d33d658..90d718d74188fcb2ae05ba7b1dd741054d061366 100644 --- a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp +++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp @@ -27,6 +27,7 @@ #include "DrawingArea.h" #include "DrawingAreaMessages.h" +#include "DrawingAreaProxyMessages.h" #include "WebPage.h" #include "WebPageCreationParameters.h" #include "WebProcess.h" @@ -82,6 +83,13 @@ void DrawingArea::dispatchAfterEnsuringUpdatedScrollPosition(WTF::Function #include #include #include #include #include +#include #include #include @@ -255,4 +259,22 @@ void WebCookieJar::deleteCookie(const WebCore::Document& document, const URL& ur WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::DeleteCookie(url, cookieName), 0); } +void WebCookieJar::setCookieFromResponse(ResourceLoader& loader, const String& setCookieValue) +{ + auto* webFrame = WebFrame::fromCoreFrame(*loader.frame()); + + WebResourceLoader::TrackingParameters trackingParameters; + trackingParameters.webPageProxyID = webFrame->page()->webPageProxyIdentifier(); + trackingParameters.pageID = webFrame->page()->identifier(); + trackingParameters.frameID = webFrame->frameID(); + trackingParameters.resourceID = loader.identifier(); + + NetworkResourceLoadParameters loadParameters; + if (!WebLoaderStrategy::fillParametersForNetworkProcessLoad(loader, loader.request(), trackingParameters, true, 0_s, loadParameters)) + return; + + URL mainDocumentURL = loader.frame()->document()->topDocument().url(); + WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCookieFromResponse(loadParameters, mainDocumentURL, setCookieValue), 0); +} + } // namespace WebKit diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h index bc78502b18b994a3ffa47b933273ebdb84fafde9..f4c95fcbc0a1d618cc51f748a0df82b7ebe20cab 100644 --- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h +++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h @@ -52,6 +52,8 @@ public: void cookiesDeleted(const String& host, const Vector&); void allCookiesDeleted(); + void setCookieFromResponse(WebCore::ResourceLoader&, const String& setCookieValue); + private: WebCookieJar(); 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 af905408117bbd6239212d1d9e14aa2a97f41129..13a8d05a15f3b65f726a54ef47a9d8a3cb298eaa 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp +++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp @@ -882,6 +882,9 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters) m_page->setCanUseCredentialStorage(parameters.canUseCredentialStorage); + if (parameters.shouldPauseInInspectorWhenShown) + m_page->inspectorController().pauseWhenShown(); + updateThrottleState(); } @@ -1668,6 +1671,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 }; + frame->coreFrame()->loader().load(WTFMove(frameLoadRequest)); + ASSERT(!m_pendingFrameNavigationID); +} + void WebPage::loadRequest(LoadParameters&& loadParameters) { setLastNavigationWasAppBound(loadParameters.request.isAppBound()); @@ -1908,17 +1927,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()) @@ -1935,20 +1950,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)); @@ -1956,7 +1969,6 @@ void WebPage::sendViewportAttributesChanged(const ViewportArguments& viewportArg send(Messages::WebPageProxy::DidChangeViewportProperties(attr)); #endif } -#endif void WebPage::scrollMainFrameIfNotAtMaxScrollPosition(const IntSize& scrollOffset) { @@ -2251,6 +2263,7 @@ void WebPage::scaleView(double scale) } m_page->setViewScaleFactor(scale); + send(Messages::WebPageProxy::ViewScaleFactorDidChange(scale)); scalePage(pageScale, scrollPositionAtNewScale); } @@ -2355,17 +2368,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) @@ -3233,6 +3242,104 @@ void WebPage::touchEvent(const WebTouchEvent& touchEvent) send(Messages::WebPageProxy::DidReceiveEvent(static_cast(touchEvent.type()), handled)); } + +void WebPage::fakeTouchTap(const WebCore::IntPoint& position, uint8_t modifiers, CompletionHandler&& completionHandler) +{ + SetForScope userIsInteractingChange { m_userIsInteracting, true }; + + bool handled = false; + + uint32_t id = 0; + float radiusX = 1.0; + float radiusY = 1.0; + float rotationAngle = 0.0; + float force = 1.0; + const WebCore::IntSize radius(radiusX,radiusY); + const WebCore::IntPoint screenPosition = position; + OptionSet eventModifiers; + eventModifiers = eventModifiers.fromRaw(modifiers); + + { + Vector touchPoints; + WebPlatformTouchPoint::TouchPointState state = WebPlatformTouchPoint::TouchPointState::TouchPressed; + touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force)); + + WebTouchEvent touchEvent(WebEvent::TouchStart, WTFMove(touchPoints), eventModifiers, WallTime::now()); + + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(touchEvent, m_page.get()); + } + { + Vector touchPoints; + WebPlatformTouchPoint::TouchPointState state = WebPlatformTouchPoint::TouchPointState::TouchReleased; + touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force)); + + WebTouchEvent touchEvent(WebEvent::TouchEnd, WTFMove(touchPoints), eventModifiers, WallTime::now()); + + CurrentEvent currentEvent(touchEvent); + handled = handleTouchEvent(touchEvent, m_page.get()) || handled; + } + if (!handled) { + FloatPoint adjustedPoint; + Node* nodeRespondingToClick = m_page->mainFrame().nodeRespondingToClickEvents(position, adjustedPoint); + Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr; + IntPoint adjustedIntPoint = roundedIntPoint(adjustedPoint); + if (!frameRespondingToClick) { + completionHandler(); + return; + } + bool shiftKey = eventModifiers.contains(WebEvent::Modifier::ShiftKey); + bool ctrlKey = eventModifiers.contains(WebEvent::Modifier::ControlKey); + bool altKey = eventModifiers.contains(WebEvent::Modifier::AltKey); + bool metaKey = eventModifiers.contains(WebEvent::Modifier::MetaKey); + double force = 0.0; + SyntheticClickType syntheticClickType = SyntheticClickType::OneFingerTap; + + m_page->mainFrame().eventHandler().mouseMoved(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::NoButton, + PlatformEvent::Type::MouseMoved, + 0, + shiftKey, + ctrlKey, + altKey, + metaKey, + WallTime::now(), + force, + syntheticClickType + )); + m_page->mainFrame().eventHandler().handleMousePressEvent(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::LeftButton, + PlatformEvent::Type::MousePressed, + 1, + shiftKey, + ctrlKey, + altKey, + metaKey, + WallTime::now(), + force, + syntheticClickType + )); + m_page->mainFrame().eventHandler().handleMouseReleaseEvent(PlatformMouseEvent( + adjustedIntPoint, + adjustedIntPoint, + MouseButton::LeftButton, + PlatformEvent::Type::MouseReleased, + 1, + shiftKey, + ctrlKey, + altKey, + metaKey, + WallTime::now(), + force, + syntheticClickType + )); + } + completionHandler(); +} #endif void WebPage::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint) @@ -3309,6 +3416,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(); @@ -3546,6 +3658,7 @@ void WebPage::didCompletePageTransition() void WebPage::show() { send(Messages::WebPageProxy::ShowPage()); + m_page->inspectorController().didShowNewWindow(); } void WebPage::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension) @@ -4286,7 +4399,7 @@ NotificationPermissionRequestManager* WebPage::notificationPermissionRequestMana #if ENABLE(DRAG_SUPPORT) -#if PLATFORM(GTK) +#if PLATFORM(GTK) || PLATFORM(WPE) void WebPage::performDragControllerAction(DragControllerAction action, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet draggingSourceOperationMask, SelectionData&& selectionData, OptionSet flags) { if (!m_page) { @@ -6608,6 +6721,9 @@ Ref WebPage::createDocumentLoader(Frame& frame, const ResourceRe WebsitePoliciesData::applyToDocumentLoader(WTFMove(*m_pendingWebsitePolicies), documentLoader); m_pendingWebsitePolicies = std::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 fe52fe347ea51e7ac6b85b5eea7f04b3c6eb3b6d..243c1f4a318e929d262f7810df3fd3ccd6aeb629 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.h +++ b/Source/WebKit/WebProcess/WebPage/WebPage.h @@ -112,6 +112,10 @@ typedef struct _AtkObject AtkObject; #include "WebPrintOperationGtk.h" #endif +#if PLATFORM(WPE) +#include "ArgumentCodersWPE.h" +#endif + #if PLATFORM(GTK) || PLATFORM(WPE) #include "InputMethodState.h" #endif @@ -965,11 +969,11 @@ public: void clearSelection(); void restoreSelectionInFocusedEditableElement(); -#if ENABLE(DRAG_SUPPORT) && PLATFORM(GTK) +#if ENABLE(DRAG_SUPPORT) && (PLATFORM(GTK) || PLATFORM(WPE)) void performDragControllerAction(DragControllerAction, const WebCore::IntPoint& clientPosition, const WebCore::IntPoint& globalPosition, OptionSet draggingSourceOperationMask, WebCore::SelectionData&&, OptionSet); #endif -#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) +#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) && !PLATFORM(WPE) void performDragControllerAction(DragControllerAction, const WebCore::DragData&, SandboxExtension::Handle&&, SandboxExtension::HandleArray&&); #endif @@ -983,6 +987,9 @@ public: void didStartDrag(); void dragCancelled(); OptionSet allowedDragSourceActions() const { return m_allowedDragSourceActions; } +#if PLATFORM(MAC) + void setDragPasteboardName(const String& pasteboardName) { m_page->setDragPasteboardName(pasteboardName); } +#endif #endif void beginPrinting(WebCore::FrameIdentifier, const PrintInfo&); @@ -1215,6 +1222,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(); @@ -1573,6 +1581,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&&); @@ -1610,6 +1619,7 @@ private: void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled); #elif ENABLE(TOUCH_EVENTS) void touchEvent(const WebTouchEvent&); + void fakeTouchTap(const WebCore::IntPoint& position, uint8_t modifiers, CompletionHandler&& completionHandler); #endif void cancelPointer(WebCore::PointerID, const WebCore::IntPoint&); @@ -1732,9 +1742,7 @@ private: void countStringMatches(const String&, OptionSet, uint32_t maxMatchCount); void replaceMatches(const Vector& matchIndices, const String& replacementText, bool selectionOnly, CompletionHandler&&); -#if USE(COORDINATED_GRAPHICS) void sendViewportAttributesChanged(const WebCore::ViewportArguments&); -#endif void didChangeSelectedIndexForActivePopupMenu(int32_t newIndex); void setTextForActivePopupMenu(int32_t index); @@ -2260,6 +2268,7 @@ private: UserActivity m_userActivity; uint64_t m_pendingNavigationID { 0 }; + uint64_t m_pendingFrameNavigationID { 0 }; std::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 7afb98959e7e4eb865d08710706b14e5043cd0da..cb75ad8ee7f612a5c4b68cd952c5d935cb2142f5 100644 --- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in +++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in @@ -133,6 +133,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); @@ -144,6 +145,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType #endif #if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS) TouchEvent(WebKit::WebTouchEvent event) + FakeTouchTap(WebCore::IntPoint position, uint8_t modifiers) -> () Async #endif CancelPointer(WebCore::PointerID pointerId, WebCore::IntPoint documentPoint) @@ -178,6 +180,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) LoadSimulatedRequestAndResponse(struct WebKit::LoadParameters loadParameters, WebCore::ResourceResponse simulatedResponse) @@ -317,10 +320,10 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType AddMIMETypeWithCustomContentProvider(String mimeType) # Drag and drop. -#if PLATFORM(GTK) && ENABLE(DRAG_SUPPORT) +#if (PLATFORM(GTK) || PLATFORM(WPE)) && ENABLE(DRAG_SUPPORT) PerformDragControllerAction(enum:uint8_t WebKit::DragControllerAction action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet draggingSourceOperationMask, WebCore::SelectionData selection, OptionSet flags) #endif -#if !PLATFORM(GTK) && ENABLE(DRAG_SUPPORT) +#if !PLATFORM(GTK) && !PLATFORM(WPE) && ENABLE(DRAG_SUPPORT) PerformDragControllerAction(enum:uint8_t WebKit::DragControllerAction action, WebCore::DragData dragData, WebKit::SandboxExtension::Handle sandboxExtensionHandle, WebKit::SandboxExtension::HandleArray sandboxExtensionsForUpload) #endif #if ENABLE(DRAG_SUPPORT) @@ -329,6 +332,10 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType DragCancelled() #endif +#if PLATFORM(MAC) && ENABLE(DRAG_SUPPORT) + SetDragPasteboardName(String pasteboardName) +#endif + #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT) RequestDragStart(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet allowedActionsMask) diff --git a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm index 375e5e97370d73edce1afe1dc704a851921427f8..3ce7528d64a3695e6c87b78df3e219b855789fbb 100644 --- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm +++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm @@ -833,21 +833,37 @@ String WebPage::platformUserAgent(const URL&) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenIsTouchPrimaryInputDevice(); +#else return true; +#endif } bool WebPage::hoverSupportedByAnyAvailablePointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenHasTouchDevice(); +#else return true; +#endif } std::optional WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + if (screenIsTouchPrimaryInputDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } OptionSet WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const { +#if ENABLE(TOUCH_EVENTS) + if (screenHasTouchDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } diff --git a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp index 8e9454597bb23b22c506f929020fc3c37ffaa71a..9730e673e85da143a3acdda03fb9fa3fb4fb1119 100644 --- a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp +++ b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -118,21 +119,37 @@ String WebPage::platformUserAgent(const URL&) const bool WebPage::hoverSupportedByPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenIsTouchPrimaryInputDevice(); +#else return true; +#endif } bool WebPage::hoverSupportedByAnyAvailablePointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + return !screenHasTouchDevice(); +#else return true; +#endif } std::optional WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const { +#if ENABLE(TOUCH_EVENTS) + if (screenIsTouchPrimaryInputDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } OptionSet WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const { +#if ENABLE(TOUCH_EVENTS) + if (screenHasTouchDevice()) + return PointerCharacteristics::Coarse; +#endif return PointerCharacteristics::Fine; } diff --git a/Source/WebKit/WebProcess/WebProcess.cpp b/Source/WebKit/WebProcess/WebProcess.cpp index 87cc422a592dbb6c547219189a57857da94d1260..8fe6007994a9d22c417309737c60a8bda0c6cea5 100644 --- a/Source/WebKit/WebProcess/WebProcess.cpp +++ b/Source/WebKit/WebProcess/WebProcess.cpp @@ -87,6 +87,7 @@ #include "WebsiteData.h" #include "WebsiteDataStoreParameters.h" #include "WebsiteDataType.h" +#include #include #include #include @@ -343,6 +344,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/WebKit/WebProcess/win/WebProcessMainWin.cpp b/Source/WebKit/WebProcess/win/WebProcessMainWin.cpp index 8987c3964a9308f2454759de7f8972215a3ae416..bcac0afeb94ed8123d1f9fb0b932c8497d157b49 100644 --- a/Source/WebKit/WebProcess/win/WebProcessMainWin.cpp +++ b/Source/WebKit/WebProcess/win/WebProcessMainWin.cpp @@ -42,7 +42,9 @@ public: bool platformInitialize() override { if (SetProcessDpiAwarenessContextPtr()) - SetProcessDpiAwarenessContextPtr()(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); + // Playwright begin + SetProcessDpiAwarenessContextPtr()(DPI_AWARENESS_CONTEXT_UNAWARE); + // Playwright end else SetProcessDPIAware(); return true; diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm index c020b8bba2d0041f3e54e7f18c6a3776833ef049..88ccc0d2354e95feeaef730a5a10f59eb1bbb818 100644 --- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm @@ -4236,7 +4236,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 8a4ec8910ca2f4104e4b59b22f1081200f280f9b..ef1933c8030f40d9deed891fcef31a93ad037c7d 100644 --- a/Source/WebKitLegacy/mac/WebView/WebView.mm +++ b/Source/WebKitLegacy/mac/WebView/WebView.mm @@ -4027,7 +4027,7 @@ IGNORE_WARNINGS_END } #endif // PLATFORM(IOS_FAMILY) -#if ENABLE(TOUCH_EVENTS) +#if ENABLE(IOS_TOUCH_EVENTS) - (NSArray *)_touchEventRegions { @@ -4069,7 +4069,7 @@ IGNORE_WARNINGS_END }).autorelease(); } -#endif // ENABLE(TOUCH_EVENTS) +#endif // ENABLE(IOS_TOUCH_EVENTS) // For backwards compatibility with the WebBackForwardList API, we honor both // a per-WebView and a per-preferences setting for whether to use the back/forward cache. diff --git a/Source/cmake/FindLibVPX.cmake b/Source/cmake/FindLibVPX.cmake new file mode 100644 index 0000000000000000000000000000000000000000..dd6a53e2d57318489b7e49dd7373706d5d9dc387 --- /dev/null +++ b/Source/cmake/FindLibVPX.cmake @@ -0,0 +1,25 @@ +# Find LibVPX + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LIBVPX REQUIRED vpx) + +find_path(LIBVPX_INCLUDE_DIRS + NAMES vpx/vp8.h + HINTS ${PC_LIBVPX_INCLUDEDIR} + ${PC_LIBVPX_INCLUDE_DIRS} +) + +find_library(LIBVPX_LIBRARIES + NAMES vpx + HINTS ${PC_LIBVPX_LIBDIR} + ${PC_LIBVPX_LIBRARY_DIRS} +) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibVPX REQUIRED_VARS LIBVPX_INCLUDE_DIRS LIBVPX_LIBRARIES + VERSION_VAR PC_LIBVPX_VERSION) + +mark_as_advanced( + LIBVPX_INCLUDE_DIRS + LIBVPX_LIBRARIES +) diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake index 7de2d6046a98839687ed277009bd9fd4eb5c2fe0..ca67eefec0f255c88122351d845f7daab88f6a16 100644 --- a/Source/cmake/OptionsGTK.cmake +++ b/Source/cmake/OptionsGTK.cmake @@ -5,6 +5,8 @@ WEBKIT_OPTION_BEGIN() SET_PROJECT_VERSION(2 33 2) +set(ENABLE_WEBKIT_LEGACY OFF) + set(CMAKE_C_VISIBILITY_PRESET hidden) set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(bmalloc_LIBRARY_TYPE OBJECT) @@ -32,6 +34,10 @@ find_package(EGL) find_package(OpenGL) find_package(OpenGLES2) +# Playwright begin +find_package(LibVPX REQUIRED) +# Playwright end + include(GStreamerDefinitions) SET_AND_EXPOSE_TO_BUILD(USE_ATK TRUE) @@ -70,7 +76,7 @@ WEBKIT_OPTION_DEFINE(ENABLE_INTROSPECTION "Whether to enable GObject introspecti WEBKIT_OPTION_DEFINE(ENABLE_QUARTZ_TARGET "Whether to enable support for the Quartz windowing target." PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_WAYLAND_TARGET "Whether to enable support for the Wayland windowing target." PUBLIC ON) WEBKIT_OPTION_DEFINE(ENABLE_X11_TARGET "Whether to enable support for the X11 windowing target." PUBLIC ON) -WEBKIT_OPTION_DEFINE(USE_AVIF "Whether to enable support for AVIF images." PUBLIC ${ENABLE_EXPERIMENTAL_FEATURES}) +WEBKIT_OPTION_DEFINE(USE_AVIF "Whether to enable support for AVIF images." PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_GTK4 "Whether to enable usage of GTK4 instead of GTK3." PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_LCMS "Whether to enable support for image color management using libcms2." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_LIBHYPHEN "Whether to enable the default automatic hyphenation implementation." PUBLIC ON) @@ -78,7 +84,7 @@ WEBKIT_OPTION_DEFINE(USE_LIBNOTIFY "Whether to enable the default web notificati WEBKIT_OPTION_DEFINE(USE_LIBSECRET "Whether to enable the persistent credential storage using libsecret." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_OPENGL_OR_ES "Whether to use OpenGL or ES." PUBLIC ${USE_OPENGL_OR_ES_DEFAULT}) WEBKIT_OPTION_DEFINE(USE_OPENJPEG "Whether to enable support for JPEG2000 images." PUBLIC ON) -WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Soup 3." PUBLIC OFF) +WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Soup 3." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_SYSTEMD "Whether to enable journald logging" PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_WOFF2 "Whether to enable support for WOFF2 Web Fonts." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_WPE_RENDERER "Whether to enable WPE rendering" PUBLIC ON) @@ -133,7 +139,7 @@ endif () # without approval from a GTK reviewer. There must be strong reason to support # changing the value of the option. WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DRAG_SUPPORT PUBLIC ON) -WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC OFF) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPELLCHECK PUBLIC ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_TOUCH_EVENTS PUBLIC ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEB_CRYPTO PUBLIC ON) @@ -163,7 +169,6 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INPUT_TYPE_MONTH PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INPUT_TYPE_TIME PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INPUT_TYPE_WEEK PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_LAYOUT_FORMATTING_CONTEXT PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) -WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_STREAM PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MHTML PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MOUSE_CURSOR_SCALE PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NETSCAPE_PLUGIN_API PRIVATE OFF) @@ -180,6 +185,16 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SHAREABLE_RESOURCE PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEB_API_STATISTICS PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEB_RTC PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) +# 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_DEVICE_ORIENTATION PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_STREAM PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPEECH_SYNTHESIS 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 ed79aed95af5c7cf5525f8647258f4747a5b2553..9ddf39dabf46e4b405418cd4a02c418dcf90f6d7 100644 --- a/Source/cmake/OptionsWPE.cmake +++ b/Source/cmake/OptionsWPE.cmake @@ -3,6 +3,7 @@ include(VersioningUtils) SET_PROJECT_VERSION(2 33 2) +set(ENABLE_WEBKIT_LEGACY OFF) set(USER_AGENT_BRANDING "" CACHE STRING "Branding to add to user agent string") find_package(Cairo 1.14.0 REQUIRED) @@ -50,7 +51,6 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CSS_TYPED_OM PRIVATE ${ENABLE_EXPERIMENT WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FILTERS_LEVEL_2 PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GPU_PROCESS PRIVATE OFF) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_LAYOUT_FORMATTING_CONTEXT PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) -WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_STREAM PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MHTML PRIVATE ON) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NETSCAPE_PLUGIN_API PRIVATE OFF) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NOTIFICATIONS PRIVATE ON) @@ -67,15 +67,28 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBGL2 PRIVATE OFF) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEB_RTC PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WEBXR PRIVATE ${ENABLE_EXPERIMENTAL_FEATURES}) +# 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_DATALIST_ELEMENT PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DOWNLOAD_ATTRIBUTE PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DRAG_SUPPORT PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_STREAM PRIVATE ON) +WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPEECH_SYNTHESIS 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. WEBKIT_OPTION_DEFINE(ENABLE_GTKDOC "Whether or not to use generate gtkdoc." PUBLIC OFF) -WEBKIT_OPTION_DEFINE(ENABLE_WPE_QT_API "Whether to enable support for the Qt5/QML plugin" PUBLIC ${ENABLE_DEVELOPER_MODE}) -WEBKIT_OPTION_DEFINE(USE_AVIF "Whether to enable support for AVIF images." PUBLIC ${ENABLE_EXPERIMENTAL_FEATURES}) +WEBKIT_OPTION_DEFINE(ENABLE_WPE_QT_API "Whether to enable support for the Qt5/QML plugin" PUBLIC OFF) +WEBKIT_OPTION_DEFINE(USE_AVIF "Whether to enable support for AVIF images." PUBLIC OFF) WEBKIT_OPTION_DEFINE(USE_LCMS "Whether to enable support for image color management using libcms2." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_OPENJPEG "Whether to enable support for JPEG2000 images." PUBLIC ON) -WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Soup 3." PUBLIC OFF) +WEBKIT_OPTION_DEFINE(USE_SOUP2 "Whether to enable usage of Soup 2 instead of Soup 3." PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_SYSTEMD "Whether to enable journald logging" PUBLIC ON) WEBKIT_OPTION_DEFINE(USE_WOFF2 "Whether to enable support for WOFF2 Web Fonts." PUBLIC ON) diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake index ae2ab4d10367dbf6bc38f9a0246cab2485b6fb67..e1b8732496b4adc13551a7b3d7cbd6e1cc961bd9 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 () @@ -88,6 +89,13 @@ if (${WTF_PLATFORM_WIN_CAIRO}) # No support planned WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF) + # 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_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/Source/cmake/OptionsWinCairo.cmake b/Source/cmake/OptionsWinCairo.cmake index 512392e6424ea64ff65fffc14df30344ce6cbe99..90b7c9614333868ff8c157f5bd938da98be4871d 100644 --- a/Source/cmake/OptionsWinCairo.cmake +++ b/Source/cmake/OptionsWinCairo.cmake @@ -32,15 +32,36 @@ if (OpenJPEG_FOUND) endif () find_package(WOFF2 1.0.2 COMPONENTS dec) -if (WOFF2_FOUND) - SET_AND_EXPOSE_TO_BUILD(USE_WOFF2 ON) -endif () +SET_AND_EXPOSE_TO_BUILD(USE_WOFF2 ON) find_package(WebP COMPONENTS demux) if (WebP_FOUND) SET_AND_EXPOSE_TO_BUILD(USE_WEBP ON) endif () +# Playwright begin +if (NOT LIBVPX_PACKAGE_PATH) + set(LIBVPX_PACKAGE_PATH "C:\\vcpkg\\packages\\libvpx_x64-windows") +endif() +file(TO_CMAKE_PATH "${LIBVPX_PACKAGE_PATH}" LIBVPX_PACKAGE_PATH) +message(STATUS "Using LIBVPX_PACKAGE_PATH = ${LIBVPX_PACKAGE_PATH}") + +find_library(LIBVPX_CUSTOM_LIBRARY vpxmd.lib + HINTS ${LIBVPX_PACKAGE_PATH}/lib + REQIRED + NO_DEFAULT_PATH +) +message(STATUS "Found LIBVPX_CUSTOM_LIBRARY = ${LIBVPX_CUSTOM_LIBRARY}") + +find_path(LIBVPX_CUSTOM_INCLUDE_DIR + NAMES vpx/vp8.h + HINTS ${LIBVPX_PACKAGE_PATH}/include + REQUIRED + NO_DEFAULT_PATH +) +message(STATUS "Found LIBVPX_CUSTOM_INCLUDE_DIR = ${LIBVPX_CUSTOM_INCLUDE_DIR}") +# Playwright end + set(USE_ANGLE_EGL ON) set(USE_ANGLE_WEBGL ON) diff --git a/Tools/MiniBrowser/gtk/BrowserTab.c b/Tools/MiniBrowser/gtk/BrowserTab.c index ab75a69f64aadee2b22e0d8d114932db55aaa000..e82450546a7dba66155b26c3d841d0a74675c701 100644 --- a/Tools/MiniBrowser/gtk/BrowserTab.c +++ b/Tools/MiniBrowser/gtk/BrowserTab.c @@ -161,6 +161,11 @@ static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, Brows #endif } +static gboolean loadFailed() +{ + return TRUE; +} + static GtkWidget *createInfoBarQuestionMessage(const char *title, const char *text) { GtkWidget *dialog = gtk_info_bar_new_with_buttons("No", GTK_RESPONSE_NO, "Yes", GTK_RESPONSE_YES, NULL); @@ -649,6 +654,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); @@ -698,6 +704,9 @@ static char *getInternalURI(const char *uri) if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank")) return g_strconcat(BROWSER_ABOUT_SCHEME, uri + strlen ("about"), NULL); + if (!g_str_has_prefix(uri, "http://") && !g_str_has_prefix(uri, "https://") && !g_str_has_prefix(uri, "file://")) + return g_strconcat("http://", uri, NULL); + return g_strdup(uri); } diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.c b/Tools/MiniBrowser/gtk/BrowserWindow.c index 063e94568490cc72193222987b805e7dfff94fea..76ba6df237dd8c2c2bcf339541751e82d842bf76 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.c +++ b/Tools/MiniBrowser/gtk/BrowserWindow.c @@ -70,7 +70,7 @@ struct _BrowserWindowClass { GtkApplicationWindowClass parent; }; -static const char *defaultWindowTitle = "WebKitGTK MiniBrowser"; +static const char *defaultWindowTitle = "🎭 Playwright"; static const gdouble minimumZoomLevel = 0.5; static const gdouble maximumZoomLevel = 3; static const gdouble defaultZoomLevel = 1; @@ -154,13 +154,11 @@ static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, Browser static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window) { const char *title = webkit_web_view_get_title(webView); + char *privateTitle = NULL; if (!title) title = defaultWindowTitle; - char *privateTitle = NULL; - if (webkit_web_view_is_controlled_by_automation(webView)) - privateTitle = g_strdup_printf("[Automation] %s", title); - else if (webkit_web_view_is_ephemeral(webView)) - privateTitle = g_strdup_printf("[Private] %s", title); + else + privateTitle = g_strdup_printf("🎭 Playwright: %s", title); gtk_window_set_title(GTK_WINDOW(window), privateTitle ? privateTitle : title); g_free(privateTitle); } @@ -1373,6 +1371,12 @@ static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event) } #endif +static void zeroPreferredSize(GtkWidget* widget, gint* minimumSize, gint* naturalSize) +{ + *minimumSize = 10; + *naturalSize = 10; +} + static void browser_window_class_init(BrowserWindowClass *klass) { GObjectClass *gobjectClass = G_OBJECT_CLASS(klass); @@ -1386,6 +1390,14 @@ static void browser_window_class_init(BrowserWindowClass *klass) GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass); widgetClass->delete_event = browserWindowDeleteEvent; #endif + +// Playwrigth begin + // Override preferred (which is minimum :-) size to 0 so that we can + // emulate arbitrary resolution. + GtkWidgetClass* browserWidgetClass = GTK_WIDGET_CLASS(klass); + browserWidgetClass->get_preferred_width = zeroPreferredSize; + browserWidgetClass->get_preferred_height = zeroPreferredSize; +// Playwrigth end } /* Public API. */ diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.h b/Tools/MiniBrowser/gtk/BrowserWindow.h index 62629b4c1c25ae82bd797b39bbf9de0331f8eed2..5de7900a29b0e629f1ac404bbb0dc5b4e605294d 100644 --- a/Tools/MiniBrowser/gtk/BrowserWindow.h +++ b/Tools/MiniBrowser/gtk/BrowserWindow.h @@ -37,7 +37,7 @@ G_BEGIN_DECLS #define BROWSER_IS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_WINDOW)) #define BROWSER_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BROWSER_TYPE_WINDOW)) #define BROWSER_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), BROWSER_TYPE_WINDOW, BrowserWindowClass)) -#define BROWSER_DEFAULT_URL "http://www.webkitgtk.org/" +#define BROWSER_DEFAULT_URL "about:blank" #define BROWSER_ABOUT_SCHEME "minibrowser-about" typedef struct _BrowserWindow BrowserWindow; diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c index 241ac28e0d59d93c81bad88bcddcb197620b3f2a..6554de7369b99556ff558a0340dd580bf9420393 100644 --- a/Tools/MiniBrowser/gtk/main.c +++ b/Tools/MiniBrowser/gtk/main.c @@ -55,7 +55,12 @@ static gboolean enableITP; static gboolean enableSandbox; static gboolean exitAfterLoad; static gboolean webProcessCrashed; +static gboolean inspectorPipe; +static gboolean headless; +static gboolean noStartupWindow; +static const char *userDataDir; static gboolean printVersion; +static GtkApplication *browserApplication = NULL; typedef enum { MINI_BROWSER_ERROR_INVALID_ABOUT_PATH @@ -149,6 +154,10 @@ static const GOptionEntry commandLineOptions[] = { "enable-sandbox", 0, 0, G_OPTION_ARG_NONE, &enableSandbox, "Enable web process sandbox support", NULL }, { "exit-after-load", 0, 0, G_OPTION_ARG_NONE, &exitAfterLoad, "Quit the browser after the load finishes", NULL }, { "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 } }; @@ -617,6 +626,48 @@ 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); + gtk_window_set_application(GTK_WINDOW(newWindow), browserApplication); + browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView); + gtk_widget_grab_focus(GTK_WIDGET(newWebView)); + gtk_widget_show(GTK_WIDGET(newWindow)); + webkit_web_view_load_uri(newWebView, "about:blank"); + return newWebView; +} + +static void quitBroserApplication(WebKitBrowserInspector* browser_inspector) +{ + g_application_release(G_APPLICATION(browserApplication)); +} + +static void keepApplicationAliveUntilQuit(GApplication *application) +{ + // Reference the application, it will be released in quitBroserApplication. + g_application_hold(application); + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "quit-application", G_CALLBACK(quitBroserApplication), NULL); +} + +static void configureBrowserInspectorPipe() +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + + webkit_browser_inspector_initialize_pipe(proxy, ignoreHosts); +} + static void startup(GApplication *application) { const char *actionAccels[] = { @@ -647,10 +698,22 @@ static void startup(GApplication *application) static void activate(GApplication *application, WebKitSettings *webkitSettings) { + if (inspectorPipe) + configureBrowserInspectorPipe(); + + if (noStartupWindow) { + keepApplicationAliveUntilQuit(application); + g_clear_object(&webkitSettings); + return; + } + WebKitWebsiteDataManager *manager; - if (privateMode || automationMode) + if (userDataDir) { + manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL); + } else if (inspectorPipe || privateMode || automationMode) { manager = webkit_website_data_manager_new_ephemeral(); - else { + } else { char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION_STRING, "MiniBrowser", NULL); char *cacheDirectory = g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION_STRING, "MiniBrowser", NULL); manager = webkit_website_data_manager_new("base-data-directory", dataDirectory, "base-cache-directory", cacheDirectory, NULL); @@ -674,6 +737,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) "use-system-appearance-for-scrollbars", FALSE, #endif NULL); + persistentWebContext = webContext; g_object_unref(manager); if (enableSandbox) @@ -755,9 +819,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings) if (exitAfterLoad) exitAfterWebViewLoadFinishes(webView, application); } - gchar *url = argumentToURL(uriArguments[i]); - webkit_web_view_load_uri(webView, url); - g_free(url); + webkit_web_view_load_uri(webView, uriArguments[i]); } } else { WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings, userContentManager, defaultWebsitePolicies); @@ -833,9 +895,11 @@ int main(int argc, char *argv[]) } GtkApplication *application = gtk_application_new("org.webkitgtk.MiniBrowser", G_APPLICATION_NON_UNIQUE); + browserApplication = application; g_signal_connect(application, "startup", G_CALLBACK(startup), NULL); g_signal_connect(application, "activate", G_CALLBACK(activate), webkitSettings); g_application_run(G_APPLICATION(application), 0, NULL); + browserApplication = NULL; g_object_unref(application); return exitAfterLoad && webProcessCrashed ? 1 : 0; diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp index 2e5c76219de1a60dccae1c8088ceabd8b12c95d0..cf6650a4fda1516b2adf578fc263ad874b200c01 100644 --- a/Tools/MiniBrowser/wpe/main.cpp +++ b/Tools/MiniBrowser/wpe/main.cpp @@ -40,6 +40,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; @@ -63,6 +66,9 @@ static const GOptionEntry commandLineOptions[] = { "bg-color", 0, 0, G_OPTION_ARG_STRING, &bgColor, "Window background color. Default: white", "COLOR" }, { "enable-itp", 0, 0, G_OPTION_ARG_NONE, &enableITP, "Enable Intelligent Tracking Prevention (ITP)", nullptr }, { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WPE version", nullptr }, + { "inspector-pipe", 'v', 0, G_OPTION_ARG_NONE, &inspectorPipe, "Expose remote debugging protocol over pipe", nullptr }, + { "user-data-dir", 0, 0, G_OPTION_ARG_STRING, &userDataDir, "Default profile persistence folder location", "FILE" }, + { "no-startup-window", 0, 0, G_OPTION_ARG_NONE, &noStartupWindow, "Do not open default page", nullptr }, { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, nullptr, "[URL]" }, { nullptr, 0, 0, G_OPTION_ARG_NONE, nullptr, nullptr, nullptr } }; @@ -147,13 +153,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(); @@ -165,17 +192,66 @@ 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)); +// Playwright begin + if (headlessMode) { + webkit_web_view_backend_set_screenshot_callback(viewBackend, + [](gpointer data) { + return static_cast(data)->snapshot(); + }); + } +// Playwright end + WebKitWebView* newWebView; + if (webView) { + newWebView = webkit_web_view_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, "create", G_CALLBACK(createWebView), 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 quitBroserApplication(WebKitBrowserInspector* browser_inspector, gpointer data) +{ + GMainLoop* mainLoop = static_cast(data); + g_main_loop_quit(mainLoop); +} + +static void configureBrowserInspector(GMainLoop* mainLoop) +{ + WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default(); + g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL); + g_signal_connect(browserInspector, "quit-application", G_CALLBACK(quitBroserApplication), mainLoop); + webkit_browser_inspector_initialize_pipe(proxy, ignoreHosts); +} + int main(int argc, char *argv[]) { #if ENABLE_DEVELOPER_MODE @@ -207,6 +283,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(); @@ -216,7 +302,15 @@ int main(int argc, char *argv[]) return 1; } - auto* manager = (privateMode || automationMode) ? webkit_website_data_manager_new_ephemeral() : webkit_website_data_manager_new(nullptr); + WebKitWebsiteDataManager *manager; + if (userDataDir) { + manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL); + cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL); + } else if (inspectorPipe || privateMode || automationMode) { + manager = webkit_website_data_manager_new_ephemeral(); + } else { + manager = webkit_website_data_manager_new(NULL); + } webkit_website_data_manager_set_itp_enabled(manager, enableITP); if (proxy) { @@ -228,7 +322,8 @@ int main(int argc, char *argv[]) if (ignoreTLSErrors) webkit_website_data_manager_set_tls_errors_policy(manager, WEBKIT_TLS_ERRORS_POLICY_IGNORE); - auto* webContext = webkit_web_context_new_with_website_data_manager(manager); + 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) { @@ -287,7 +382,14 @@ int main(int argc, char *argv[]) auto* viewBackend = webkit_web_view_backend_new(wpeBackend, [](gpointer data) { delete static_cast(data); }, backend.release()); - +// Playwright begin + if (headlessMode) { + webkit_web_view_backend_set_screenshot_callback(viewBackend, + [](gpointer data) { + return static_cast(data)->snapshot(); + }); + } +// Playwright end auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "backend", viewBackend, "web-context", webContext, @@ -304,8 +406,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); @@ -318,16 +418,9 @@ int main(int argc, char *argv[]) webkit_web_view_set_background_color(webView, &color); if (uriArguments) { - const char* uri = uriArguments[0]; - if (g_str_equal(uri, "about:gpu")) - uri = "webkit://gpu"; - - GFile* file = g_file_new_for_commandline_arg(uri); - char* url = g_file_get_uri(file); - g_object_unref(file); - webkit_web_view_load_uri(webView, url); - g_free(url); - } else if (automationMode) + // Playwright: avoid weird url transformation like http://trac.webkit.org/r240840 + webkit_web_view_load_uri(webView, uriArguments[0]); + } else if (automationMode || inspectorPipe) webkit_web_view_load_uri(webView, "about:blank"); else webkit_web_view_load_uri(webView, "https://wpewebkit.org"); @@ -337,8 +430,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/PlatformWin.cmake b/Tools/PlatformWin.cmake index ef4407cfc114e602d98ed81724da504f453e258f..448dd483715162baba484f756fbcc1d72de4ba0c 100644 --- a/Tools/PlatformWin.cmake +++ b/Tools/PlatformWin.cmake @@ -12,4 +12,5 @@ endif () if (ENABLE_WEBKIT) add_subdirectory(WebKitTestRunner) + add_subdirectory(Playwright/win) endif () diff --git a/Tools/Scripts/build-webkit b/Tools/Scripts/build-webkit index ddc2a96ac68cd51d5f4efeca78a118db91709aa2..57a78f54e72d264daa27faa53ac2a30cab98dd82 100755 --- a/Tools/Scripts/build-webkit +++ b/Tools/Scripts/build-webkit @@ -247,7 +247,7 @@ if (isAppleCocoaWebKit()) { push @projects, ("Source/WebKit"); if (!isEmbeddedWebKit()) { - push @projects, ("Tools/MiniBrowser"); + push @projects, ("Tools/Playwright"); # WebInspectorUI must come after JavaScriptCore and WebCore but before WebKit and WebKit2 my $webKitIndex = first { $projects[$_] eq "Source/WebKitLegacy" } 0..$#projects; diff --git a/Tools/WebKitTestRunner/PlatformGTK.cmake b/Tools/WebKitTestRunner/PlatformGTK.cmake index 6f8366b63e43eca6b95b67bb47fee9e7a1970cf9..cc8299dfa4380b833e79a870779a222059579d3b 100644 --- a/Tools/WebKitTestRunner/PlatformGTK.cmake +++ b/Tools/WebKitTestRunner/PlatformGTK.cmake @@ -26,6 +26,7 @@ list(APPEND WebKitTestRunner_LIBRARIES ${GLIB_LIBRARIES} Cairo::Cairo GTK::GTK + stdc++fs ) list(APPEND WebKitTestRunnerInjectedBundle_LIBRARIES diff --git a/Tools/WebKitTestRunner/PlatformWPE.cmake b/Tools/WebKitTestRunner/PlatformWPE.cmake index 775b41868718ea6734efc9082f8161eee2e0015e..68a720c0cb01d534653a259536c481683873680d 100644 --- a/Tools/WebKitTestRunner/PlatformWPE.cmake +++ b/Tools/WebKitTestRunner/PlatformWPE.cmake @@ -31,6 +31,7 @@ list(APPEND WebKitTestRunner_LIBRARIES ${WPEBACKEND_FDO_LIBRARIES} Cairo::Cairo WPEToolingBackends + stdc++fs ) list(APPEND WebKitTestRunnerInjectedBundle_LIBRARIES diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 8b5d93545a606748f492f6b73cdbd1219596cc0f..f81ce7d529281b68cb674cb25c53844c1732c56e 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -787,6 +787,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options) 0, // requestStorageAccessConfirm shouldAllowDeviceOrientationAndMotionAccess, runWebAuthenticationPanel, + 0, // handleJavaScriptDialog decidePolicyForSpeechRecognitionPermissionRequest, decidePolicyForMediaKeySystemPermissionRequest }; diff --git a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm index 296c902f375b1189f45ee56bb3ffd4d826dd26f6..45d8ca4bdd18e2467b26b0c6998b4dc58dde7634 100644 --- a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm +++ b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm @@ -977,4 +977,51 @@ void EventSenderProxy::scaleGestureEnd(double scale) #endif // ENABLE(MAC_GESTURE_EVENTS) +#if ENABLE(TOUCH_EVENTS) +void EventSenderProxy::addTouchPoint(int, int) +{ +} + +void EventSenderProxy::updateTouchPoint(int, int, int) +{ +} + +void EventSenderProxy::touchStart() +{ +} + +void EventSenderProxy::touchMove() +{ +} + +void EventSenderProxy::touchEnd() +{ +} + +void EventSenderProxy::touchCancel() +{ +} + +void EventSenderProxy::clearTouchPoints() +{ +} + +void EventSenderProxy::releaseTouchPoint(int) +{ +} + +void EventSenderProxy::cancelTouchPoint(int) +{ +} + +void EventSenderProxy::setTouchPointRadius(int, int) +{ +} + +void EventSenderProxy::setTouchModifier(WKEventModifiers, bool) +{ +} +#endif // ENABLE(TOUCH_EVENTS) + + } // namespace WTR diff --git a/Tools/gtk/install-dependencies b/Tools/gtk/install-dependencies index 46388b47a0f433fbdae3874a958fb2d207916c45..d42933e66178ff007a5008dc807483c4896ea5e1 100755 --- a/Tools/gtk/install-dependencies +++ b/Tools/gtk/install-dependencies @@ -120,6 +120,7 @@ function installDependenciesWithApt { libhyphen-dev \ libjpeg-dev \ libkate-dev \ + liblcms2-dev \ libmount-dev \ libmpg123-dev \ libnotify-dev \ @@ -143,6 +144,7 @@ function installDependenciesWithApt { libupower-glib-dev \ libwebp-dev \ libwoff-dev \ + libxcb-glx0-dev \ libxcomposite-dev \ libxt-dev \ libxtst-dev \ @@ -151,6 +153,7 @@ function installDependenciesWithApt { nasm \ ninja-build \ patch \ + patchelf \ ruby \ xfonts-utils" diff --git a/Tools/win/DLLLauncher/DLLLauncherMain.cpp b/Tools/win/DLLLauncher/DLLLauncherMain.cpp index 52605867b9302d1afcc56c5e9b0c54acf0827900..6edf24ab60249241ba2969531ef55f4b495dce9e 100644 --- a/Tools/win/DLLLauncher/DLLLauncherMain.cpp +++ b/Tools/win/DLLLauncher/DLLLauncherMain.cpp @@ -99,11 +99,9 @@ static bool prependPath(const std::wstring& directoryToPrepend) static int fatalError(const std::wstring& programName, const std::wstring& message) { std::wstring caption = programName + L" can't open."; -#if USE_CONSOLE_ENTRY_POINT +// Playwright begin fwprintf(stderr, L"%s\n%s\n", caption.c_str(), message.c_str()); -#else - ::MessageBoxW(0, message.c_str(), caption.c_str(), MB_ICONERROR); -#endif +// Playwright end return 1; } diff --git a/Tools/wpe/backends/HeadlessViewBackend.cpp b/Tools/wpe/backends/HeadlessViewBackend.cpp index c09b6f39f894943f11b7a453428fab7d6f6e68fb..bc21acb648562ee0380811599b08f7d26c3e706a 100644 --- a/Tools/wpe/backends/HeadlessViewBackend.cpp +++ b/Tools/wpe/backends/HeadlessViewBackend.cpp @@ -145,27 +145,24 @@ void HeadlessViewBackend::updateSnapshot(struct wpe_fdo_shm_exported_buffer* exp return; } - uint32_t bufferStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_width); - uint8_t* buffer = new uint8_t[bufferStride * m_height]; - memset(buffer, 0, bufferStride * m_height); + uint32_t width = std::max(0, wl_shm_buffer_get_width(shmBuffer)); + uint32_t height = std::max(0, wl_shm_buffer_get_height(shmBuffer)); + if (!width || !height) { + fprintf(stderr, "HeadlessViewBackend::updateSnapshot shmBuffer is empty: %ux%u\n", width, height); + return; + } + uint32_t bufferStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); + uint32_t stride = std::max(0, wl_shm_buffer_get_stride(shmBuffer)); + if (bufferStride != stride) { + fprintf(stderr, "bufferStride != stride: %u != %u\n", bufferStride, stride); + return; + } + uint8_t* buffer = new uint8_t[bufferStride * height]; { - uint32_t width = std::min(m_width, std::max(0, wl_shm_buffer_get_width(shmBuffer))); - uint32_t height = std::min(m_height, std::max(0, wl_shm_buffer_get_height(shmBuffer))); - uint32_t stride = std::max(0, wl_shm_buffer_get_stride(shmBuffer)); - wl_shm_buffer_begin_access(shmBuffer); auto* data = static_cast(wl_shm_buffer_get_data(shmBuffer)); - - for (uint32_t y = 0; y < height; ++y) { - for (uint32_t x = 0; x < width; ++x) { - buffer[bufferStride * y + 4 * x + 0] = data[stride * y + 4 * x + 0]; - buffer[bufferStride * y + 4 * x + 1] = data[stride * y + 4 * x + 1]; - buffer[bufferStride * y + 4 * x + 2] = data[stride * y + 4 * x + 2]; - buffer[bufferStride * y + 4 * x + 3] = data[stride * y + 4 * x + 3]; - } - } - + memcpy(buffer, data, bufferStride * height); wl_shm_buffer_end_access(shmBuffer); } @@ -173,7 +170,7 @@ void HeadlessViewBackend::updateSnapshot(struct wpe_fdo_shm_exported_buffer* exp cairo_surface_destroy(m_snapshot); m_snapshot = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_ARGB32, - m_width, m_height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_width)); + width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width)); static cairo_user_data_key_t bufferKey; cairo_surface_set_user_data(m_snapshot, &bufferKey, buffer, diff --git a/Tools/wpe/install-dependencies b/Tools/wpe/install-dependencies index 6bc2db3024aa3466200f70d20b425227215b6a43..09774119a487ffc4df80ae6f49dd4f31c4021a70 100755 --- a/Tools/wpe/install-dependencies +++ b/Tools/wpe/install-dependencies @@ -78,6 +78,7 @@ function installDependenciesWithApt { libjpeg-dev \ libkate-dev \ libfile-copy-recursive-perl \ + liblcms2-dev \ libopenjp2-7-dev \ libpng-dev \ libseccomp-dev \ @@ -87,10 +88,12 @@ function installDependenciesWithApt { libtool \ libwebp-dev \ libwoff-dev \ + libxcb-glx0-dev \ libxml2-dev \ libxslt1-dev \ ninja-build \ patch \ + patchelf \ pkg-config \ ruby \ zlib1g-dev"