diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 37aca585f67028500a828354396c9e59ccfe273d..f32c64abe10c08b44a75b4682ab2885a4d258799 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -1402,22 +1402,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-input.xcfilelist b/Source/JavaScriptCore/DerivedSources-input.xcfilelist
index 7b9566ebe6355e6cb853e59a478a17a29953e856..a8d3266e69c4700a8b5ed806f456e8d1bc3194b9 100644
--- a/Source/JavaScriptCore/DerivedSources-input.xcfilelist
+++ b/Source/JavaScriptCore/DerivedSources-input.xcfilelist
@@ -100,21 +100,26 @@ $(PROJECT_DIR)/inspector/protocol/CPUProfiler.json
 $(PROJECT_DIR)/inspector/protocol/CSS.json
 $(PROJECT_DIR)/inspector/protocol/Canvas.json
 $(PROJECT_DIR)/inspector/protocol/Console.json
+$(PROJECT_DIR)/inspector/protocol/Dialog.json
 $(PROJECT_DIR)/inspector/protocol/DOM.json
 $(PROJECT_DIR)/inspector/protocol/DOMDebugger.json
 $(PROJECT_DIR)/inspector/protocol/DOMStorage.json
 $(PROJECT_DIR)/inspector/protocol/Database.json
 $(PROJECT_DIR)/inspector/protocol/Debugger.json
+$(PROJECT_DIR)/inspector/protocol/Emulation.json
 $(PROJECT_DIR)/inspector/protocol/GenericTypes.json
 $(PROJECT_DIR)/inspector/protocol/Heap.json
 $(PROJECT_DIR)/inspector/protocol/IndexedDB.json
+$(PROJECT_DIR)/inspector/protocol/Input.json
 $(PROJECT_DIR)/inspector/protocol/Inspector.json
 $(PROJECT_DIR)/inspector/protocol/LayerTree.json
 $(PROJECT_DIR)/inspector/protocol/Memory.json
 $(PROJECT_DIR)/inspector/protocol/Network.json
 $(PROJECT_DIR)/inspector/protocol/Page.json
+$(PROJECT_DIR)/inspector/protocol/Playwright.json
 $(PROJECT_DIR)/inspector/protocol/Recording.json
 $(PROJECT_DIR)/inspector/protocol/Runtime.json
+$(PROJECT_DIR)/inspector/protocol/Screencast.json
 $(PROJECT_DIR)/inspector/protocol/ScriptProfiler.json
 $(PROJECT_DIR)/inspector/protocol/Security.json
 $(PROJECT_DIR)/inspector/protocol/ServiceWorker.json
diff --git a/Source/JavaScriptCore/DerivedSources.make b/Source/JavaScriptCore/DerivedSources.make
index 103f0b77b93558944be1770a00e1a149d7257812..a580b33ea9a7f2f74547f77c1dab4caa019dce81 100644
--- a/Source/JavaScriptCore/DerivedSources.make
+++ b/Source/JavaScriptCore/DerivedSources.make
@@ -303,22 +303,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/inspector/IdentifiersFactory.cpp b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp
index 9bc5d1fd8e2a7e576be046b3c6ae1266696cf552..610f810db1dd6865c500c0796386a8284f4178e9 100644
--- a/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp
+++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.cpp
@@ -32,14 +32,21 @@
 namespace Inspector {
 
 namespace {
+static uint64_t s_processID = 0;
 static unsigned long s_lastUsedIdentifier = 0;
 }
 
 static String addPrefixToIdentifier(unsigned long identifier)
 {
-    return makeString("0."_s, identifier);
+    return makeString(s_processID, '.', identifier);
 }
 
+void IdentifiersFactory::initializeWithProcessID(uint64_t processID) {
+    ASSERT(!s_processID);
+    s_processID = processID;
+}
+
+
 String IdentifiersFactory::createIdentifier()
 {
     return addPrefixToIdentifier(++s_lastUsedIdentifier);
diff --git a/Source/JavaScriptCore/inspector/IdentifiersFactory.h b/Source/JavaScriptCore/inspector/IdentifiersFactory.h
index 4113ddb45d4a8d08379d4dc56c44cde56162accf..e00cb9cb01a7a241f3f25b1e4cdc2fcaee92b3ac 100644
--- a/Source/JavaScriptCore/inspector/IdentifiersFactory.h
+++ b/Source/JavaScriptCore/inspector/IdentifiersFactory.h
@@ -31,6 +31,7 @@ namespace Inspector {
 
 class IdentifiersFactory {
 public:
+    JS_EXPORT_PRIVATE static void initializeWithProcessID(uint64_t);
     JS_EXPORT_PRIVATE static String createIdentifier();
     JS_EXPORT_PRIVATE static String requestId(unsigned long identifier);
 };
diff --git a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp
index 8b39848154ecab9f7daa2d21c85562a319cd06d7..c8a1f44cb4516993899ffe1404b6c3865d42433a 100644
--- a/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp
+++ b/Source/JavaScriptCore/inspector/InjectedScriptBase.cpp
@@ -85,7 +85,10 @@ static RefPtr<JSON::Value> jsToInspectorValue(JSC::JSGlobalObject* globalObject,
         JSC::PropertyNameArray propertyNames(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
         object.methodTable()->getOwnPropertyNames(&object, globalObject, propertyNames, JSC::DontEnumPropertiesMode::Exclude);
         for (auto& name : propertyNames) {
-            auto inspectorValue = jsToInspectorValue(globalObject, object.get(globalObject, name), maxDepth);
+            JSC::JSValue childValue = object.get(globalObject, name);
+            if (childValue.isUndefined())
+                continue;
+            auto inspectorValue = jsToInspectorValue(globalObject, childValue, maxDepth);
             if (!inspectorValue)
                 return nullptr;
             inspectorObject->setValue(name.string(), inspectorValue.releaseNonNull());
diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp
index 1f5d0adbf624bd24ef1e525967e6e82e8c37b4e5..4fe0f364b4ccd11774bf29f772e0a568549a4322 100644
--- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp
+++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.cpp
@@ -102,7 +102,7 @@ void BackendDispatcher::registerDispatcherForDomain(const String& domain, Supple
     m_dispatchers.set(domain, dispatcher);
 }
 
-void BackendDispatcher::dispatch(const String& message)
+void BackendDispatcher::dispatch(const String& message, Interceptor&& interceptor)
 {
     Ref<BackendDispatcher> protect(*this);
 
@@ -147,6 +147,9 @@ void BackendDispatcher::dispatch(const String& message)
         requestId = *requestIdInt;
     }
 
+    if (interceptor && interceptor(messageObject) == InterceptionResult::Intercepted)
+        return;
+
     {
         // We could be called re-entrantly from a nested run loop, so restore the previous id.
         SetForScope scopedRequestId(m_currentRequestId, requestId);
diff --git a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h
index 2eba743177c016a3415d4a5deafc552e842dd0fa..939d14be7a2703777652467f0f60e67ef1c5e0f8 100644
--- a/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h
+++ b/Source/JavaScriptCore/inspector/InspectorBackendDispatcher.h
@@ -83,8 +83,11 @@ public:
         ServerError
     };
 
+    enum class InterceptionResult { Intercepted, Continue };
+    using Interceptor = WTF::Function<InterceptionResult(const RefPtr<JSON::Object>&)>;
+
     JS_EXPORT_PRIVATE void registerDispatcherForDomain(const String& domain, SupplementalBackendDispatcher*);
-    JS_EXPORT_PRIVATE void dispatch(const String& message);
+    JS_EXPORT_PRIVATE void dispatch(const String& message, Interceptor&& interceptor = Interceptor());
 
     // Note that 'unused' is a workaround so the compiler can pick the right sendResponse based on arity.
     // When <http://webkit.org/b/179847> 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<void()>&& callback)
 {
-    ASSERT(!m_resumeCallback);
     m_resumeCallback = WTFMove(callback);
 }
 
diff --git a/Source/JavaScriptCore/inspector/InspectorTarget.h b/Source/JavaScriptCore/inspector/InspectorTarget.h
index b555c2e5a071d0a6a016061cc60755449557556d..d019346f0932296d15212c76a4a9b56beb565ff4 100644
--- a/Source/JavaScriptCore/inspector/InspectorTarget.h
+++ b/Source/JavaScriptCore/inspector/InspectorTarget.h
@@ -66,8 +66,12 @@ public:
     virtual void connect(FrontendChannel::ConnectionType) = 0;
     virtual void disconnect() = 0;
     virtual void sendMessageToTargetBackend(const String&) = 0;
+    virtual void activate(String& error) { error = "Target cannot be activated"_s; }
+    virtual void close(String& error, bool /* runBeforeUnload */) { error = "Target cannot be closed"_s; }
 
 private:
+    virtual void willResume() { }
+
     WTF::Function<void()> m_resumeCallback;
     bool m_isPaused { false };
 };
diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp
index c33e236f5228e21c6d5e0ea9bd97d07cdcb70640..7f160aec0f13e8c936aa7dea769d4e160d716452 100644
--- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp
+++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.cpp
@@ -222,6 +222,14 @@ void JSGlobalObjectConsoleClient::screenshot(JSGlobalObject*, Ref<ScriptArgument
     warnUnimplemented("console.screenshot"_s);
 }
 
+void JSGlobalObjectConsoleClient::bindingCalled(JSGlobalObject*, const String&, const String&)
+{
+    if (LIKELY(!m_consoleAgent->developerExtrasEnabled()))
+        return;
+
+    warnUnimplemented("console.bindingCalled"_s);
+}
+
 void JSGlobalObjectConsoleClient::warnUnimplemented(const String& method)
 {
     auto message = makeString(method, " is currently ignored in JavaScript context inspection."_s);
diff --git a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h
index 6bbd0729a65b4a901e7da4dc50cc47c669bd9897..452b25d0e8eba3df1d5f6623dc222048bef120cd 100644
--- a/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h
+++ b/Source/JavaScriptCore/inspector/JSGlobalObjectConsoleClient.h
@@ -64,6 +64,7 @@ private:
     void record(JSC::JSGlobalObject*, Ref<ScriptArguments>&&) final;
     void recordEnd(JSC::JSGlobalObject*, Ref<ScriptArguments>&&) final;
     void screenshot(JSC::JSGlobalObject*, Ref<ScriptArguments>&&) final;
+    void bindingCalled(JSC::JSGlobalObject*, const String&, const String&) final;
 
     void warnUnimplemented(const String& method);
     void internalAddMessage(MessageType, MessageLevel, JSC::JSGlobalObject*, Ref<ScriptArguments>&&);
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
index 0cb6efeef2430faa5dbd812f71d4abfd5f6eb9df..787ec6a5f8413c0a9dc133cb0e51ccdab58d40d0 100644
--- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
+++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.cpp
@@ -194,9 +194,8 @@ void InspectorRuntimeAgent::callFunctionOn(const Protocol::Runtime::RemoteObject
 void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const Protocol::Runtime::RemoteObjectId& objectId, const String& functionDeclaration, RefPtr<JSON::Array>&& arguments, std::optional<bool>&& doNotPauseOnExceptionsAndMuteConsole, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& /* emulateUserGesture */, std::optional<bool>&& awaitPromise, Ref<CallFunctionOnCallback>&& callback)
 {
     ASSERT(!injectedScript.hasNoValue());
-
     JSC::Debugger::TemporarilyDisableExceptionBreakpoints temporarilyDisableExceptionBreakpoints(m_debugger);
-
+    
     bool pauseAndMute = doNotPauseOnExceptionsAndMuteConsole.value_or(false);
     if (pauseAndMute) {
         temporarilyDisableExceptionBreakpoints.replace();
@@ -215,6 +214,11 @@ void InspectorRuntimeAgent::callFunctionOn(InjectedScript& injectedScript, const
         unmuteConsole();
 }
 
+Protocol::ErrorStringOr<void> InspectorRuntimeAgent::addBinding(const String&)
+{
+    return makeUnexpected("Not implemented in this type of agent."_s);
+}
+
 Protocol::ErrorStringOr<Ref<Protocol::Runtime::ObjectPreview>> InspectorRuntimeAgent::getPreview(const Protocol::Runtime::RemoteObjectId& objectId)
 {
     Protocol::ErrorString errorString;
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
index 816633a6dfc75a1248f6edb44807e5d4f602568c..687fb7dadfad9357e15a27e0869fa145c46fb39a 100644
--- a/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
+++ b/Source/JavaScriptCore/inspector/agents/InspectorRuntimeAgent.h
@@ -64,6 +64,7 @@ public:
     Protocol::ErrorStringOr<std::tuple<Ref<Protocol::Runtime::RemoteObject>, std::optional<bool> /* wasThrown */, std::optional<int> /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional<bool>&& includeCommandLineAPI, std::optional<bool>&& doNotPauseOnExceptionsAndMuteConsole, std::optional<Protocol::Runtime::ExecutionContextId>&&, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& saveResult, std::optional<bool>&& emulateUserGesture) override;
     void awaitPromise(const Protocol::Runtime::RemoteObjectId&, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& saveResult, Ref<AwaitPromiseCallback>&&) final;
     void callFunctionOn(const Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr<JSON::Array>&& arguments, std::optional<bool>&& doNotPauseOnExceptionsAndMuteConsole, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& emulateUserGesture, std::optional<bool>&& awaitPromise, Ref<CallFunctionOnCallback>&&) override;
+    Protocol::ErrorStringOr<void> addBinding(const String& name) override;
     Protocol::ErrorStringOr<void> releaseObject(const Protocol::Runtime::RemoteObjectId&) final;
     Protocol::ErrorStringOr<Ref<Protocol::Runtime::ObjectPreview>> getPreview(const Protocol::Runtime::RemoteObjectId&) final;
     Protocol::ErrorStringOr<std::tuple<Ref<JSON::ArrayOf<Protocol::Runtime::PropertyDescriptor>>, RefPtr<JSON::ArrayOf<Protocol::Runtime::InternalPropertyDescriptor>>>> getProperties(const Protocol::Runtime::RemoteObjectId&, std::optional<bool>&& ownProperties, std::optional<int>&& fetchStart, std::optional<int>&& fetchCount, std::optional<bool>&& generatePreview) final;
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp
index e47c6ca59f37fbf18ca8a393df72e0472363fabd..b393465540595220561ae00afb85408279710864 100644
--- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp
+++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.cpp
@@ -90,6 +90,34 @@ Protocol::ErrorStringOr<void> InspectorTargetAgent::sendMessageToTarget(const St
     return { };
 }
 
+Protocol::ErrorStringOr<void> 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<void> InspectorTargetAgent::close(const String& targetId,  std::optional<bool>&& runBeforeUnload)
+{
+    InspectorTarget* target = m_targets.get(targetId);
+    if (!target)
+        return makeUnexpected("Missing target for given targetId"_s);
+
+    String errorString;
+    target->close(errorString, runBeforeUnload && *runBeforeUnload);
+    if (!errorString.isEmpty())
+        return makeUnexpected(errorString);
+
+    return { };
+}
+
 void InspectorTargetAgent::sendMessageFromTargetToFrontend(const String& targetId, const String& message)
 {
     ASSERT_WITH_MESSAGE(m_targets.get(targetId), "Sending a message from an untracked target to the frontend.");
@@ -147,7 +175,17 @@ void InspectorTargetAgent::targetDestroyed(InspectorTarget& target)
     if (!m_isConnected)
         return;
 
-    m_frontendDispatcher->targetDestroyed(target.identifier());
+    m_frontendDispatcher->targetDestroyed(target.identifier(), false);
+}
+
+void InspectorTargetAgent::targetCrashed(InspectorTarget& target)
+{
+    m_targets.remove(target.identifier());
+
+    if (!m_isConnected)
+        return;
+
+    m_frontendDispatcher->targetDestroyed(target.identifier(), true);
 }
 
 void InspectorTargetAgent::didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID)
diff --git a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h
index 04377b714a6ccb5294c65d592e74350621d470ba..b6de937bfa3e6185ce29f4e432d327a3cedee6df 100644
--- a/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h
+++ b/Source/JavaScriptCore/inspector/agents/InspectorTargetAgent.h
@@ -53,8 +53,11 @@ public:
     Protocol::ErrorStringOr<void> setPauseOnStart(bool) final;
     Protocol::ErrorStringOr<void> resume(const String& targetId) final;
     Protocol::ErrorStringOr<void> sendMessageToTarget(const String& targetId, const String& message) final;
+    Protocol::ErrorStringOr<void> activate(const String& targetId) override;
+    Protocol::ErrorStringOr<void> close(const String& targetId, std::optional<bool>&& runBeforeUnload) override;
 
     // Target lifecycle.
+    void targetCrashed(InspectorTarget&);
     void targetCreated(InspectorTarget&);
     void targetDestroyed(InspectorTarget&);
     void didCommitProvisionalTarget(const String& oldTargetID, const String& committedTargetID);
@@ -62,6 +65,9 @@ public:
     // Target messages.
     void sendMessageFromTargetToFrontend(const String& targetId, const String& message);
 
+    bool shouldPauseOnStart() const { return m_shouldPauseOnStart; }
+    bool isConnected() { return m_isConnected; }
+
 private:
     // FrontendChannel
     FrontendChannel::ConnectionType connectionType() const;
diff --git a/Source/JavaScriptCore/inspector/protocol/DOM.json b/Source/JavaScriptCore/inspector/protocol/DOM.json
index 27c65fbda226f1cd5bfd68944fe87fb9b2a688a6..b036f050859ee88004a7bf6daa4bb73835360615 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",
@@ -268,6 +278,16 @@
                 { "name": "width", "type": "number" },
                 { "name": "height", "type": "number" }
             ]
+        },
+        {
+            "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": [
@@ -697,7 +717,10 @@
             "description": "Resolves JavaScript node object for given node id.",
             "targetTypes": ["page"],
             "parameters": [
-                { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to resolve." },
+                { "name": "nodeId", "$ref": "NodeId", "optional": true, "description": "Id of the node to resolve." },
+                { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "optional": true, "description": "Source element handle." },
+                { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to resolve the owner element." },
+                { "name": "executionContextId", "$ref": "Runtime.ExecutionContextId", "optional": true, "description": "Specifies in which execution context to adopt to." },
                 { "name": "objectGroup", "type": "string", "optional": true, "description": "Symbolic group name that can be used to release multiple objects." }
             ],
             "returns": [
@@ -774,6 +797,47 @@
             "returns": [
                 { "name": "mediaStats", "$ref": "MediaStats", "description": "An interleaved array of node attribute names and values." }
             ]
+        },
+        {
+            "name": "describeNode",
+            "description": "Returns node description.",
+            "parameters": [
+                { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id of the node wrapper." }
+            ],
+            "returns": [
+                { "name": "contentFrameId", "$ref": "Network.FrameId", "optional": true, "description": "Frame ID for frame owner elements." },
+                { "name": "ownerFrameId", "$ref": "Network.FrameId", "optional": true, "description": "ID of the owning frame element." }
+            ]
+        },
+        {
+          "name": "scrollIntoViewIfNeeded",
+          "description": "Scrolls the given rect into view if not already in the viewport.",
+          "parameters": [
+              { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id of the node wrapper." },
+              { "name": "rect", "$ref": "Rect", "optional": true, "description": "Rect relative to the node's border box, in CSS pixels." }
+          ]
+        },
+        {
+            "name": "getContentQuads",
+            "description": "Returns quads that describe node position on the page. This method\nmight return multiple quads for inline nodes.",
+            "parameters": [
+                { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "JavaScript object id of the node wrapper." }
+            ],
+            "returns": [
+                {
+                    "name": "quads", "type": "array", "items": { "$ref": "Quad" }, "description": "Quads that describe node layout relative to viewport."
+                }
+            ]
+        },
+        {
+            "name": "setInputFiles",
+            "description": "Sets input files for given <input type=file>",
+            "parameters": [
+                { "name": "objectId", "$ref": "Runtime.RemoteObjectId", "description": "Input element handle." },
+                { "name": "files", "type": "array", "items": { "$ref": "FilePayload" }, "optional": true, "description": "Files to set" },
+                { "name": "paths", "type": "array", "items": { "type": "string" }, "optional": true, "description": "File paths to set" }
+            ],
+            "async": true
         }
     ],
     "events": [
diff --git a/Source/JavaScriptCore/inspector/protocol/Dialog.json b/Source/JavaScriptCore/inspector/protocol/Dialog.json
new file mode 100644
index 0000000000000000000000000000000000000000..79edea03fed4e9be5da96e1275e182a479cb7a0a
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/protocol/Dialog.json
@@ -0,0 +1,36 @@
+{
+    "domain": "Dialog",
+    "description": "Actions and events related to alert boxes.",
+    "availability": ["web"],
+    "types": [
+    ],
+    "commands": [
+        {
+            "name": "enable",
+            "description": "Enables dialog domain notifications."
+        },
+        {
+            "name": "disable",
+            "description": "Disables dialog domain notifications."
+        },
+        {
+            "name": "handleJavaScriptDialog",
+            "description": "Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload).",
+            "parameters": [
+                { "name": "accept", "type": "boolean", "description": "Whether to accept or dismiss the dialog."},
+                { "name": "promptText", "optional": true, "type": "string", "description": "The text to enter into the dialog prompt before accepting. Used only if this is a prompt dialog."}
+            ]
+        }
+    ],
+    "events": [
+        {
+            "name": "javascriptDialogOpening",
+            "description": "Fired when a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload) is about to open.",
+            "parameters": [
+                { "name": "type", "type": "string", "description": "Dialog type."},
+                { "name": "message", "type": "string", "description": "Message that will be displayed by the dialog."},
+                { "name": "defaultPrompt", "optional": true, "type": "string", "description": "Default dialog prompt."}
+            ]
+        }
+    ]
+}
diff --git a/Source/JavaScriptCore/inspector/protocol/Emulation.json b/Source/JavaScriptCore/inspector/protocol/Emulation.json
new file mode 100644
index 0000000000000000000000000000000000000000..8377901cb3ad75c29532a1f0f547efb53558a327
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/protocol/Emulation.json
@@ -0,0 +1,59 @@
+{
+    "domain": "Emulation",
+    "availability": ["web"],
+    "commands": [
+        {
+            "name": "setDeviceMetricsOverride",
+            "description": "Overrides device metrics with provided values.",
+            "async": true,
+            "parameters": [
+                { "name": "width", "type": "integer" },
+                { "name": "height", "type": "integer" },
+                { "name": "fixedLayout", "type": "boolean" },
+                { "name": "deviceScaleFactor", "type": "number", "optional": true }
+            ]
+        },
+        {
+            "name": "setJavaScriptEnabled",
+            "description": "Allows to disable script execution for the page.",
+            "parameters": [
+                { "name": "enabled", "type": "boolean" }
+            ]
+        },
+        {
+            "name": "setAuthCredentials",
+            "description": "Credentials to use during HTTP authentication.",
+            "parameters": [
+                { "name": "username", "type": "string", "optional": true },
+                { "name": "password", "type": "string", "optional": true },
+                { "name": "origin", "type": "string", "optional": true }
+            ]
+        },
+        {
+            "name": "setActiveAndFocused",
+            "description": "Makes page focused for test.",
+            "parameters": [
+                { "name": "active", "type": "boolean", "optional": true }
+            ]
+        },
+        {
+            "name": "grantPermissions",
+            "parameters": [
+                { "name": "origin", "type": "string" },
+                { "name": "permissions", "type": "array", "items": { "type": "string" } }
+            ],
+            "description": "Overrides the permissions."
+        },
+        {
+            "name": "resetPermissions",
+            "description": "Clears permission overrides."
+        },
+        {
+            "name": "setOrientationOverride",
+            "description": "Overrides window.orientation with provided value.",
+            "parameters": [
+                { "name": "angle", "type": "integer", "optional": true }
+            ]
+        }
+    ]
+}
diff --git a/Source/JavaScriptCore/inspector/protocol/Input.json b/Source/JavaScriptCore/inspector/protocol/Input.json
new file mode 100644
index 0000000000000000000000000000000000000000..1c43b476603325fa412bcfded9163e7a00aebbfa
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/protocol/Input.json
@@ -0,0 +1,264 @@
+{
+    "domain": "Input",
+    "availability": ["web"],
+    "types": [
+        {
+            "id": "TimeSinceEpoch",
+            "description": "UTC time in seconds, counted from January 1, 1970.",
+            "type": "number"
+        },
+        {
+            "id": "TouchPoint",
+            "type": "object",
+            "description": "Touch point.",
+            "properties": [
+                { "name": "x", "type": "integer", "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels." },
+                { "name": "y", "type": "integer", "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels." },
+                { "name": "id", "type": "integer", "description": "Identifier used to track touch sources between events, must be unique within an event." }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "dispatchKeyEvent",
+            "description": "Dispatches a key event to the page.",
+            "async": true,
+            "parameters": [
+                {
+                    "name": "type",
+                    "description": "Type of the key event.",
+                    "type": "string",
+                    "enum": [
+                        "keyDown",
+                        "keyUp"
+                    ]
+                },
+                {
+                    "name": "modifiers",
+                    "description": "Bit field representing pressed modifier keys. (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "text",
+                    "description": "Text as generated by processing a virtual key code with a keyboard layout. Not needed for\nfor `keyUp` and `rawKeyDown` events (default: \"\")",
+                    "optional": true,
+                    "type": "string"
+                },
+                {
+                    "name": "unmodifiedText",
+                    "description": "Text that would have been generated by the keyboard if no modifiers were pressed (except for\nshift). Useful for shortcut (accelerator) key handling (default: \"\").",
+                    "optional": true,
+                    "type": "string"
+                },
+                {
+                    "name": "code",
+                    "description": "Unique DOM defined string value for each physical key (e.g., 'KeyA') (default: \"\").",
+                    "optional": true,
+                    "type": "string"
+                },
+                {
+                    "name": "key",
+                    "description": "Unique DOM defined string value describing the meaning of the key in the context of active\nmodifiers, keyboard layout, etc (e.g., 'AltGr') (default: \"\").",
+                    "optional": true,
+                    "type": "string"
+                },
+                {
+                    "name": "windowsVirtualKeyCode",
+                    "description": "Windows virtual key code (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "nativeVirtualKeyCode",
+                    "description": "Native virtual key code (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "autoRepeat",
+                    "description": "Whether the event was generated from auto repeat (default: false).",
+                    "optional": true,
+                    "type": "boolean"
+                },
+                {
+                    "name": "isKeypad",
+                    "description": "Whether the event was generated from the keypad (default: false).",
+                    "optional": true,
+                    "type": "boolean"
+                },
+                {
+                    "name": "isSystemKey",
+                    "description": "Whether the event was a system key event (default: false).",
+                    "optional": true,
+                    "type": "boolean"
+                },
+                {
+                    "name": "macCommands",
+                    "description": "Mac editing commands associated with this key",
+                    "type": "array",
+                    "optional": true,
+                    "items": {
+                      "type": "string"
+                    }
+                }
+            ]
+        },
+        {
+            "name": "dispatchMouseEvent",
+            "description": "Dispatches a mouse event to the page.",
+            "async": true,
+            "parameters": [
+                {
+                    "name": "type",
+                    "description": "Type of the mouse event.",
+                    "type": "string",
+                    "enum": [ "move", "down", "up", "wheel"]
+                },
+                {
+                    "name": "x",
+                    "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels.",
+                    "type": "integer"
+                },
+                {
+                    "name": "y",
+                    "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to\nthe top of the viewport and Y increases as it proceeds towards the bottom of the viewport.",
+                    "type": "integer"
+                },
+                {
+                    "name": "modifiers",
+                    "description": "Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8\n(default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "button",
+                    "description": "Mouse button (default: \"none\").",
+                    "optional": true,
+                    "type": "string",
+                    "enum": [
+                        "none",
+                        "left",
+                        "middle",
+                        "right",
+                        "back",
+                        "forward"
+                    ]
+                },
+                {
+                    "name": "buttons",
+                    "description": "A number indicating which buttons are pressed on the mouse when a mouse event is triggered.\nLeft=1, Right=2, Middle=4, Back=8, Forward=16, None=0.",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "clickCount",
+                    "description": "Number of times the mouse button was clicked (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "deltaX",
+                    "description": "X delta in CSS pixels for mouse wheel event (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "deltaY",
+                    "description": "Y delta in CSS pixels for mouse wheel event (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                }
+            ]
+        },
+        {
+            "name": "dispatchWheelEvent",
+            "description": "Dispatches a wheel event to the page.",
+            "async": true,
+            "parameters": [
+                {
+                    "name": "x",
+                    "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels.",
+                    "type": "integer"
+                },
+                {
+                    "name": "y",
+                    "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to\nthe top of the viewport and Y increases as it proceeds towards the bottom of the viewport.",
+                    "type": "integer"
+                },
+                {
+                    "name": "modifiers",
+                    "description": "Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8\n(default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "deltaX",
+                    "description": "X delta in CSS pixels for mouse wheel event (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "deltaY",
+                    "description": "Y delta in CSS pixels for mouse wheel event (default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                }
+            ]
+        },
+        {
+            "name": "dispatchTapEvent",
+            "description": "Dispatches a tap event to the page.",
+            "async": true,
+            "parameters": [
+                {
+                    "name": "x",
+                    "description": "X coordinate of the event relative to the main frame's viewport in CSS pixels.",
+                    "type": "integer"
+                },
+                {
+                    "name": "y",
+                    "description": "Y coordinate of the event relative to the main frame's viewport in CSS pixels. 0 refers to\nthe top of the viewport and Y increases as it proceeds towards the bottom of the viewport.",
+                    "type": "integer"
+                },
+                {
+                    "name": "modifiers",
+                    "description": "Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8\n(default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                }
+            ]
+        },
+        {
+            "name": "dispatchTouchEvent",
+            "description": "Dispatches a touch event to the page.",
+            "async": true,
+            "parameters": [
+                {
+                    "name": "type",
+                    "description": "Type of the touch event.",
+                    "type": "string",
+                    "enum": [
+                        "touchStart",
+                        "touchMove",
+                        "touchEnd",
+                        "touchCancel"
+                    ]
+                },
+                {
+                    "name": "modifiers",
+                    "description": "Bit field representing pressed modifier keys. Alt=1, Ctrl=2, Meta/Command=4, Shift=8\n(default: 0).",
+                    "optional": true,
+                    "type": "integer"
+                },
+                {
+                    "name": "touchPoints",
+                    "description": "List of touch points",
+                    "type": "array",
+                    "optional": true,
+                    "items": { "$ref": "TouchPoint" }
+                }
+            ]
+        }
+    ]
+}
diff --git a/Source/JavaScriptCore/inspector/protocol/Network.json b/Source/JavaScriptCore/inspector/protocol/Network.json
index 96af27ece2ac200e11c4311b3ca0d9d3b5a048da..3168f7806fcbdabec07acc5e304bae1e3736240a 100644
--- a/Source/JavaScriptCore/inspector/protocol/Network.json
+++ b/Source/JavaScriptCore/inspector/protocol/Network.json
@@ -352,6 +352,13 @@
             "parameters": [
                 { "name": "bytesPerSecondLimit", "type": "integer", "optional": true, "description": "Limits the bytes per second of requests if positive. Removes any limits if zero or not provided." }
             ]
+        },
+        {
+            "name": "setEmulateOfflineState",
+            "description": "Emulate offline state overriding the actual state.",
+            "parameters": [
+                { "name": "offline", "type": "boolean", "description": "True to emulate offline." }
+            ]
         }
     ],
     "events": [
diff --git a/Source/JavaScriptCore/inspector/protocol/Page.json b/Source/JavaScriptCore/inspector/protocol/Page.json
index b5e2bb2eb58765ec20392b36bf5ef1ac35857a69..c14ec5652c0e9d311d94947e38a9e0da701046ef 100644
--- a/Source/JavaScriptCore/inspector/protocol/Page.json
+++ b/Source/JavaScriptCore/inspector/protocol/Page.json
@@ -20,7 +20,15 @@
                 "ScriptEnabled",
                 "ShowDebugBorders",
                 "ShowRepaintCounter",
-                "WebSecurityEnabled"
+                "WebSecurityEnabled",
+                "DeviceOrientationEventEnabled",
+                "SpeechRecognitionEnabled",
+                "PointerLockEnabled",
+                "NotificationsEnabled",
+                "FullScreenEnabled",
+                "InputTypeMonthEnabled",
+                "InputTypeWeekEnabled",
+                "FixedBackgroundsPaintRelativeToDocument"
             ]
         },
         {
@@ -62,6 +70,12 @@
             "enum": ["None", "Lax", "Strict"],
             "description": "Same-Site policy of a cookie."
         },
+        {
+            "id": "ForcedColors",
+            "type": "string",
+            "enum": ["Active", "None"],
+            "description": "Page forced-colors media query override."
+        },
         {
             "id": "Frame",
             "type": "object",
@@ -125,6 +139,50 @@
                 { "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": "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": [
@@ -144,6 +202,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.",
@@ -160,6 +226,14 @@
                 { "name": "value", "type": "string", "optional": true, "description": "Value to override the user agent with. If this value is not provided, the override is removed. Overrides are removed when Web Inspector closes/disconnects." }
             ]
         },
+        {
+            "name": "overridePlatform",
+            "description": "Override's the navigator.platform of the inspected page",
+            "targetTypes": ["page"],
+            "parameters": [
+                { "name": "value", "type": "string", "optional": true, "description": "Value to override the platform with. If this value is not provided, the override is removed. Overrides are removed when Web Inspector closes/disconnects." }
+            ]
+        },
         {
             "name": "overrideSetting",
             "description": "Allows the frontend to override the inspected page's settings.",
@@ -283,6 +357,28 @@
                 { "name": "media", "type": "string", "description": "Media type to emulate. Empty string disables the override." }
             ]
         },
+        {
+            "name": "setForcedColors",
+            "description": "Forces the forced-colors media query for the page.",
+            "targetTypes": ["page"],
+            "parameters": [
+                { "name": "forcedColors", "$ref": "ForcedColors", "optional": true }
+            ]
+        },
+        {
+            "name": "setTimeZone",
+            "description": "Enables time zone emulation.",
+            "parameters": [
+                { "name": "timeZone", "type": "string", "optional": true }
+            ]
+        },
+        {
+            "name": "setTouchEmulationEnabled",
+            "description": "Enables touch events on platforms that lack them.",
+            "parameters": [
+                {"name": "enabled", "type": "boolean", "description": "Whether touch should be enabled."}
+            ]
+        },
         {
             "name": "snapshotNode",
             "description": "Capture a snapshot of the specified node that does not include unrelated layers.",
@@ -303,7 +399,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)." }
@@ -321,12 +418,64 @@
         {
             "name": "setScreenSizeOverride",
             "description": "Overrides screen size exposed to DOM and used in media queries for testing with provided values.",
-            "condition": "!(defined(WTF_PLATFORM_COCOA) && WTF_PLATFORM_COCOA)",
             "targetTypes": ["page"],
             "parameters": [
                 { "name": "width", "type": "integer", "description": "Screen width", "optional": true },
                 { "name": "height", "type": "integer", "description": "Screen height", "optional": true }
             ]
+        },
+        {
+            "name": "insertText",
+            "description": "Insert text into the current selection of the page.",
+            "parameters": [
+                { "name": "text", "type": "string", "description": "Text to insert." }
+            ]
+        },
+        {
+            "name": "accessibilitySnapshot",
+            "description": "Serializes and returns all of the accessibility nodes of the page.",
+            "parameters": [
+                { "name": "objectId", "type": "string", "optional": true, "description": "Object Id of a node to find in the accessibility tree."}
+            ],
+            "returns": [
+                { "name": "axNode", "$ref": "AXNode", "description": "The root AXNode."}
+            ]
+        },
+        {
+            "name": "setInterceptFileChooserDialog",
+            "description": "Intercepts file chooser dialog",
+            "parameters": [
+                { "name": "enabled", "type": "boolean", "description": "True to enable." }
+            ]
+        },
+        {
+            "name": "setDefaultBackgroundColorOverride",
+            "description": "Sets or clears an override of the default background color of the frame. This override is used if the content does not specify one.",
+            "parameters": [
+                { "name": "color", "$ref": "DOM.RGBAColor", "optional": true, "description": "RGBA of the default background color. If not specified, any existing override will be cleared." }
+            ]
+        },
+        {
+            "name": "createUserWorld",
+            "description": "Creates an user world for every loaded frame.",
+            "parameters": [
+                { "name": "name", "type": "string", "description": "Isolated world name, will be used as an execution context name." }
+            ]
+        },
+        {
+            "name": "setBypassCSP",
+            "description": "Enable page Content Security Policy by-passing.",
+            "parameters": [
+                { "name": "enabled", "type": "boolean", "description": "Whether to bypass page CSP." }
+            ]
+        },
+        {
+            "name": "crash",
+            "description": "Crashes the page process"
+        },
+        {
+            "name": "updateScrollingState",
+            "description": "Ensures that the scroll regions are up to date."
         }
     ],
     "events": [
@@ -334,14 +483,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." }
             ]
         },
         {
@@ -351,6 +502,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.",
@@ -379,7 +538,8 @@
             "targetTypes": ["page"],
             "parameters": [
                 { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has scheduled a navigation." },
-                { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." }
+                { "name": "delay", "type": "number", "description": "Delay (in seconds) until the navigation is scheduled to begin. The navigation is not guaranteed to start." },
+                { "name": "targetIsCurrentFrame", "type": "boolean", "description": "Whether the naviation will happen in the same frame." }
             ]
         },
         {
@@ -390,6 +550,22 @@
                 { "name": "frameId", "$ref": "Network.FrameId", "description": "Id of the frame that has cleared its scheduled navigation." }
             ]
         },
+        {
+            "name": "navigatedWithinDocument",
+            "description": "Fired when same-document navigation happens, e.g. due to history API usage or anchor navigation.",
+            "parameters": [
+                {
+                    "name": "frameId",
+                    "description": "Id of the frame.",
+                    "$ref": "Network.FrameId"
+                },
+                {
+                    "name": "url",
+                    "description": "Frame's new url.",
+                    "type": "string"
+                }
+            ]
+        },
         {
             "name": "defaultUserPreferencesDidChange",
             "description": "Fired when the default value of a user preference changes at the system level.",
@@ -397,6 +573,42 @@
             "parameters": [
                 { "name": "preferences", "type": "array", "items": { "$ref": "UserPreference" }, "description": "List of user preferences that can be overriden and their new system (default) values." }
             ]
+        },
+        {
+            "name": "willCheckNavigationPolicy",
+            "description": "Fired when page is about to check policy for newly triggered navigation.",
+            "parameters": [
+                {
+                    "name": "frameId",
+                    "description": "Id of the frame.",
+                    "$ref": "Network.FrameId"
+                }
+            ]
+          },
+          {
+            "name": "didCheckNavigationPolicy",
+            "description": "Fired when page has received navigation policy decision.",
+            "parameters": [
+                {
+                    "name": "frameId",
+                    "description": "Id of the frame.",
+                    "$ref": "Network.FrameId"
+                },
+                {
+                    "name": "cancel",
+                    "description": "True if the navigation will not continue in this frame.",
+                    "type": "boolean",
+                    "optional": true
+                }
+            ]
+          },
+          {
+            "name": "fileChooserOpened",
+            "description": "Fired when the page shows file chooser for it's <input type=file>.",
+            "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..978d6f92b18498633c982969299f068332eb2884
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/protocol/Playwright.json
@@ -0,0 +1,307 @@
+{
+    "domain": "Playwright",
+    "availability": ["web"],
+    "types": [
+        {
+            "id": "ContextID",
+            "type": "string",
+            "description": "Id of Browser context."
+        },
+        {
+            "id": "PageProxyID",
+            "type": "string",
+            "description": "Id of WebPageProxy."
+        },
+        {
+            "id": "CookieSameSitePolicy",
+            "type": "string",
+            "enum": ["None", "Lax", "Strict"],
+            "description": "Same-Site policy of a cookie."
+        },
+        {
+            "id": "Cookie",
+            "type": "object",
+            "description": "Cookie object",
+            "properties": [
+                { "name": "name", "type": "string", "description": "Cookie name." },
+                { "name": "value", "type": "string", "description": "Cookie value." },
+                { "name": "domain", "type": "string", "description": "Cookie domain." },
+                { "name": "path", "type": "string", "description": "Cookie path." },
+                { "name": "expires", "type": "number", "description": "Cookie expires." },
+                { "name": "httpOnly", "type": "boolean", "description": "True if cookie is http-only." },
+                { "name": "secure", "type": "boolean", "description": "True if cookie is secure." },
+                { "name": "session", "type": "boolean", "description": "True if cookie is session cookie." },
+                { "name": "sameSite", "$ref": "CookieSameSitePolicy", "description": "Cookie Same-Site policy." }
+            ]
+        },
+        {
+            "id": "SetCookieParam",
+            "type": "object",
+            "description": "Cookie object",
+            "properties": [
+                { "name": "name", "type": "string", "description": "Cookie name." },
+                { "name": "value", "type": "string", "description": "Cookie value." },
+                { "name": "domain", "type": "string", "description": "Cookie domain." },
+                { "name": "path", "type": "string", "description": "Cookie path." },
+                { "name": "expires", "type": "number", "optional": true, "description": "Cookie expires." },
+                { "name": "httpOnly", "type": "boolean", "optional": true, "description": "True if cookie is http-only." },
+                { "name": "secure", "type": "boolean", "optional": true, "description": "True if cookie is secure." },
+                { "name": "session", "type": "boolean", "optional": true, "description": "True if cookie is session cookie." },
+                { "name": "sameSite", "$ref": "CookieSameSitePolicy", "optional": true, "description": "Cookie Same-Site policy." }
+            ]
+        },
+        {
+            "id": "NameValue",
+            "type": "object",
+            "description": "Name-value pair",
+            "properties": [
+                { "name": "name", "type": "string" },
+                { "name": "value", "type": "string" }
+            ]
+        },
+        {
+            "id": "OriginStorage",
+            "type": "object",
+            "description": "Origin object",
+            "properties": [
+                { "name": "origin", "type": "string", "description": "Origin." },
+                { "name": "items", "type": "array", "items": { "$ref": "NameValue" }, "description": "Storage entries." }
+            ]
+        },
+        {
+            "id": "Geolocation",
+            "type": "object",
+            "description": "Geolocation",
+            "properties": [
+                { "name": "timestamp", "type": "number", "description": "Mock latitude" },
+                { "name": "latitude", "type": "number", "description": "Mock latitude" },
+                { "name": "longitude", "type": "number", "description": "Mock longitude" },
+                { "name": "accuracy", "type": "number", "description": "Mock accuracy" }
+            ]
+        }
+    ],
+    "commands": [
+        {
+            "name": "enable"
+        },
+        {
+            "name": "disable"
+        },
+        {
+            "name": "getInfo",
+            "returns": [
+                { "name": "os", "type": "string", "description": "Name of the operating system where the browser is running (macOS, Linux or Windows)." }
+            ]
+        },
+        {
+            "name": "close",
+            "async": true,
+            "description": "Close browser."
+        },
+        {
+            "name": "createContext",
+            "description": "Creates new ephemeral browser context.",
+            "parameters": [
+                { "name": "proxyServer", "type": "string", "optional": true, "description": "Proxy server, similar to the one passed to --proxy-server" },
+                { "name": "proxyBypassList", "type": "string", "optional": true, "description": "Proxy bypass list, similar to the one passed to --proxy-bypass-list" }
+            ],
+            "returns": [
+                { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." }
+            ]
+        },
+        {
+            "name": "deleteContext",
+            "async": true,
+            "description": "Deletes browser context previously created with createContect. The command will automatically close all pages that use the context.",
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "description": "Identifier of the context to delete." }
+            ]
+        },
+        {
+            "name": "createPage",
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." }
+            ],
+            "returns": [
+                { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." }
+            ]
+        },
+        {
+            "name": "navigate",
+            "async": true,
+            "description": "Navigates current page to the given URL.",
+            "parameters": [
+                { "name": "url", "type": "string", "description": "URL to navigate the page to." },
+                { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." },
+                { "name": "frameId", "$ref": "Network.FrameId", "optional": true, "description": "Id of the frame to navigate."},
+                { "name": "referrer", "type": "string", "optional": true, "description": "Referrer URL." }
+            ],
+            "returns": [
+                { "name": "loaderId", "$ref": "Network.LoaderId", "optional": true, "description": "Identifier of the loader associated with the navigation." }
+            ]
+        },
+        {
+            "name": "grantFileReadAccess",
+            "description": "Grants read access for the specified files to the web process of the page.",
+            "parameters": [
+                { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." },
+                { "name": "paths", "type": "array", "items": { "type": "string" }, "description": "Id of the frame to navigate."}
+            ]
+        },
+        {
+            "name": "takePageScreenshot",
+            "description": "Capture a snapshot of the page.",
+            "async": true,
+            "parameters": [
+                { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." },
+                { "name": "x", "type": "integer", "description": "X coordinate" },
+                { "name": "y", "type": "integer", "description": "Y coordinate" },
+                { "name": "width", "type": "integer", "description": "Rectangle width" },
+                { "name": "height", "type": "integer", "description": "Rectangle height" },
+                { "name": "omitDeviceScaleFactor", "type": "boolean", "optional": true, "description": "By default, screenshot is inflated by device scale factor to avoid blurry image. This flag disables it." }
+            ],
+            "returns": [
+                { "name": "dataURL", "type": "string", "description": "Base64-encoded image data (PNG)." }
+            ]
+        },
+        {
+            "name": "setIgnoreCertificateErrors",
+            "description": "Change whether all certificate errors should be ignored.",
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." },
+                { "name": "ignore", "type": "boolean" }
+            ]
+        },
+        {
+            "name": "getAllCookies",
+            "description": "Returns all cookies in the given browser context.",
+            "async": true,
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }
+            ],
+            "returns": [
+                { "name": "cookies", "type": "array", "items": { "$ref": "Cookie" }, "description": "Cookies." }
+            ]
+        },
+        {
+            "name": "setCookies",
+            "description": "Sets cookies in the given browser context.",
+            "async": true,
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." },
+                { "name": "cookies", "type": "array", "items": { "$ref": "SetCookieParam" }, "description": "Cookies." }
+            ]
+        },
+        {
+            "name": "deleteAllCookies",
+            "description": "Deletes cookies in the given browser context.",
+            "async": true,
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }
+            ]
+        },
+        {
+            "name": "setGeolocationOverride",
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." },
+                { "name": "geolocation", "$ref": "Geolocation", "optional": true, "description": "Geolocation to set, if missing emulates position unavailable." }
+            ],
+            "description": "Overrides the geolocation position or error."
+        },
+        {
+            "name": "setLanguages",
+            "description": "Allows to set locale language for context.",
+            "parameters": [
+                { "name": "languages", "type": "array", "items": { "type": "string" } },
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }
+            ]
+        },
+        {
+            "name": "setDownloadBehavior",
+            "description": "Allows to override download behavior.",
+            "parameters": [
+                { "name": "behavior", "optional": true, "type": "string", "enum": ["allow", "deny"] },
+                { "name": "downloadPath", "optional": true, "type": "string" },
+                { "name": "browserContextId", "$ref": "ContextID", "optional": true, "description": "Browser context id." }
+            ]
+        },
+        {
+            "name": "cancelDownload",
+            "parameters": [
+                { "name": "uuid", "type": "string" }
+            ],
+            "description": "Cancels a current running download."
+        },
+        {
+            "name": "clearMemoryCache",
+            "description": "Clears browser memory cache.",
+            "async": true,
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "optional": false, "description": "Browser context id." }
+            ]
+        }
+    ],
+    "events": [
+        {
+            "name": "pageProxyCreated",
+            "parameters": [
+                { "name": "browserContextId", "$ref": "ContextID", "description": "Unique identifier of the context." },
+                { "name": "pageProxyId", "$ref": "PageProxyID" },
+                { "name": "openerId", "$ref": "PageProxyID", "optional": true, "description": "Unique identifier of the opening page. Only set for pages created by window.open()." }
+            ]
+        },
+        {
+            "name": "pageProxyDestroyed",
+            "parameters": [
+                { "name": "pageProxyId", "$ref": "PageProxyID" }
+            ]
+        },
+        {
+            "name": "provisionalLoadFailed",
+            "description": "Fired when provisional load fails.",
+            "parameters": [
+                { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." },
+                { "name": "loaderId", "$ref": "Network.LoaderId", "description": "Identifier of the loader associated with the navigation." },
+                { "name": "error", "type": "string", "description": "Localized error string." }
+            ]
+        },
+        {
+          "name": "windowOpen",
+          "description": "Fired when page opens a new window.",
+          "parameters": [
+              { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." },
+              { "name": "url", "type": "string" },
+              { "name": "windowFeatures", "type": "array", "items": { "type": "string" } }
+          ]
+        },
+        {
+            "name": "downloadCreated",
+            "parameters": [
+                { "name": "pageProxyId", "$ref": "PageProxyID", "description": "Unique identifier of the page proxy." },
+                { "name": "frameId", "$ref": "Network.FrameId", "description": "Unique identifier of the originating frame." },
+                { "name": "uuid", "type": "string" },
+                { "name": "url", "type": "string" }
+            ]
+        },
+        {
+            "name": "downloadFilenameSuggested",
+            "parameters": [
+                { "name": "uuid", "type": "string" },
+                { "name": "suggestedFilename", "type": "string" }
+            ]
+        },
+        {
+            "name": "downloadFinished",
+            "parameters": [
+                { "name": "uuid", "type": "string" },
+                { "name": "error", "type": "string" }
+            ]
+        },
+        {
+            "name": "screencastFinished",
+            "parameters": [
+                { "name": "screencastId", "$ref": "Screencast.ScreencastId", "description": "Unique identifier of the screencast." }
+            ]
+        }
+    ]
+}
diff --git a/Source/JavaScriptCore/inspector/protocol/Runtime.json b/Source/JavaScriptCore/inspector/protocol/Runtime.json
index 301b88eb1607b0975c3fa81d91045eb5403378ec..0e2ae5d96b3cdcc20ecc95ddc7b49538dcb3c302 100644
--- a/Source/JavaScriptCore/inspector/protocol/Runtime.json
+++ b/Source/JavaScriptCore/inspector/protocol/Runtime.json
@@ -272,6 +272,13 @@
             ],
             "async": true
         },
+        {
+          "name": "addBinding",
+          "description": "Adds binding with the given name on the global objects of all inspected contexts. Each binding function call produces Runtime.bindingCalled event.",
+          "parameters": [
+              { "name": "name", "type": "string", "description": "Name of the bound function." }
+          ]
+        },
         {
             "name": "getPreview",
             "description": "Returns a preview for the given object.",
@@ -408,6 +415,15 @@
             "parameters": [
                 { "name": "context", "$ref": "ExecutionContextDescription", "description": "A newly created execution context." }
             ]
-        }
+        },
+        {
+          "name": "bindingCalled",
+          "description": "Issued when new execution context is created.",
+          "parameters": [
+              { "name": "contextId", "$ref": "ExecutionContextId", "description": "Id of the execution context where the binding was called." },
+              { "name": "name", "type": "string", "description": "Name of the bound function." },
+              { "name": "argument", "type": "string", "description": "String argument passed to the function." }
+          ]
+      }
     ]
 }
diff --git a/Source/JavaScriptCore/inspector/protocol/Screencast.json b/Source/JavaScriptCore/inspector/protocol/Screencast.json
new file mode 100644
index 0000000000000000000000000000000000000000..73a4e53ced3acc41316bb8d4c787306d3f28a27e
--- /dev/null
+++ b/Source/JavaScriptCore/inspector/protocol/Screencast.json
@@ -0,0 +1,64 @@
+{
+    "domain": "Screencast",
+    "availability": ["web"],
+    "types": [
+        {
+            "id": "ScreencastId",
+            "type": "string",
+            "description": "Unique identifier of the screencast."
+        }
+    ],
+    "commands": [
+        {
+            "name": "startVideo",
+            "description": "Starts recoring video to speified file.",
+            "parameters": [
+                { "name": "file", "type": "string", "description": "Output file location." },
+                { "name": "width", "type": "integer" },
+                { "name": "height", "type": "integer" },
+                { "name": "toolbarHeight", "type": "integer" }
+            ],
+            "returns": [
+                { "name": "screencastId", "$ref": "ScreencastId", "description": "Unique identifier of the screencast." }
+            ]
+        },
+        {
+            "name": "stopVideo",
+            "async": true,
+            "description": "Stops recoding video. Returns after the file has been closed."
+        },
+        {
+            "name": "startScreencast",
+            "description": "Starts screencast.",
+            "parameters": [
+                { "name": "width", "type": "integer" },
+                { "name": "height", "type": "integer" },
+                { "name": "toolbarHeight", "type": "integer" },
+                { "name": "quality", "type": "integer" }
+            ],
+            "returns": [
+                { "name": "generation", "type": "integer", "description": "Screencast session generation." }
+            ]
+        },
+        {
+            "name": "stopScreencast",
+            "description": "Stops screencast."
+        },
+        {
+            "name": "screencastFrameAck",
+            "parameters": [
+                { "name": "generation", "type": "integer", "description": "Screencast session generation" }
+            ]
+        }
+    ],
+    "events": [
+        {
+            "name": "screencastFrame",
+            "parameters": [
+                { "name": "data", "type": "string", "description": "Base64 data" },
+                { "name": "deviceWidth", "type": "integer" },
+                { "name": "deviceHeight", "type": "integer" }
+            ]
+        }
+    ]
+}
diff --git a/Source/JavaScriptCore/inspector/protocol/Target.json b/Source/JavaScriptCore/inspector/protocol/Target.json
index 52920cded24a9c6b0ef6fb4e518664955db4f9fa..bbbabc4e7259088b9404e8cc07eecd6f45077da0 100644
--- a/Source/JavaScriptCore/inspector/protocol/Target.json
+++ b/Source/JavaScriptCore/inspector/protocol/Target.json
@@ -10,7 +10,7 @@
             "properties": [
                 { "name": "targetId", "type": "string", "description": "Unique identifier for the target." },
                 { "name": "type", "type": "string", "enum": ["page", "service-worker", "worker"] },
-                { "name": "isProvisional", "type": "boolean", "optional": true, "description": "Whether this is a provisional page target." },
+                { "name": "isProvisional", "type": "boolean", "optional": true, "description": "True value indicates that this is a provisional page target i.e. Such target may be created when current page starts cross-origin navigation. Eventually each provisional target is either committed and swaps with the current target or gets destroyed, e.g. in case of load request failure." },
                 { "name": "isPaused", "type": "boolean", "optional": true, "description": "Whether the target is paused on start and has to be explicitely resumed by inspector." }
             ]
         }
@@ -37,6 +37,21 @@
                 { "name": "targetId", "type": "string" },
                 { "name": "message", "type": "string", "description": "JSON Inspector Protocol message (command) to be dispatched on the backend." }
             ]
+        },
+        {
+            "name": "activate",
+            "description": "Reveals the target on screen.",
+            "parameters": [
+                { "name": "targetId", "type": "string" }
+            ]
+        },
+        {
+            "name": "close",
+            "description": "Closes the target.",
+            "parameters": [
+                { "name": "targetId", "type": "string" },
+                { "name": "runBeforeUnload", "type": "boolean", "optional": true }
+            ]
         }
     ],
     "events": [
@@ -49,7 +64,8 @@
         {
             "name": "targetDestroyed",
             "parameters": [
-                { "name": "targetId", "type": "string" }
+                { "name": "targetId", "type": "string" },
+                { "name": "crashed", "type": "boolean" }
             ]
         },
         {
diff --git a/Source/JavaScriptCore/runtime/ConsoleClient.h b/Source/JavaScriptCore/runtime/ConsoleClient.h
index 24891ad836086fd23024fcb4d08ca63f6974c812..29f4b6b1923383fec7a99d28a4e815dc4536d160 100644
--- a/Source/JavaScriptCore/runtime/ConsoleClient.h
+++ b/Source/JavaScriptCore/runtime/ConsoleClient.h
@@ -78,6 +78,7 @@ public:
     virtual void record(JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) = 0;
     virtual void recordEnd(JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) = 0;
     virtual void screenshot(JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) = 0;
+    virtual void bindingCalled(JSGlobalObject*, const String& name, const String& arg) = 0;
 
 private:
     enum ArgumentRequirement { ArgumentRequired, ArgumentNotRequired };
diff --git a/Source/ThirdParty/libwebrtc/CMakeLists.txt b/Source/ThirdParty/libwebrtc/CMakeLists.txt
index 347f61b918ee705f510c9e28d49acc5b3aac1f3c..b1718ebbdd3157938895b281497642de08216bbd 100644
--- a/Source/ThirdParty/libwebrtc/CMakeLists.txt
+++ b/Source/ThirdParty/libwebrtc/CMakeLists.txt
@@ -5,6 +5,8 @@ file(MAKE_DIRECTORY ${libwebrtc_DERIVED_SOURCES_DIR})
 
 enable_language(ASM)
 
+add_definitions(-DLIBYUV_DISABLE_SVE)
+
 if (NOT APPLE)
     find_package(LibVpx 1.10.0)
     if (NOT LIBVPX_FOUND)
@@ -601,6 +603,11 @@ set(webrtc_SOURCES
     Source/third_party/crc32c/src/src/crc32c.cc
     Source/third_party/crc32c/src/src/crc32c_portable.cc
     Source/third_party/crc32c/src/src/crc32c_sse42.cc
+# Playwright begin
+    Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc
+    Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc
+    Source/third_party/libwebm/mkvmuxer/mkvwriter.cc
+# Playwright end
     Source/third_party/libyuv/source/compare.cc
     Source/third_party/libyuv/source/compare_common.cc
     Source/third_party/libyuv/source/compare_gcc.cc
@@ -2476,6 +2483,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/Base-libwebrtc.xcconfig b/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig
index 0c5c8e689bdddec766f9de5bffd4444a5e068d77..330dd1f585e530722178c65c883641a2b8c0f1bd 100644
--- a/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig
+++ b/Source/ThirdParty/libwebrtc/Configurations/Base-libwebrtc.xcconfig
@@ -24,6 +24,8 @@
 HEADER_SEARCH_PATHS = Source Source/third_party/libsrtp/crypto/include Source/third_party/libsrtp/include Source/third_party/boringssl/src/include Source/third_party/libyuv/include Source/webrtc/webkit_sdk/objc/Framework/Headers Source/webrtc/common_audio/signal_processing/include Source/webrtc/modules/audio_coding/codecs/isac/main/include Source/third_party/opus/src/celt Source/third_party/opus/src/include Source/third_party/opus/src/src Source/webrtc/modules/audio_device/mac Source/webrtc/modules/audio_device/ios Source/webrtc Source/webrtc/webkit_sdk/objc Source/webrtc/webkit_sdk/objc/base Source/webrtc/webkit_sdk/objc/Framework/Classes Source/third_party/libsrtp/config Source/webrtc/webkit_sdk/objc/Framework/Classes/Common Source/webrtc/webkit_sdk/objc/Framework/Classes/Video Source/webrtc/webkit_sdk/objc/Framework/Classes/PeerConnection Source/third_party/abseil-cpp Source/third_party/libvpx/source/libvpx Source/third_party/libwebm/webm_parser/include Source/third_party/crc32c/config Source/third_party/crc32c/include Source/third_party/crc32c/src/include Source/third_party/libaom/source/libaom;
 USE_HEADERMAP = NO;
 
+HEADER_SEARCH_PATHS = ${HEADER_SEARCH_PATHS} Source/third_party/libwebm/mkvmuxer Source/third_party/libvpx/source/libvpx/third_party/libwebm;
+
 WARNING_CFLAGS = -Wno-deprecated-declarations $(inherited);
 
 // FIXME: Set WEBRTC_USE_BUILTIN_ISAC_FIX and WEBRTC_USE_BUILTIN_ISAC_FLOAT for iOS and Mac
diff --git a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp
index c6fb5ee1c32a896cd247d339ce5471b0c0628a89..e234adaff73a7302aa8847f32ad1fec545b087b1 100644
--- a/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp
+++ b/Source/ThirdParty/libwebrtc/Configurations/libwebrtc.exp
@@ -421,3 +421,16 @@ __ZNK8mkvmuxer7Segment16GetTrackByNumberEy
 __ZN8mkvmuxer6Tracks11kAv1CodecIdE
 __ZN8mkvmuxer6Tracks11kVp8CodecIdE
 __ZN8mkvmuxer6Tracks11kVp9CodecIdE
+__ZN8mkvmuxer11SegmentInfo4InitEv
+__ZN8mkvmuxer9MkvWriterC1EP7__sFILE
+_ARGBToI420
+_vpx_codec_destroy
+_vpx_codec_enc_config_default
+_vpx_codec_enc_init_ver
+_vpx_codec_encode
+_vpx_codec_err_to_string
+_vpx_codec_error
+_vpx_codec_get_cx_data
+_vpx_codec_iface_name
+_vpx_codec_version_str
+_vpx_codec_vp8_cx
diff --git a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj
index 10f3107c5688e799c6466a1e74f834637b39d2b2..ac3ce66727fb6de865fe1df7b94ed1debba56212 100644
--- a/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj
+++ b/Source/ThirdParty/libwebrtc/libwebrtc.xcodeproj/project.pbxproj
@@ -35,6 +35,20 @@
 		};
 /* End PBXAggregateTarget section */
 
+/* Begin PBXAggregateTarget section */
+		F31720AC27FE215900EEE407 /* Copy libvpx headers */ = {
+			isa = PBXAggregateTarget;
+			buildConfigurationList = F31720B027FE215900EEE407 /* Build configuration list for PBXAggregateTarget "Copy libvpx headers" */;
+			buildPhases = (
+				F31720B127FE216400EEE407 /* ShellScript */,
+			);
+			dependencies = (
+			);
+			name = "Copy libvpx headers";
+			productName = "Copy libvpx headers";
+		};
+/* End PBXAggregateTarget section */
+
 /* Begin PBXBuildFile section */
 		2D6BFF60280A93DF00A1A74F /* video_coding.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45B234C81710028A615 /* video_coding.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		2D6BFF61280A93EC00A1A74F /* video_codec_initializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4131C45E234C81720028A615 /* video_codec_initializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -5653,6 +5667,13 @@
 			remoteGlobalIDString = DDF30D0527C5C003006A526F;
 			remoteInfo = absl;
 		};
+		F31720B327FE273100EEE407 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = FB39D0701200ED9200088E69 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = F31720AC27FE215900EEE407;
+			remoteInfo = "Copy libvpx headers";
+		};
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -23816,6 +23837,7 @@
 			);
 			dependencies = (
 				410B3827292B73E90003E515 /* PBXTargetDependency */,
+				F31720B427FE273100EEE407 /* PBXTargetDependency */,
 				DD2E76E827C6B69A00F2A74C /* PBXTargetDependency */,
 				CDEBB4CC24C01AB400ADBD44 /* PBXTargetDependency */,
 				411ED040212E0811004320BA /* PBXTargetDependency */,
@@ -23898,6 +23920,7 @@
 				4460B8B92B155B6A00392062 /* vp9_qp_parser_fuzzer */,
 				444A6EF02AEADFC9005FE121 /* vp9_replay_fuzzer */,
 				44945C512B9BA1C300447FFD /* webm_fuzzer */,
+				F31720AC27FE215900EEE407 /* Copy libvpx headers */,
 			);
 		};
 /* End PBXProject section */
@@ -24001,6 +24024,23 @@
 			shellPath = /bin/sh;
 			shellScript = "[ -z \"${WK_DERIVED_SDK_HEADERS_DIR}\" -o -d \"${WK_DERIVED_SDK_HEADERS_DIR}\" ] && touch \"${SCRIPT_OUTPUT_FILE_0}\"\n";
 		};
+		F31720B127FE216400EEE407 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+			);
+			outputFileListPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "PRIVATE_HEADERS_FOLDER_PATH=usr/local/include\n\nif [[ \"${DEPLOYMENT_LOCATION}\" == \"NO\" ]]; then\n    PRIVATE_HEADERS_PATH=\"${TARGET_BUILD_DIR%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nelse\n    PRIVATE_HEADERS_PATH=\"${DSTROOT}${INSTALL_PATH_PREFIX%/}/${PRIVATE_HEADERS_FOLDER_PATH}\"\nfi;\n\necho \"#### PRIVATE_HEADERS_PATH = ${PRIVATE_HEADERS_PATH}\"\necho\n\nmkdir -p \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libyuv/include/\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --exclude \"src\" --exclude \"internal\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libvpx/source/libvpx/vpx\" \"${PRIVATE_HEADERS_PATH}\"\n\nrsync -av --no-owner --no-group --prune-empty-dirs --exclude \".svn\" --exclude \"usr\" --include \"*/\" --include \"*.h\" --exclude \"*\" \"${SRCROOT}/Source/third_party/libwebm/\" \"${PRIVATE_HEADERS_PATH}\"\n\n";
+		};
 /* End PBXShellScriptBuildPhase section */
 
 /* Begin PBXSourcesBuildPhase section */
@@ -26864,6 +26904,11 @@
 			target = DDF30D0527C5C003006A526F /* absl */;
 			targetProxy = DD2E76E727C6B69A00F2A74C /* PBXContainerItemProxy */;
 		};
+		F31720B427FE273100EEE407 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = F31720AC27FE215900EEE407 /* Copy libvpx headers */;
+			targetProxy = F31720B327FE273100EEE407 /* PBXContainerItemProxy */;
+		};
 /* End PBXTargetDependency section */
 
 /* Begin XCBuildConfiguration section */
@@ -27439,6 +27484,27 @@
 			};
 			name = Production;
 		};
+		F31720AD27FE215900EEE407 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		F31720AE27FE215900EEE407 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+		F31720AF27FE215900EEE407 /* Production */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Production;
+		};
 		FB39D0711200ED9200088E69 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			baseConfigurationReference = 5D7C59C71208C68B001C873E /* DebugRelease.xcconfig */;
@@ -27741,6 +27807,16 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Production;
 		};
+		F31720B027FE215900EEE407 /* Build configuration list for PBXAggregateTarget "Copy libvpx headers" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				F31720AD27FE215900EEE407 /* Debug */,
+				F31720AE27FE215900EEE407 /* Release */,
+				F31720AF27FE215900EEE407 /* Production */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Production;
+		};
 		FB39D0731200ED9200088E69 /* Build configuration list for PBXProject "libwebrtc" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (
diff --git a/Source/ThirdParty/skia/CMakeLists.txt b/Source/ThirdParty/skia/CMakeLists.txt
index 2f20123e16626a3a1b76534ea4c0c38522228e06..3ab6fa2fe2a297e98597985903ba7ba735d6d436 100644
--- a/Source/ThirdParty/skia/CMakeLists.txt
+++ b/Source/ThirdParty/skia/CMakeLists.txt
@@ -5,6 +5,7 @@ if (NOT WIN32)
     find_package(Freetype 2.9.0 REQUIRED)
     find_package(Fontconfig 2.13.0 REQUIRED)
 endif ()
+find_package(Threads REQUIRED)
 find_package(WebP REQUIRED COMPONENTS mux)
 
 if (ANDROID)
@@ -950,6 +951,7 @@ endif ()
 target_link_libraries(Skia PRIVATE
     JPEG::JPEG
     PNG::PNG
+    Threads::Threads
     WebP::mux
 )
 
diff --git a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
index 97c903534c16864727f7ea5528ab56bfa5b3104a..fd0f0232df11883c9627ed71950f438ea007b480 100644
--- a/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
+++ b/Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml
@@ -613,6 +613,7 @@ ApplePayEnabled:
   richJavaScript: true
 
 # FIXME: This is on by default in WebKit2 PLATFORM(COCOA). Perhaps we should consider turning it on for WebKitLegacy as well.
+# Playwright: enable on all platforms to align with Safari.
 AsyncClipboardAPIEnabled:
   type: bool
   status: mature
@@ -623,7 +624,7 @@ AsyncClipboardAPIEnabled:
       default: false
     WebKit:
       "PLATFORM(COCOA) || PLATFORM(GTK)" : true
-      default: false
+      default: true
     WebCore:
       default: false
 
@@ -868,13 +869,10 @@ BlobFileAccessEnforcementEnabled:
   sharedPreferenceForWebProcess: true
   defaultValue:
     WebKitLegacy:
-      "PLATFORM(COCOA)": true
       default: false
     WebKit:
-      "PLATFORM(COCOA)": true
       default: false
     WebCore:
-      "PLATFORM(COCOA)": true
       default: false
 
 BlobRegistryTopOriginPartitioningEnabled:
@@ -2194,6 +2192,7 @@ CrossOriginEmbedderPolicyEnabled:
     WebCore:
       default: false
 
+# Playwright: disable setting.
 CrossOriginOpenerPolicyEnabled:
   type: bool
   status: stable
@@ -2234,7 +2233,7 @@ CustomPasteboardDataEnabled:
     WebKitLegacy:
       default: false
     WebKit:
-      "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WIN)": true
+      "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true
       default: false
 
 DNSPrefetchingEnabled:
@@ -2279,6 +2278,7 @@ DOMAudioSessionFullEnabled:
     WebCore:
       default: false
 
+# Playwright: enable on all platforms to align with Safari.
 DOMPasteAccessRequestsEnabled:
   type: bool
   status: internal
@@ -2290,7 +2290,7 @@ DOMPasteAccessRequestsEnabled:
       default: false
     WebKit:
       "PLATFORM(IOS) || PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(VISION)": true
-      default: false
+      default: true
     WebCore:
       default: false
 
@@ -2639,7 +2639,7 @@ DirectoryUploadEnabled:
     WebKitLegacy:
       default: false
     WebKit:
-      "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)": true
+      "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)": true
       default: false
     WebCore:
       default: false
@@ -3103,10 +3103,10 @@ FullScreenEnabled:
     WebKitLegacy:
       default: false
     WebKit:
-      "PLATFORM(GTK) || PLATFORM(WPE)": true
+      "PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(WPE)": true
       default: false
     WebCore:
-      "PLATFORM(GTK) || PLATFORM(WPE)": true
+      "PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(WPE)": true
       default: false
   sharedPreferenceForWebProcess: true
 
@@ -3795,6 +3795,7 @@ InspectorAttachmentSide:
     WebKit:
       default: 0
 
+# Playwright: disable setting.
 InspectorStartsAttached:
   type: bool
   status: embedder
@@ -3802,7 +3803,7 @@ InspectorStartsAttached:
   exposed: [ WebKit ]
   defaultValue:
     WebKit:
-      default: true
+      default: false
 
 InspectorWindowFrame:
   type: String
@@ -4153,9 +4154,10 @@ LayoutViewportHeightExpansionFactor:
     WebCore:
       default: 0
 
+# Playwright: disable setting.
 LazyIframeLoadingEnabled:
   type: bool
-  status: stable
+  status: preview
   category: html
   humanReadableName: "Lazy iframe loading"
   humanReadableDescription: "Enable lazy iframe loading support"
@@ -4163,9 +4165,9 @@ LazyIframeLoadingEnabled:
     WebKitLegacy:
       default: true
     WebKit:
-      default: true
+      default: false
     WebCore:
-      default: true
+      default: false
 
 LazyImageLoadingEnabled:
   type: bool
@@ -5695,7 +5697,7 @@ PermissionsAPIEnabled:
     WebKitLegacy:
       default: false
     WebKit:
-      "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)" : true
+      "PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)" : true
       default: false
     WebCore:
       default: false
@@ -5758,6 +5760,19 @@ PitchCorrectionAlgorithm:
     WebCore:
       default: MediaPlayerEnums::PitchCorrectionAlgorithm::BestAllAround
 
+# Playwright: add preference 'PointerLockEnabled'.
+PointerLockEnabled:
+  type: bool
+  status: embedder
+  condition: ENABLE(POINTER_LOCK)
+  defaultValue:
+    WebKitLegacy:
+      default: true
+    WebKit:
+      default: true
+    WebCore:
+      default: true
+
 PointerLockOptionsEnabled:
   type: bool
   status: stable
@@ -6308,7 +6323,7 @@ ScreenOrientationAPIEnabled:
     WebKitLegacy:
       default: false
     WebKit:
-      default: WebKit::defaultShouldEnableScreenOrientationAPI()
+      default: true
     WebCore:
       default: false
   sharedPreferenceForWebProcess: true
@@ -7704,6 +7719,7 @@ UseCGDisplayListsForDOMRendering:
       default: true
   sharedPreferenceForWebProcess: true
 
+# Playwright: force-disable on Windows.
 UseGPUProcessForCanvasRenderingEnabled:
   type: bool
   status: stable
@@ -7716,7 +7732,7 @@ UseGPUProcessForCanvasRenderingEnabled:
   defaultValue:
     WebKit:
       "ENABLE(GPU_PROCESS_BY_DEFAULT)": true
-      "USE(GRAPHICS_LAYER_WC)": true
+      "USE(GRAPHICS_LAYER_WC)": false
       default: false
 
 UseGPUProcessForDOMRenderingEnabled:
@@ -7759,6 +7775,7 @@ UseGPUProcessForMediaEnabled:
       "ENABLE(GPU_PROCESS_BY_DEFAULT)": true
       default: false
 
+# Playwright: force-disable on Windows.
 UseGPUProcessForWebGLEnabled:
   type: bool
   status: internal
@@ -7770,7 +7787,7 @@ UseGPUProcessForWebGLEnabled:
       default: false
     WebKit:
       "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true
-      "USE(GRAPHICS_LAYER_WC)": true
+      "USE(GRAPHICS_LAYER_WC)": false
       default: false
     WebCore:
       "ENABLE(GPU_PROCESS_BY_DEFAULT) && ENABLE(GPU_PROCESS_WEBGL_BY_DEFAULT)": true
diff --git a/Source/WTF/wtf/PlatformEnable.h b/Source/WTF/wtf/PlatformEnable.h
index 05707f446c2ad5a709f78fd7950a3c099f5f02e2..dae9ff949061a18cd149d63fe937c1cbfc302f4e 100644
--- a/Source/WTF/wtf/PlatformEnable.h
+++ b/Source/WTF/wtf/PlatformEnable.h
@@ -409,7 +409,7 @@
 
 // ORIENTATION_EVENTS should never get enabled on Desktop, only Mobile.
 #if !defined(ENABLE_ORIENTATION_EVENTS)
-#define ENABLE_ORIENTATION_EVENTS 0
+#define ENABLE_ORIENTATION_EVENTS 1
 #endif
 
 #if !defined(ENABLE_OVERFLOW_SCROLLING_TOUCH)
@@ -514,7 +514,7 @@
 #endif
 
 #if !defined(ENABLE_TOUCH_EVENTS)
-#define ENABLE_TOUCH_EVENTS 0
+#define ENABLE_TOUCH_EVENTS 1
 #endif
 
 #if !defined(ENABLE_TOUCH_ACTION_REGIONS)
diff --git a/Source/WTF/wtf/PlatformEnableCocoa.h b/Source/WTF/wtf/PlatformEnableCocoa.h
index 93435c6b18c4abb7934ac880a6bbb86b05a33756..b81515175fd55e4460a5ef398f9d3af28aeb70e6 100644
--- a/Source/WTF/wtf/PlatformEnableCocoa.h
+++ b/Source/WTF/wtf/PlatformEnableCocoa.h
@@ -802,7 +802,7 @@
 #endif
 
 #if !defined(ENABLE_SEC_ITEM_SHIM)
-#define ENABLE_SEC_ITEM_SHIM 1
+#define ENABLE_SEC_ITEM_SHIM 0
 #endif
 
 #if !defined(ENABLE_SERVER_PRECONNECT)
diff --git a/Source/WTF/wtf/PlatformHave.h b/Source/WTF/wtf/PlatformHave.h
index 1779062c715c2232d13bb8c8e21dd82d932817df..8e35f41126a904460b812cdcef9350f224cc40ce 100644
--- a/Source/WTF/wtf/PlatformHave.h
+++ b/Source/WTF/wtf/PlatformHave.h
@@ -433,7 +433,7 @@
 #define HAVE_FOUNDATION_WITH_SAME_SITE_COOKIE_SUPPORT 1
 #endif
 
-#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(HAIKU) || PLATFORM(WPE)
+#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(HAIKU) || PLATFORM(WPE) || PLATFORM(WIN)
 #define HAVE_OS_DARK_MODE_SUPPORT 1
 #endif
 
@@ -1234,7 +1234,8 @@
 #endif
 
 #if PLATFORM(MAC)
-#define HAVE_GPU_AVAILABILITY_CHECK 1
+// Playwright: disable the check to make WebGL always work.
+#define HAVE_GPU_AVAILABILITY_CHECK 0
 #endif
 
 #if !defined(HAVE_LOCKDOWN_MODE_PDF_ADDITIONS) && \
diff --git a/Source/WTF/wtf/unicode/UTF8Conversion.h b/Source/WTF/wtf/unicode/UTF8Conversion.h
index 007b8fe3292f326504013be8198ae020f7aacf35..1c722c473732ffe05fdb61010fa4417e3e399d1f 100644
--- a/Source/WTF/wtf/unicode/UTF8Conversion.h
+++ b/Source/WTF/wtf/unicode/UTF8Conversion.h
@@ -27,6 +27,11 @@
 
 #include <wtf/text/LChar.h>
 
+// Can be probably removed when we drop Debian 11.
+#ifdef Success
+#undef Success
+#endif
+
 namespace WTF {
 namespace Unicode {
 
diff --git a/Source/WebCore/DerivedSources.make b/Source/WebCore/DerivedSources.make
index f3c5f1acd4bcc6b51fa2175ac1f786280023d24b..041585f28cf7a38d4261b27b5e9be5e3b8cc65fc 100644
--- a/Source/WebCore/DerivedSources.make
+++ b/Source/WebCore/DerivedSources.make
@@ -1220,6 +1220,10 @@ JS_BINDING_IDLS := \
     $(WebCore)/dom/SubscriberCallback.idl \
     $(WebCore)/dom/SubscriptionObserver.idl \
     $(WebCore)/dom/SubscriptionObserverCallback.idl \
+    $(WebCore)/dom/Document+Touch.idl \
+    $(WebCore)/dom/Touch.idl \
+    $(WebCore)/dom/TouchEvent.idl \
+    $(WebCore)/dom/TouchList.idl \
     $(WebCore)/dom/Text.idl \
     $(WebCore)/dom/TextDecoder.idl \
     $(WebCore)/dom/TextDecoderStream.idl \
@@ -1814,9 +1818,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 90bf15adb6a36e190f68448a125b5446a0674631..d64af222f0c824a7cd719e250c1023071465d24e 100644
--- a/Source/WebCore/Modules/geolocation/Geolocation.cpp
+++ b/Source/WebCore/Modules/geolocation/Geolocation.cpp
@@ -360,8 +360,9 @@ bool Geolocation::shouldBlockGeolocationRequests()
     bool isSecure = SecurityOrigin::isSecure(document->url()) || document->isSecureContext();
     bool hasMixedContent = !document->foundMixedContent().isEmpty();
     bool isLocalOrigin = securityOrigin()->isLocal();
+    bool isPotentiallyTrustworthy = securityOrigin()->isPotentiallyTrustworthy();
     if (document->canAccessResource(ScriptExecutionContext::ResourceType::Geolocation) != ScriptExecutionContext::HasResourceAccess::No) {
-        if (isLocalOrigin || (isSecure && !hasMixedContent))
+        if (isLocalOrigin || (isSecure && !hasMixedContent) || isPotentiallyTrustworthy)
             return false;
     }
 
diff --git a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm
index b2b0391c120d527a9ab4bc6daf8bff7ea5d03cf7..d490a95f89f21536fce4f403b86399160abefc23 100644
--- a/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm
+++ b/Source/WebCore/Modules/speech/cocoa/WebSpeechRecognizerTask.mm
@@ -195,6 +195,7 @@ - (void)sendEndIfNeeded
 
 - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available
 {
+    UNUSED_PARAM(speechRecognizer);
     ASSERT(isMainThread());
 
     if (available || !_task)
@@ -208,6 +209,7 @@ - (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidC
 
 - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription
 {
+    UNUSED_PARAM(task);
     ASSERT(isMainThread());
 
     [self sendSpeechStartIfNeeded];
@@ -216,6 +218,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTran
 
 - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult
 {
+    UNUSED_PARAM(task);
     ASSERT(isMainThread());
 
     if (task.state == SFSpeechRecognitionTaskStateCanceling || (!_doMultipleRecognitions && task.state == SFSpeechRecognitionTaskStateCompleted))
@@ -229,6 +232,7 @@ - (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecogniti
 
 - (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task
 {
+    UNUSED_PARAM(task);
     ASSERT(isMainThread());
 
     [self sendSpeechEndIfNeeded];
diff --git a/Source/WebCore/PlatformWPE.cmake b/Source/WebCore/PlatformWPE.cmake
index 9a7c34a144f55c4d333ebd6f5e86aa9fcec3f9f4..8c55646049ac55cd8dc483ce75bbb12030ef7c68 100644
--- a/Source/WebCore/PlatformWPE.cmake
+++ b/Source/WebCore/PlatformWPE.cmake
@@ -60,6 +60,8 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/graphics/gbm/PlatformDisplayGBM.h
 
     platform/graphics/libwpe/PlatformDisplayLibWPE.h
+
+    platform/wpe/SelectionData.h
 )
 
 set(CSS_VALUE_PLATFORM_DEFINES "HAVE_OS_DARK_MODE_SUPPORT=1")
diff --git a/Source/WebCore/SourcesCocoa.txt b/Source/WebCore/SourcesCocoa.txt
index c22eb8b9b958976182c3ce078035f3f6238bb297..fcf83f02fdff9b91143d264a2e72ac2062125541 100644
--- a/Source/WebCore/SourcesCocoa.txt
+++ b/Source/WebCore/SourcesCocoa.txt
@@ -721,3 +721,9 @@ testing/cocoa/WebViewVisualIdentificationOverlay.mm
 platform/graphics/angle/GraphicsContextGLANGLE.cpp @no-unify
 platform/graphics/cocoa/GraphicsContextGLCocoa.mm @no-unify
 platform/graphics/cv/GraphicsContextGLCVCocoa.mm @no-unify
+
+// Playwright begin
+JSTouch.cpp
+JSTouchEvent.cpp
+JSTouchList.cpp
+// Playwright end
diff --git a/Source/WebCore/SourcesGTK.txt b/Source/WebCore/SourcesGTK.txt
index cafba5ad19fcce8184f9caeaf50445b3b2065522..75fa95a4f8248ad2d19c2c19dc22166a843f03bb 100644
--- a/Source/WebCore/SourcesGTK.txt
+++ b/Source/WebCore/SourcesGTK.txt
@@ -112,3 +112,10 @@ platform/unix/LoggingUnix.cpp
 platform/unix/SharedMemoryUnix.cpp
 
 platform/xdg/MIMETypeRegistryXdg.cpp
+
+// Playwright: begin.
+JSSpeechSynthesisErrorCode.cpp
+JSSpeechSynthesisErrorEvent.cpp
+JSSpeechSynthesisErrorEventInit.cpp
+JSSpeechSynthesisEventInit.cpp
+// Playwright: end.
diff --git a/Source/WebCore/SourcesWPE.txt b/Source/WebCore/SourcesWPE.txt
index 3c68a8ed10cd24cffd26b4b70c3adad8eb6ba91f..b36dee714fdceba5248922bfb6d2046922ca6b34 100644
--- a/Source/WebCore/SourcesWPE.txt
+++ b/Source/WebCore/SourcesWPE.txt
@@ -46,6 +46,8 @@ editing/libwpe/EditorLibWPE.cpp
 
 loader/soup/ResourceLoaderSoup.cpp
 
+page/wpe/DragControllerWPE.cpp
+
 page/linux/ResourceUsageOverlayLinux.cpp
 page/linux/ResourceUsageThreadLinux.cpp
 
@@ -90,6 +92,17 @@ platform/text/LocaleICU.cpp
 platform/unix/LoggingUnix.cpp
 platform/unix/SharedMemoryUnix.cpp
 
+platform/wpe/DragDataWPE.cpp
+platform/wpe/DragImageWPE.cpp
 platform/wpe/PlatformScreenWPE.cpp
 
 platform/xdg/MIMETypeRegistryXdg.cpp
+
+// Playwright: begin.
+platform/wpe/SelectionData.cpp
+
+JSSpeechSynthesisErrorCode.cpp
+JSSpeechSynthesisErrorEvent.cpp
+JSSpeechSynthesisErrorEventInit.cpp
+JSSpeechSynthesisEventInit.cpp
+// Playwright: end.
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index a30a792bb3990e024a09567fa5f21631858fb58d..55746a752863d94b440e8b401309dd69484af2c0 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -6329,6 +6329,13 @@
 		EDEC98030AED7E170059137F /* WebCorePrefix.h in Headers */ = {isa = PBXBuildFile; fileRef = EDEC98020AED7E170059137F /* WebCorePrefix.h */; };
 		EE0C7E042CE845CB0043DAF8 /* CSSPositionTryRule.h in Headers */ = {isa = PBXBuildFile; fileRef = EE0C7E002CE845CB0043DAF8 /* CSSPositionTryRule.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 */; };
+		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, ); }; };
@@ -20816,6 +20823,14 @@
 		EE7A169F2C607BFA0057B563 /* StartViewTransitionOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StartViewTransitionOptions.h; sourceTree = "<group>"; };
 		EFB7287B2124C73D005C2558 /* CanvasActivityRecord.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CanvasActivityRecord.cpp; sourceTree = "<group>"; };
 		EFCC6C8D20FE914000A2321B /* CanvasActivityRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CanvasActivityRecord.h; sourceTree = "<group>"; };
+		F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformTouchEvent.h; sourceTree = "<group>"; };
+		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 = "<group>"; };
+		F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformTouchPoint.h; sourceTree = "<group>"; };
 		F12171F316A8BC63000053CA /* WebVTTElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebVTTElement.cpp; sourceTree = "<group>"; };
 		F12171F416A8BC63000053CA /* WebVTTElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebVTTElement.h; sourceTree = "<group>"; };
 		F32BDCD52363AAC90073B6AE /* UserGestureEmulationScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserGestureEmulationScope.cpp; sourceTree = "<group>"; };
@@ -28555,6 +28570,11 @@
 				BC4A5324256055590028C592 /* TextDirectionSubmenuInclusionBehavior.h */,
 				2D4F96F11A1ECC240098BF88 /* TextIndicator.cpp */,
 				2D4F96F21A1ECC240098BF88 /* TextIndicator.h */,
+				F050E16923AD660C0011CE47 /* Touch.cpp */,
+				F050E16F23AD669E0011CE47 /* TouchEvent.cpp */,
+				F050E17023AD669F0011CE47 /* TouchEvent.h */,
+				F050E16C23AD66630011CE47 /* TouchList.cpp */,
+				F050E16B23AD66620011CE47 /* TouchList.h */,
 				F48570A42644C76D00C05F71 /* TranslationContextMenuInfo.h */,
 				F4E1965F21F26E4E00285078 /* UndoItem.cpp */,
 				2ECDBAD521D8906300F00ECD /* UndoItem.h */,
@@ -35368,6 +35388,8 @@
 				29E4D8DF16B0940F00C84704 /* PlatformSpeechSynthesizer.h */,
 				1AD8F81A11CAB9E900E93E54 /* PlatformStrategies.cpp */,
 				1AD8F81911CAB9E900E93E54 /* PlatformStrategies.h */,
+				F050E16623AC9C070011CE47 /* PlatformTouchEvent.h */,
+				F050E17623AD70C40011CE47 /* PlatformTouchPoint.h */,
 				0FD7C21D23CE41E30096D102 /* PlatformWheelEvent.cpp */,
 				935C476A09AC4D4F00A6AAB4 /* PlatformWheelEvent.h */,
 				F491A66A2A9FEFA300F96146 /* PlatformWheelEvent.serialization.in */,
@@ -38149,6 +38171,7 @@
 				AD6E71AB1668899D00320C13 /* DocumentSharedObjectPool.h */,
 				6BDB5DC1227BD3B800919770 /* DocumentStorageAccess.cpp */,
 				6BDB5DC0227BD3B800919770 /* DocumentStorageAccess.h */,
+				F050E17323AD6A800011CE47 /* DocumentTouch.cpp */,
 				7CE7FA5B1EF882300060C9D6 /* DocumentTouch.cpp */,
 				7CE7FA591EF882300060C9D6 /* DocumentTouch.h */,
 				A8185F3209765765005826D9 /* DocumentType.cpp */,
@@ -43001,6 +43024,8 @@
 				F4E90A3C2B52038E002DA469 /* PlatformTextAlternatives.h in Headers */,
 				0F7D07331884C56C00B4AF86 /* PlatformTextTrack.h in Headers */,
 				074E82BB18A69F0E007EF54C /* PlatformTimeRanges.h in Headers */,
+				F050E16823AC9C080011CE47 /* PlatformTouchEvent.h in Headers */,
+				F050E17823AD70C50011CE47 /* PlatformTouchPoint.h in Headers */,
 				CDD08ABD277E542600EA3755 /* PlatformTrackConfiguration.h in Headers */,
 				CD1F9B022700323D00617EB6 /* PlatformVideoColorPrimaries.h in Headers */,
 				CD1F9B01270020B700617EB6 /* PlatformVideoColorSpace.h in Headers */,
@@ -44322,6 +44347,7 @@
 				0F54DD081881D5F5003EEDBB /* Touch.h in Headers */,
 				71B7EE0D21B5C6870031C1EF /* TouchAction.h in Headers */,
 				0F54DD091881D5F5003EEDBB /* TouchEvent.h in Headers */,
+				F050E16D23AD66630011CE47 /* TouchList.h in Headers */,
 				0F54DD0A1881D5F5003EEDBB /* TouchList.h in Headers */,
 				070334D71459FFD5008D8D45 /* TrackBase.h in Headers */,
 				BE88E0C21715CE2600658D98 /* TrackListBase.h in Headers */,
@@ -45498,6 +45524,8 @@
 				2D22830323A8470700364B7E /* CursorMac.mm in Sources */,
 				5CBD59592280E926002B22AA /* CustomHeaderFields.cpp in Sources */,
 				07E4BDBF2A3A5FAB000D5509 /* DictationCaretAnimator.cpp in Sources */,
+				F050E17423AD6A800011CE47 /* DocumentTouch.cpp in Sources */,
+				329C0C2528BD96EB00F187D2 /* ElementName.cpp in Sources */,
 				7CE6CBFD187F394900D46BF5 /* FormatConverter.cpp in Sources */,
 				4667EA3E2968D9DA00BAB1E2 /* GameControllerHapticEffect.mm in Sources */,
 				46FE73D32968E52000B8064C /* GameControllerHapticEngines.mm in Sources */,
@@ -45587,6 +45615,9 @@
 				CE88EE262414467B007F29C2 /* TextAlternativeWithRange.mm in Sources */,
 				BE39137129B267F500FA5D4F /* TextTransformCocoa.cpp in Sources */,
 				51DF6D800B92A18E00C2DC85 /* ThreadCheck.mm in Sources */,
+				F050E16A23AD660C0011CE47 /* Touch.cpp in Sources */,
+				F050E17123AD669F0011CE47 /* TouchEvent.cpp in Sources */,
+				F050E16E23AD66630011CE47 /* TouchList.cpp in Sources */,
 				538EC8031F96AF81004D22A8 /* UnifiedSource1-mm.mm in Sources */,
 				538EC8021F96AF81004D22A8 /* UnifiedSource1.cpp in Sources */,
 				538EC8051F96AF81004D22A8 /* UnifiedSource2-mm.mm in Sources */,
diff --git a/Source/WebCore/accessibility/AccessibilityObject.cpp b/Source/WebCore/accessibility/AccessibilityObject.cpp
index 8d5aae2faffe469a44fdeee680b0a608487eb750..9389e0f7a372120cea95d95ee74ad59ff0810f62 100644
--- a/Source/WebCore/accessibility/AccessibilityObject.cpp
+++ b/Source/WebCore/accessibility/AccessibilityObject.cpp
@@ -70,6 +70,7 @@
 #include "HTMLTableSectionElement.h"
 #include "HTMLTextAreaElement.h"
 #include "HitTestResult.h"
+#include "InspectorInstrumentation.h"
 #include "LocalFrame.h"
 #include "LocalizedStrings.h"
 #include "MathMLNames.h"
@@ -4039,7 +4040,12 @@ AccessibilityObjectInclusion AccessibilityObject::defaultObjectInclusion() const
     if (roleValue() == AccessibilityRole::ApplicationDialog)
         return AccessibilityObjectInclusion::IncludeObject;
 
-    return accessibilityPlatformIncludesObject();
+    AccessibilityObjectInclusion platformBehavior = accessibilityPlatformIncludesObject();
+    if (platformBehavior != AccessibilityObjectInclusion::DefaultBehavior) {
+        if (auto* page = this->page())
+            InspectorInstrumentation::maybeOverrideDefaultObjectInclusion(*page, platformBehavior);
+    }
+    return platformBehavior;
 }
 
 bool AccessibilityObject::isWithinHiddenWebArea() const
diff --git a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h
index 73946c90c05b0df97746d1e0b67b29274176f081..4bb2265f523ee4fb21ddda22819420ccdb9b154c 100644
--- a/Source/WebCore/bindings/js/WebCoreBuiltinNames.h
+++ b/Source/WebCore/bindings/js/WebCoreBuiltinNames.h
@@ -186,6 +186,8 @@ namespace WebCore {
     macro(DelayNode) \
     macro(DeprecationReportBody) \
     macro(DigitalCredential) \
+    macro(DeviceMotionEvent) \
+    macro(DeviceOrientationEvent) \
     macro(DocumentTimeline) \
     macro(DynamicsCompressorNode) \
     macro(ElementInternals) \
diff --git a/Source/WebCore/css/query/MediaQueryFeatures.cpp b/Source/WebCore/css/query/MediaQueryFeatures.cpp
index db901b29c12a0d49a5898d05421a813a627b8dc0..1ea6b452ecce001e3d3729a2c86c47fa9174b562 100644
--- a/Source/WebCore/css/query/MediaQueryFeatures.cpp
+++ b/Source/WebCore/css/query/MediaQueryFeatures.cpp
@@ -364,7 +364,11 @@ const FeatureSchema& forcedColors()
     static MainThreadNeverDestroyed<IdentifierSchema> schema {
         "forced-colors"_s,
         FixedVector { CSSValueNone, CSSValueActive },
-        [](auto&) {
+        [](auto& context) {
+            auto* page = context.document->frame()->page();
+            std::optional<bool> forcedColorsOverride = page->useForcedColorsOverride();
+            if (forcedColorsOverride)
+                return forcedColorsOverride.value() ? MatchingIdentifiers { CSSValueActive } : MatchingIdentifiers { CSSValueNone };
             return MatchingIdentifiers { CSSValueNone };
         }
     };
@@ -540,6 +544,9 @@ const FeatureSchema& prefersReducedMotion()
         [](auto& context) {
             bool userPrefersReducedMotion = [&] {
                 Ref frame = *context.document->frame();
+                std::optional<bool> reducedMotionOverride = frame->page()->useReducedMotionOverride();
+                if (reducedMotionOverride)
+                    return reducedMotionOverride.value();
                 switch (frame->settings().forcedPrefersReducedMotionAccessibilityValue()) {
                 case ForcedAccessibilityValue::On:
                     return true;
diff --git a/Source/WebCore/dom/DataTransfer.cpp b/Source/WebCore/dom/DataTransfer.cpp
index 2e0a6ccf6778b23f4338c981ae3799c589beccab..4d6b5c864dad7719cedd5668f7d32428be904248 100644
--- a/Source/WebCore/dom/DataTransfer.cpp
+++ b/Source/WebCore/dom/DataTransfer.cpp
@@ -520,6 +520,14 @@ Ref<DataTransfer> DataTransfer::createForDrag(const Document& document)
     return adoptRef(*new DataTransfer(StoreMode::ReadWrite, Pasteboard::createForDragAndDrop(PagePasteboardContext::create(document.pageID())), Type::DragAndDropData));
 }
 
+#if PLATFORM(MAC)
+Ref<DataTransfer> DataTransfer::createForDrag(const Document& document, const String& pasteboardName)
+{
+    return adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique<Pasteboard>(PagePasteboardContext::create(document.pageID()), pasteboardName), Type::DragAndDropData));
+}
+#endif
+
+
 Ref<DataTransfer> DataTransfer::createForDragStartEvent(const Document& document)
 {
     auto dataTransfer = adoptRef(*new DataTransfer(StoreMode::ReadWrite, makeUnique<StaticPasteboard>(), Type::DragAndDropData));
diff --git a/Source/WebCore/dom/DataTransfer.h b/Source/WebCore/dom/DataTransfer.h
index 6327b8ff7709ed58bfd8140e59af87cb3a1f2b51..562812425187e2bae137abb4903a1497d6c4fbab 100644
--- a/Source/WebCore/dom/DataTransfer.h
+++ b/Source/WebCore/dom/DataTransfer.h
@@ -92,6 +92,9 @@ public:
 
 #if ENABLE(DRAG_SUPPORT)
     static Ref<DataTransfer> createForDrag(const Document&);
+#if PLATFORM(MAC)
+    static Ref<DataTransfer> createForDrag(const Document&, const String& pasteboardName);
+#endif
     static Ref<DataTransfer> createForDragStartEvent(const Document&);
     static Ref<DataTransfer> createForDrop(const Document&, std::unique_ptr<Pasteboard>&&, OptionSet<DragOperation>, bool draggingFiles);
     static Ref<DataTransfer> createForUpdatingDropTarget(const Document&, std::unique_ptr<Pasteboard>&&, OptionSet<DragOperation>, bool draggingFiles);
diff --git a/Source/WebCore/dom/DeviceMotionEvent.idl b/Source/WebCore/dom/DeviceMotionEvent.idl
index d59cba0b1c3e1876614476cd887fa1b2a9619d0c..565987a3f9ef7dc29edf8315cebe51b00953dc84 100644
--- a/Source/WebCore/dom/DeviceMotionEvent.idl
+++ b/Source/WebCore/dom/DeviceMotionEvent.idl
@@ -25,6 +25,7 @@
 
 [
     Conditional=DEVICE_ORIENTATION,
+    EnabledBySetting=DeviceOrientationEventEnabled,
     Exposed=Window
 ] interface DeviceMotionEvent : Event {
     readonly attribute Acceleration? acceleration;
diff --git a/Source/WebCore/dom/DeviceOrientationEvent.idl b/Source/WebCore/dom/DeviceOrientationEvent.idl
index 9043052540b13d8120fb641de6337af46c3b36ef..a0f89e64b64640d2d4dbc14734868c4d4b03fc6f 100644
--- a/Source/WebCore/dom/DeviceOrientationEvent.idl
+++ b/Source/WebCore/dom/DeviceOrientationEvent.idl
@@ -25,6 +25,7 @@
 
 [
     Conditional=DEVICE_ORIENTATION,
+    EnabledBySetting=DeviceOrientationEventEnabled,
     Exposed=Window
 ] interface DeviceOrientationEvent : Event {
     readonly attribute unrestricted double? alpha;
diff --git a/Source/WebCore/dom/Document+PointerLock.idl b/Source/WebCore/dom/Document+PointerLock.idl
index 2e9c9fda6a920cd8904432bd1bdbfbf32d01c085..2fd33597e905b0544665ff765f310945305a0c4a 100644
--- a/Source/WebCore/dom/Document+PointerLock.idl
+++ b/Source/WebCore/dom/Document+PointerLock.idl
@@ -25,6 +25,7 @@
 
 // https://w3c.github.io/pointerlock/#extensions-to-the-document-interface
 [
+    EnabledBySetting=PointerLockEnabled,
     Conditional=POINTER_LOCK
 ] partial interface Document {
     attribute EventHandler onpointerlockchange;
diff --git a/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl b/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl
index 9b8dbfc15ce078702321abcd6c0e636df7a60510..2956f7098e87af10ab8f5584b456ce9a6d432a20 100644
--- a/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl
+++ b/Source/WebCore/dom/DocumentOrShadowRoot+PointerLock.idl
@@ -25,6 +25,7 @@
 
 // https://w3c.github.io/pointerlock/#extensions-to-the-documentorshadowroot-mixin
 [
+    EnabledBySetting=PointerLockEnabled,
     Conditional=POINTER_LOCK
 ] partial interface mixin DocumentOrShadowRoot {
     readonly attribute Element? pointerLockElement;
diff --git a/Source/WebCore/dom/Element+PointerLock.idl b/Source/WebCore/dom/Element+PointerLock.idl
index 9b344003de17b96d8b9ca8c7f32143a27543b1ea..2208a3f2b7d930bcd291e65b474d4c3023d2a7e4 100644
--- a/Source/WebCore/dom/Element+PointerLock.idl
+++ b/Source/WebCore/dom/Element+PointerLock.idl
@@ -24,6 +24,7 @@
  */
 
 [
+    EnabledBySetting=PointerLockEnabled,
     Conditional=POINTER_LOCK
 ] partial interface Element {
     // Returns Promise<undefined> if PointerLockOptionsEnabled Runtime Flag is set, otherwise returns undefined.
diff --git a/Source/WebCore/dom/PointerEvent.cpp b/Source/WebCore/dom/PointerEvent.cpp
index 2a728c134f837ee36c033971e1c47792f4a3caf2..b1ecb3b2dd2efc43d679bb0f678457188cb2cb3a 100644
--- a/Source/WebCore/dom/PointerEvent.cpp
+++ b/Source/WebCore/dom/PointerEvent.cpp
@@ -27,10 +27,13 @@
 #include "PointerEvent.h"
 
 #include "EventNames.h"
+#include "MouseEvent.h"
 #include "Node.h"
 #include "PlatformMouseEvent.h"
+#include "PlatformTouchEvent.h"
 #include "PointerEventTypeNames.h"
 #include <wtf/TZoneMallocInlines.h>
+#include <wtf/IsoMallocInlines.h>
 
 namespace WebCore {
 
@@ -292,4 +295,59 @@ void PointerEvent::receivedTarget()
         predictedEvent->setTarget(this->target());
 }
 
+#if ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY) && !PLATFORM(WPE)
+
+static const AtomString& pointerEventType(PlatformTouchPoint::State state)
+{
+    switch (state) {
+    case PlatformTouchPoint::State::TouchPressed:
+        return eventNames().pointerdownEvent;
+    case PlatformTouchPoint::State::TouchMoved:
+        return eventNames().pointermoveEvent;
+    case PlatformTouchPoint::State::TouchStationary:
+        return eventNames().pointermoveEvent;
+    case PlatformTouchPoint::State::TouchReleased:
+        return eventNames().pointerupEvent;
+    case PlatformTouchPoint::State::TouchCancelled:
+        return eventNames().pointercancelEvent;
+    case PlatformTouchPoint::State::TouchStateEnd:
+        break;
+    }
+    ASSERT_NOT_REACHED();
+    return nullAtom();
+}
+
+Ref<PointerEvent> PointerEvent::create(const PlatformTouchEvent& event, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const IntPoint& touchDelta)
+{
+    const auto& type = pointerEventType(event.touchPoints().at(touchIndex).state());
+    return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, typeCanBubble(type), typeIsCancelable(type), touchIndex, isPrimary, WTFMove(view), touchDelta));
+}
+
+Ref<PointerEvent> PointerEvent::create(const PlatformTouchEvent& event, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const IntPoint& touchDelta)
+{
+    const auto& type = pointerEventType(event.touchPoints().at(touchIndex).state());
+    return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, canBubble, isCancelable, touchIndex, isPrimary, WTFMove(view), touchDelta));
+}
+
+Ref<PointerEvent> PointerEvent::create(const AtomString& type, const PlatformTouchEvent& event, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const IntPoint& touchDelta)
+{
+    return adoptRef(*new PointerEvent(type, event, coalescedEvents, predictedEvents, typeCanBubble(type), typeIsCancelable(type), touchIndex, isPrimary, WTFMove(view), touchDelta));
+}
+
+PointerEvent::PointerEvent(const AtomString& type, const PlatformTouchEvent& event, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const IntPoint& touchDelta)
+    : MouseEvent(EventInterfaceType::PointerEvent, type, canBubble, isCancelable, typeIsComposed(type), event.timestamp().approximateMonotonicTime(), WTFMove(view), 0,
+        event.touchPoints().at(touchIndex).pos(), event.touchPoints().at(touchIndex).pos(), touchDelta.x(), touchDelta.y(), event.modifiers(), buttonForType(type), buttonsForType(type), nullptr, 0, SyntheticClickType::NoTap, { }, { }, IsSimulated::No, IsTrusted::Yes)
+    , m_pointerId(event.touchPoints().at(touchIndex).id())
+    , m_width(2 * event.touchPoints().at(touchIndex).radiusX())
+    , m_height(2 * event.touchPoints().at(touchIndex).radiusY())
+    , m_pressure(event.touchPoints().at(touchIndex).force())
+    , m_pointerType(touchPointerEventType())
+    , m_isPrimary(isPrimary)
+    , m_coalescedEvents(coalescedEvents)
+    , m_predictedEvents(predictedEvents)
+{
+}
+
+#endif // ENABLE(TOUCH_EVENTS) && !PLATFORM(IOS_FAMILY)
+
 } // namespace WebCore
diff --git a/Source/WebCore/dom/PointerEvent.h b/Source/WebCore/dom/PointerEvent.h
index b034595d01bb63f3d72183c427fcc14695339ae2..1886e4bbba04c6177fad1562c891f2aeff0a8247 100644
--- a/Source/WebCore/dom/PointerEvent.h
+++ b/Source/WebCore/dom/PointerEvent.h
@@ -34,6 +34,8 @@
 
 #if ENABLE(TOUCH_EVENTS) && PLATFORM(IOS_FAMILY)
 #include "PlatformTouchEventIOS.h"
+#else
+#include "PlatformTouchEvent.h"
 #endif
 
 #if ENABLE(TOUCH_EVENTS) && PLATFORM(WPE)
@@ -94,7 +96,7 @@ public:
     static Ref<PointerEvent> create(const AtomString& type, MouseButton, const MouseEvent&, PointerID, const String& pointerType, CanBubble, IsCancelable);
     static Ref<PointerEvent> create(const AtomString& type, PointerID, const String& pointerType, IsPrimary = IsPrimary::No);
 
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
     static Ref<PointerEvent> create(const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&, const IntPoint& touchDelta = { });
     static Ref<PointerEvent> create(const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, CanBubble, IsCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&& view, const IntPoint& touchDelta = { });
     static Ref<PointerEvent> create(const AtomString& type, const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&, const IntPoint& touchDelta = { });
@@ -173,7 +175,7 @@ private:
     PointerEvent();
     PointerEvent(const AtomString&, Init&&, IsTrusted);
     PointerEvent(const AtomString& type, PointerID, const String& pointerType, IsPrimary);
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
     PointerEvent(const AtomString& type, const PlatformTouchEvent&, const Vector<Ref<PointerEvent>>& coalescedEvents, const Vector<Ref<PointerEvent>>& predictedEvents, CanBubble canBubble, IsCancelable isCancelable, unsigned touchIndex, bool isPrimary, Ref<WindowProxy>&&, const IntPoint& touchDelta = { });
 #endif
 
diff --git a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp
index 7813532cc52d582c42aebc979a1ecd1137765f08..c01cbd53ad2430a6ffab9a80fc73e74a8523800a 100644
--- a/Source/WebCore/editing/libwpe/EditorLibWPE.cpp
+++ b/Source/WebCore/editing/libwpe/EditorLibWPE.cpp
@@ -34,6 +34,7 @@
 #include "NotImplemented.h"
 #include "Pasteboard.h"
 #include "Settings.h"
+#include "WebContentReader.h"
 #include "markup.h"
 
 namespace WebCore {
@@ -99,6 +100,14 @@ void Editor::platformPasteFont()
 {
 }
 
+RefPtr<DocumentFragment> Editor::webContentFromPasteboard(Pasteboard& pasteboard, const SimpleRange& context, bool allowPlainText, bool& chosePlainText)
+{
+    WebContentReader reader(*document().frame(), context, allowPlainText);
+    pasteboard.read(reader);
+    chosePlainText = reader.madeFragmentFromPlainText();
+    return reader.takeFragment();
+}
+
 } // namespace WebCore
 
 #endif // USE(LIBWPE)
diff --git a/Source/WebCore/html/FileInputType.cpp b/Source/WebCore/html/FileInputType.cpp
index 26e7ca561e3923e2b11da48e777348d3928bff53..a151c289dcd1aef5e0f26faaa7785137296829b8 100644
--- a/Source/WebCore/html/FileInputType.cpp
+++ b/Source/WebCore/html/FileInputType.cpp
@@ -37,6 +37,7 @@
 #include "HTMLNames.h"
 #include "Icon.h"
 #include "InputTypeNames.h"
+#include "InspectorInstrumentation.h"
 #include "LocalFrame.h"
 #include "LocalizedStrings.h"
 #include "MIMETypeRegistry.h"
@@ -160,6 +161,11 @@ void FileInputType::handleDOMActivateEvent(Event& event)
     if (input.isDisabledFormControl())
         return;
 
+    bool intercept = false;
+    InspectorInstrumentation::runOpenPanel(input.document().frame(), element(), &intercept);
+    if (intercept)
+        return;
+
     if (!UserGestureIndicator::processingUserGesture())
         return;
 
@@ -348,7 +354,9 @@ void FileInputType::setFiles(RefPtr<FileList>&& files, RequestIcon shouldRequest
         pathsChanged = true;
     else {
         for (unsigned i = 0; i < length; ++i) {
-            if (files->file(i).path() != m_fileList->file(i).path() || !FileSystem::fileIDsAreEqual(files->file(i).fileID(), m_fileList->file(i).fileID())) {
+            if (files->file(i).path() != m_fileList->file(i).path() || !FileSystem::fileIDsAreEqual(files->file(i).fileID(), m_fileList->file(i).fileID()) ||
+                // Files created from Blob have empty path.
+                (files->file(i).path().isEmpty() && files->file(i).name() != m_fileList->file(i).name())) {
                 pathsChanged = true;
                 break;
             }
diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp
index ee592715641d111078aec266c9b35c0eea9a6f48..bc403a764837abce3c7771c31c4909b6c0de211e 100644
--- a/Source/WebCore/inspector/InspectorController.cpp
+++ b/Source/WebCore/inspector/InspectorController.cpp
@@ -300,6 +300,8 @@ void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
 
         // Unplug all instrumentations since they aren't needed now.
         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
+
+        m_pauseOnStart = PauseCondition::DONT_PAUSE;
     }
 
     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
@@ -319,6 +321,8 @@ void InspectorController::disconnectAllFrontends()
     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
     ASSERT(!m_inspectorFrontendClient);
 
+    m_pauseOnStart = PauseCondition::DONT_PAUSE;
+
     if (!m_frontendRouter->hasFrontends())
         return;
 
@@ -402,8 +406,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);
 }
@@ -546,4 +550,34 @@ void InspectorController::didComposite(LocalFrame& frame)
     InspectorInstrumentation::didComposite(frame);
 }
 
+void InspectorController::pauseOnStart(PauseCondition condition)
+{
+    m_pauseOnStart = condition;
+}
+
+void InspectorController::resumeIfPausedInNewWindow()
+{
+    m_pauseOnStart = PauseCondition::DONT_PAUSE;
+}
+
+void InspectorController::didFinishPageCreation()
+{
+    if (m_pauseOnStart == PauseCondition::WHEN_CREATION_FINISHED)
+        runLoopWhilePaused();
+}
+
+void InspectorController::didShowPage()
+{
+    if (m_pauseOnStart == PauseCondition::WHEN_SHOWN)
+        runLoopWhilePaused();
+}
+
+void InspectorController::runLoopWhilePaused()
+{
+    while (m_pauseOnStart != PauseCondition::DONT_PAUSE) {
+        if (RunLoop::cycle() == RunLoop::CycleResult::Stop)
+            break;
+    }
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/InspectorController.h b/Source/WebCore/inspector/InspectorController.h
index 4f5c1e836876710a554455ec53733f72db63de58..774c4a66af84664a7a83ba0790d147f7bbb4236a 100644
--- a/Source/WebCore/inspector/InspectorController.h
+++ b/Source/WebCore/inspector/InspectorController.h
@@ -106,6 +106,12 @@ public:
     WEBCORE_EXPORT void willComposite(LocalFrame&);
     WEBCORE_EXPORT void didComposite(LocalFrame&);
 
+    enum class PauseCondition { DONT_PAUSE, WHEN_SHOWN, WHEN_CREATION_FINISHED };
+    WEBCORE_EXPORT void pauseOnStart(PauseCondition);
+    WEBCORE_EXPORT void resumeIfPausedInNewWindow();
+    WEBCORE_EXPORT void didShowPage();
+    WEBCORE_EXPORT void didFinishPageCreation();
+
     // Testing support.
     bool isUnderTest() const { return m_isUnderTest; }
     void setIsUnderTest(bool isUnderTest) { m_isUnderTest = isUnderTest; }
@@ -136,6 +142,7 @@ private:
 
     PageAgentContext pageAgentContext();
     void createLazyAgents();
+    void runLoopWhilePaused();
 
     WeakRef<Page> m_page;
     Ref<InstrumentingAgents> m_instrumentingAgents;
@@ -159,6 +166,7 @@ private:
     bool m_isAutomaticInspection { false };
     bool m_pauseAfterInitialization = { false };
     bool m_didCreateLazyAgents { false };
+    PauseCondition m_pauseOnStart { PauseCondition::DONT_PAUSE };
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp
index da310c6df500f80d2ae762c890ce9733d892ebd1..50db06b983b2eb4ac89942df94838e009bc82175 100644
--- a/Source/WebCore/inspector/InspectorInstrumentation.cpp
+++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp
@@ -598,6 +598,12 @@ void InspectorInstrumentation::applyUserAgentOverrideImpl(InstrumentingAgents& i
         pageAgent->applyUserAgentOverride(userAgent);
 }
 
+void InspectorInstrumentation::applyPlatformOverrideImpl(InstrumentingAgents& instrumentingAgents, String& platform)
+{
+    if (auto* pageAgent = instrumentingAgents.enabledPageAgent())
+        pageAgent->applyPlatformOverride(platform);
+}
+
 void InspectorInstrumentation::applyEmulatedMediaImpl(InstrumentingAgents& instrumentingAgents, AtomString& media)
 {
     if (auto* pageAgent = instrumentingAgents.enabledPageAgent())
@@ -681,6 +687,12 @@ void InspectorInstrumentation::didFailLoadingImpl(InstrumentingAgents& instrumen
         consoleAgent->didFailLoading(identifier, error); // This should come AFTER resource notification, front-end relies on this.
 }
 
+void InspectorInstrumentation::didReceiveMainResourceErrorImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame, const ResourceError&)
+{
+    if (auto* pageRuntimeAgent = instrumentingAgents.enabledPageRuntimeAgent())
+        pageRuntimeAgent->didReceiveMainResourceError(frame);
+}
+
 void InspectorInstrumentation::willLoadXHRSynchronouslyImpl(InstrumentingAgents& instrumentingAgents)
 {
     if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent())
@@ -713,20 +725,17 @@ void InspectorInstrumentation::didReceiveScriptResponseImpl(InstrumentingAgents&
 
 void InspectorInstrumentation::domContentLoadedEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame)
 {
-    if (!frame.isMainFrame())
-        return;
-
     if (auto* pageAgent = instrumentingAgents.enabledPageAgent())
-        pageAgent->domContentEventFired();
+        pageAgent->domContentEventFired(frame);
 }
 
 void InspectorInstrumentation::loadEventFiredImpl(InstrumentingAgents& instrumentingAgents, LocalFrame* frame)
 {
-    if (!frame || !frame->isMainFrame())
+    if (!frame)
         return;
 
     if (auto* pageAgent = instrumentingAgents.enabledPageAgent())
-        pageAgent->loadEventFired();
+        pageAgent->loadEventFired(*frame);
 }
 
 void InspectorInstrumentation::frameDetachedFromParentImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame)
@@ -809,12 +818,6 @@ void InspectorInstrumentation::frameDocumentUpdatedImpl(InstrumentingAgents& ins
         pageDOMDebuggerAgent->frameDocumentUpdated(frame);
 }
 
-void InspectorInstrumentation::loaderDetachedFromFrameImpl(InstrumentingAgents& instrumentingAgents, DocumentLoader& loader)
-{
-    if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent())
-        inspectorPageAgent->loaderDetachedFromFrame(loader);
-}
-
 void InspectorInstrumentation::frameStartedLoadingImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame)
 {
     if (frame.isMainFrame()) {
@@ -845,10 +848,10 @@ void InspectorInstrumentation::frameStoppedLoadingImpl(InstrumentingAgents& inst
         inspectorPageAgent->frameStoppedLoading(frame);
 }
 
-void InspectorInstrumentation::frameScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, Seconds delay)
+void InspectorInstrumentation::frameScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame, Seconds delay, bool targetIsCurrentFrame)
 {
     if (auto* inspectorPageAgent = instrumentingAgents.enabledPageAgent())
-        inspectorPageAgent->frameScheduledNavigation(frame, delay);
+        inspectorPageAgent->frameScheduledNavigation(frame, delay, targetIsCurrentFrame);
 }
 
 void InspectorInstrumentation::frameClearedScheduledNavigationImpl(InstrumentingAgents& instrumentingAgents, Frame& frame)
@@ -863,6 +866,12 @@ void InspectorInstrumentation::accessibilitySettingsDidChangeImpl(InstrumentingA
         inspectorPageAgent->accessibilitySettingsDidChange();
 }
 
+void InspectorInstrumentation::didNavigateWithinPageImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame)
+{
+    if (InspectorPageAgent* inspectorPageAgent = instrumentingAgents.enabledPageAgent())
+        inspectorPageAgent->didNavigateWithinPage(frame);
+}
+
 #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT)
 void InspectorInstrumentation::defaultAppearanceDidChangeImpl(InstrumentingAgents& instrumentingAgents)
 {
@@ -915,6 +924,12 @@ void InspectorInstrumentation::interceptResponseImpl(InstrumentingAgents& instru
         networkAgent->interceptResponse(response, identifier, WTFMove(handler));
 }
 
+void InspectorInstrumentation::setStoppingLoadingDueToProcessSwapImpl(InstrumentingAgents& instrumentingAgents, bool value)
+{
+    if (auto* networkAgent = instrumentingAgents.enabledNetworkAgent())
+        networkAgent->setStoppingLoadingDueToProcessSwap(value);
+}
+
 // JavaScriptCore InspectorDebuggerAgent should know Console MessageTypes.
 static bool isConsoleAssertMessage(MessageSource source, MessageType type)
 {
@@ -1051,6 +1066,12 @@ void InspectorInstrumentation::consoleStopRecordingCanvasImpl(InstrumentingAgent
         canvasAgent->consoleStopRecordingCanvas(context);
 }
 
+void InspectorInstrumentation::bindingCalledImpl(InstrumentingAgents& instrumentingAgents, JSC::JSGlobalObject* globalObject, const String& name, const String& arg)
+{
+    if (auto* pageRuntimeAgent = instrumentingAgents.enabledPageRuntimeAgent())
+        pageRuntimeAgent->bindingCalled(globalObject, name, arg);
+}
+
 void InspectorInstrumentation::didOpenDatabaseImpl(InstrumentingAgents& instrumentingAgents, Database& database)
 {
     if (auto* databaseAgent = instrumentingAgents.enabledDatabaseAgent())
@@ -1357,6 +1378,36 @@ void InspectorInstrumentation::renderLayerDestroyedImpl(InstrumentingAgents& ins
         layerTreeAgent->renderLayerDestroyed(renderLayer);
 }
 
+void InspectorInstrumentation::runOpenPanelImpl(InstrumentingAgents& instrumentingAgents, HTMLInputElement* element, bool* intercept)
+{
+    if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent())
+        pageAgent->runOpenPanel(element, intercept);
+}
+
+void InspectorInstrumentation::frameAttachedImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame) {
+    if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent())
+        pageAgent->frameAttached(frame);
+}
+
+bool InspectorInstrumentation::shouldBypassCSPImpl(InstrumentingAgents& instrumentingAgents)
+{
+    if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent())
+        return pageAgent->shouldBypassCSP();
+    return false;
+}
+
+void InspectorInstrumentation::willCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame)
+{
+    if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent())
+        pageAgent->willCheckNavigationPolicy(frame);
+}
+
+void InspectorInstrumentation::didCheckNavigationPolicyImpl(InstrumentingAgents& instrumentingAgents, LocalFrame& frame, bool cancel)
+{
+    if (InspectorPageAgent* pageAgent = instrumentingAgents.enabledPageAgent())
+        pageAgent->didCheckNavigationPolicy(frame, cancel);
+}
+
 InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(WorkerOrWorkletGlobalScope& globalScope)
 {
     return globalScope.inspectorController().m_instrumentingAgents;
@@ -1373,6 +1424,13 @@ InstrumentingAgents& InspectorInstrumentation::instrumentingAgents(Page& page)
     return page.inspectorController().m_instrumentingAgents.get();
 }
 
+void InspectorInstrumentation::maybeOverrideDefaultObjectInclusion(Page& page, AccessibilityObjectInclusion& inclusion) {
+    if (InspectorPageAgent* pageAgent = instrumentingAgents(page).enabledPageAgent()) {
+        if (pageAgent->doingAccessibilitySnapshot())
+            inclusion = AccessibilityObjectInclusion::DefaultBehavior;
+    }
+}
+
 InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext& context)
 {
     // Using RefPtr makes us hit the m_inRemovedLastRefFunction assert.
diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h
index 156e222e4383bee7448347d84cb052b0d9b9ae70..9bce3a168c314fc34043578c248d69cb89b48426 100644
--- a/Source/WebCore/inspector/InspectorInstrumentation.h
+++ b/Source/WebCore/inspector/InspectorInstrumentation.h
@@ -31,6 +31,7 @@
 
 #pragma once
 
+#include "AXCoreObject.h"
 #include "CSSSelector.h"
 #include "CanvasBase.h"
 #include "CanvasRenderingContext.h"
@@ -45,6 +46,7 @@
 #include "LocalFrame.h"
 #include "LocalFrameView.h"
 #include "Page.h"
+#include "ResourceError.h"
 #include "ResourceLoader.h"
 #include "ResourceLoaderIdentifier.h"
 #include "StorageArea.h"
@@ -78,6 +80,7 @@ class DOMWrapperWorld;
 class Document;
 class DocumentLoader;
 class EventListener;
+class HTMLInputElement;
 class HTTPHeaderMap;
 class InspectorTimelineAgent;
 class InstrumentingAgents;
@@ -193,6 +196,7 @@ public:
     static void didRecalculateStyle(Document&);
     static void didScheduleStyleRecalculation(Document&);
     static void applyUserAgentOverride(LocalFrame&, String&);
+    static void applyPlatformOverride(LocalFrame&, String&);
     static void applyEmulatedMedia(LocalFrame&, AtomString&);
 
     static void flexibleBoxRendererBeganLayout(const RenderObject&);
@@ -205,6 +209,7 @@ public:
     static void didReceiveData(LocalFrame*, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength);
     static void didFinishLoading(LocalFrame*, DocumentLoader*, ResourceLoaderIdentifier, const NetworkLoadMetrics&, ResourceLoader*);
     static void didFailLoading(LocalFrame*, DocumentLoader*, ResourceLoaderIdentifier, const ResourceError&);
+    static void didReceiveMainResourceError(LocalFrame&, const ResourceError&);
 
     static void willSendRequest(ServiceWorkerGlobalScope&, ResourceLoaderIdentifier, ResourceRequest&);
     static void didReceiveResourceResponse(ServiceWorkerGlobalScope&, ResourceLoaderIdentifier, const ResourceResponse&);
@@ -231,13 +236,13 @@ public:
     static void frameDetachedFromParent(LocalFrame&);
     static void didCommitLoad(LocalFrame&, DocumentLoader*);
     static void frameDocumentUpdated(LocalFrame&);
-    static void loaderDetachedFromFrame(LocalFrame&, DocumentLoader&);
     static void frameStartedLoading(LocalFrame&);
     static void frameStoppedLoading(LocalFrame&);
     static void didCompleteRenderingFrame(Frame&);
-    static void frameScheduledNavigation(Frame&, Seconds delay);
+    static void frameScheduledNavigation(Frame&, Seconds delay, bool targetIsCurrentFrame);
     static void frameClearedScheduledNavigation(Frame&);
     static void accessibilitySettingsDidChange(Page&);
+    static void didNavigateWithinPage(LocalFrame&);
 #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT)
     static void defaultAppearanceDidChange(Page&);
 #endif
@@ -248,6 +253,7 @@ public:
     static bool shouldInterceptResponse(const LocalFrame&, const ResourceResponse&);
     static void interceptRequest(ResourceLoader&, Function<void(const ResourceRequest&)>&&);
     static void interceptResponse(const LocalFrame&, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler<void(const ResourceResponse&, RefPtr<FragmentedSharedBuffer>)>&&);
+    static void setStoppingLoadingDueToProcessSwap(Page*, bool);
 
     static void addMessageToConsole(Page&, std::unique_ptr<Inspector::ConsoleMessage>);
     static void addMessageToConsole(WorkerOrWorkletGlobalScope&, std::unique_ptr<Inspector::ConsoleMessage>);
@@ -269,6 +275,7 @@ public:
     static void stopProfiling(Page&, JSC::JSGlobalObject*, const String& title);
     static void consoleStartRecordingCanvas(CanvasRenderingContext&, JSC::JSGlobalObject&, JSC::JSObject* options);
     static void consoleStopRecordingCanvas(CanvasRenderingContext&);
+    static void bindingCalled(Page& , JSC::JSGlobalObject*, const String& name, const String& arg);
 
     static void performanceMark(ScriptExecutionContext&, const String&, std::optional<MonotonicTime>, LocalFrame*);
 
@@ -327,6 +334,12 @@ public:
     static void layerTreeDidChange(Page*);
     static void renderLayerDestroyed(Page*, const RenderLayer&);
 
+    static void runOpenPanel(LocalFrame*, HTMLInputElement*, bool*);
+    static void frameAttached(LocalFrame*);
+    static bool shouldBypassCSP(ScriptExecutionContext*);
+    static void willCheckNavigationPolicy(LocalFrame&);
+    static void didCheckNavigationPolicy(LocalFrame&, bool cancel);
+
     static void frontendCreated();
     static void frontendDeleted();
     static bool hasFrontends() { return InspectorInstrumentationPublic::hasFrontends(); }
@@ -343,6 +356,8 @@ public:
     static void registerInstrumentingAgents(InstrumentingAgents&);
     static void unregisterInstrumentingAgents(InstrumentingAgents&);
 
+    static void maybeOverrideDefaultObjectInclusion(Page&, AccessibilityObjectInclusion&);
+
 private:
     static void didClearWindowObjectInWorldImpl(InstrumentingAgents&, LocalFrame&, DOMWrapperWorld&);
     static bool isDebuggerPausedImpl(InstrumentingAgents&);
@@ -422,6 +437,7 @@ private:
     static void didRecalculateStyleImpl(InstrumentingAgents&);
     static void didScheduleStyleRecalculationImpl(InstrumentingAgents&, Document&);
     static void applyUserAgentOverrideImpl(InstrumentingAgents&, String&);
+    static void applyPlatformOverrideImpl(InstrumentingAgents&, String&);
     static void applyEmulatedMediaImpl(InstrumentingAgents&, AtomString&);
 
     static void flexibleBoxRendererBeganLayoutImpl(InstrumentingAgents&, const RenderObject&);
@@ -436,6 +452,7 @@ private:
     static void didReceiveDataImpl(InstrumentingAgents&, ResourceLoaderIdentifier, const SharedBuffer*, int encodedDataLength);
     static void didFinishLoadingImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, const NetworkLoadMetrics&, ResourceLoader*);
     static void didFailLoadingImpl(InstrumentingAgents&, ResourceLoaderIdentifier, DocumentLoader*, const ResourceError&);
+    static void didReceiveMainResourceErrorImpl(InstrumentingAgents&, LocalFrame&, const ResourceError&);
     static void willLoadXHRSynchronouslyImpl(InstrumentingAgents&);
     static void didLoadXHRSynchronouslyImpl(InstrumentingAgents&);
     static void scriptImportedImpl(InstrumentingAgents&, ResourceLoaderIdentifier, const String& sourceString);
@@ -446,13 +463,13 @@ private:
     static void frameDetachedFromParentImpl(InstrumentingAgents&, LocalFrame&);
     static void didCommitLoadImpl(InstrumentingAgents&, LocalFrame&, DocumentLoader*);
     static void frameDocumentUpdatedImpl(InstrumentingAgents&, LocalFrame&);
-    static void loaderDetachedFromFrameImpl(InstrumentingAgents&, DocumentLoader&);
     static void frameStartedLoadingImpl(InstrumentingAgents&, LocalFrame&);
     static void didCompleteRenderingFrameImpl(InstrumentingAgents&);
     static void frameStoppedLoadingImpl(InstrumentingAgents&, LocalFrame&);
-    static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay);
+    static void frameScheduledNavigationImpl(InstrumentingAgents&, Frame&, Seconds delay, bool targetIsCurrentFrame);
     static void frameClearedScheduledNavigationImpl(InstrumentingAgents&, Frame&);
     static void accessibilitySettingsDidChangeImpl(InstrumentingAgents&);
+    static void didNavigateWithinPageImpl(InstrumentingAgents&, LocalFrame&);
 #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT)
     static void defaultAppearanceDidChangeImpl(InstrumentingAgents&);
 #endif
@@ -463,6 +480,7 @@ private:
     static bool shouldInterceptResponseImpl(InstrumentingAgents&, const ResourceResponse&);
     static void interceptRequestImpl(InstrumentingAgents&, ResourceLoader&, Function<void(const ResourceRequest&)>&&);
     static void interceptResponseImpl(InstrumentingAgents&, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler<void(const ResourceResponse&, RefPtr<FragmentedSharedBuffer>)>&&);
+    static void setStoppingLoadingDueToProcessSwapImpl(InstrumentingAgents&, bool);
 
     static void addMessageToConsoleImpl(InstrumentingAgents&, std::unique_ptr<Inspector::ConsoleMessage>);
 
@@ -479,6 +497,7 @@ private:
     static void stopProfilingImpl(InstrumentingAgents&, JSC::JSGlobalObject*, const String& title);
     static void consoleStartRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&, JSC::JSGlobalObject&, JSC::JSObject* options);
     static void consoleStopRecordingCanvasImpl(InstrumentingAgents&, CanvasRenderingContext&);
+    static void bindingCalledImpl(InstrumentingAgents&, JSC::JSGlobalObject*, const String& name, const String& arg);
 
     static void performanceMarkImpl(InstrumentingAgents&, const String& label, std::optional<MonotonicTime>, LocalFrame*);
 
@@ -537,6 +556,12 @@ private:
     static void layerTreeDidChangeImpl(InstrumentingAgents&);
     static void renderLayerDestroyedImpl(InstrumentingAgents&, const RenderLayer&);
 
+    static void runOpenPanelImpl(InstrumentingAgents&, HTMLInputElement*, bool*);
+    static void frameAttachedImpl(InstrumentingAgents&, LocalFrame&);
+    static bool shouldBypassCSPImpl(InstrumentingAgents&);
+    static void willCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&);
+    static void didCheckNavigationPolicyImpl(InstrumentingAgents&, LocalFrame&, bool cancel);
+
     static InstrumentingAgents& instrumentingAgents(Page&);
     static InstrumentingAgents& instrumentingAgents(WorkerOrWorkletGlobalScope&);
     static InstrumentingAgents& instrumentingAgents(ServiceWorkerGlobalScope&);
@@ -1070,6 +1095,13 @@ inline void InspectorInstrumentation::applyUserAgentOverride(LocalFrame& frame,
         applyUserAgentOverrideImpl(*agents, userAgent);
 }
 
+inline void InspectorInstrumentation::applyPlatformOverride(LocalFrame& frame, String& platform)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(frame))
+        applyPlatformOverrideImpl(*agents, platform);
+}
+
 inline void InspectorInstrumentation::applyEmulatedMedia(LocalFrame& frame, AtomString& media)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
@@ -1172,6 +1204,13 @@ inline void InspectorInstrumentation::didFailLoading(ServiceWorkerGlobalScope& g
     didFailLoadingImpl(instrumentingAgents(globalScope), identifier, nullptr, error);
 }
 
+inline void InspectorInstrumentation::didReceiveMainResourceError(LocalFrame& frame, const ResourceError& error)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(frame))
+        didReceiveMainResourceErrorImpl(*agents, frame, error);
+}
+
 inline void InspectorInstrumentation::continueAfterXFrameOptionsDenied(LocalFrame& frame, ResourceLoaderIdentifier identifier, DocumentLoader& loader, const ResourceResponse& response)
 {
     // Treat the same as didReceiveResponse.
@@ -1262,13 +1301,6 @@ inline void InspectorInstrumentation::frameDocumentUpdated(LocalFrame& frame)
         frameDocumentUpdatedImpl(*agents, frame);
 }
 
-inline void InspectorInstrumentation::loaderDetachedFromFrame(LocalFrame& frame, DocumentLoader& loader)
-{
-    FAST_RETURN_IF_NO_FRONTENDS(void());
-    if (auto* agents = instrumentingAgents(frame))
-        loaderDetachedFromFrameImpl(*agents, loader);
-}
-
 inline void InspectorInstrumentation::frameStartedLoading(LocalFrame& frame)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
@@ -1290,11 +1322,11 @@ inline void InspectorInstrumentation::frameStoppedLoading(LocalFrame& frame)
         frameStoppedLoadingImpl(*agents, frame);
 }
 
-inline void InspectorInstrumentation::frameScheduledNavigation(Frame& frame, Seconds delay)
+inline void InspectorInstrumentation::frameScheduledNavigation(Frame& frame, Seconds delay, bool targetIsCurrentFrame)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
     if (auto* agents = instrumentingAgents(frame))
-        frameScheduledNavigationImpl(*agents, frame, delay);
+        frameScheduledNavigationImpl(*agents, frame, delay, targetIsCurrentFrame);
 }
 
 inline void InspectorInstrumentation::frameClearedScheduledNavigation(Frame& frame)
@@ -1310,6 +1342,13 @@ inline void InspectorInstrumentation::accessibilitySettingsDidChange(Page& page)
     accessibilitySettingsDidChangeImpl(instrumentingAgents(page));
 }
 
+inline void InspectorInstrumentation::didNavigateWithinPage(LocalFrame& frame)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(frame))
+        didNavigateWithinPageImpl(*agents, frame);
+}
+
 #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT)
 inline void InspectorInstrumentation::defaultAppearanceDidChange(Page& page)
 {
@@ -1362,6 +1401,13 @@ inline void InspectorInstrumentation::interceptResponse(const LocalFrame& frame,
         interceptResponseImpl(*agents, response, identifier, WTFMove(handler));
 }
 
+inline void InspectorInstrumentation::setStoppingLoadingDueToProcessSwap(Page* page, bool value)
+{
+    ASSERT(InspectorInstrumentationPublic::hasFrontends());
+    if (auto* agents = instrumentingAgents(page))
+        setStoppingLoadingDueToProcessSwapImpl(*agents, value);
+}
+
 inline void InspectorInstrumentation::didOpenDatabase(Database& database)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
@@ -1698,6 +1744,11 @@ inline void InspectorInstrumentation::performanceMark(ScriptExecutionContext& co
         performanceMarkImpl(*agents, label, WTFMove(startTime), frame);
 }
 
+inline void InspectorInstrumentation::bindingCalled(Page& page, JSC::JSGlobalObject* globalObject, const String& name, const String& arg)
+{
+    bindingCalledImpl(instrumentingAgents(page), globalObject, name, arg);
+}
+
 inline void InspectorInstrumentation::didRequestAnimationFrame(Document& document, int callbackId)
 {
     FAST_RETURN_IF_NO_FRONTENDS(void());
@@ -1754,6 +1805,42 @@ inline void InspectorInstrumentation::renderLayerDestroyed(Page* page, const Ren
         renderLayerDestroyedImpl(*agents, renderLayer);
 }
 
+inline void InspectorInstrumentation::runOpenPanel(LocalFrame* frame, HTMLInputElement* element, bool* intercept)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(*frame))
+        runOpenPanelImpl(*agents, element, intercept);
+}
+
+inline void InspectorInstrumentation::frameAttached(LocalFrame* frame)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(frame))
+        frameAttachedImpl(*agents, *frame);
+}
+
+inline bool InspectorInstrumentation::shouldBypassCSP(ScriptExecutionContext* context)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(false);
+    if (auto* agents = instrumentingAgents(context))
+        return shouldBypassCSPImpl(*agents);
+    return false;
+}
+
+inline void InspectorInstrumentation::willCheckNavigationPolicy(LocalFrame& frame)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(frame))
+        willCheckNavigationPolicyImpl(*agents, frame);
+}
+
+inline void InspectorInstrumentation::didCheckNavigationPolicy(LocalFrame& frame, bool cancel)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    if (auto* agents = instrumentingAgents(frame))
+        didCheckNavigationPolicyImpl(*agents, frame, cancel);
+}
+
 inline InstrumentingAgents* InspectorInstrumentation::instrumentingAgents(ScriptExecutionContext* context)
 {
     return context ? instrumentingAgents(*context) : nullptr;
diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp
index a67a1244fa526ad5759068e97e0d220f59565d6e..0048589109fccb9472fe35a410337771b1063d72 100644
--- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp
+++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.cpp
@@ -50,4 +50,9 @@ void InspectorInstrumentationWebKit::interceptResponseInternal(const LocalFrame&
     InspectorInstrumentation::interceptResponse(frame, response, identifier, WTFMove(handler));
 }
 
+void InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwapInternal(Page* page, bool value)
+{
+    InspectorInstrumentation::setStoppingLoadingDueToProcessSwap(page, value);
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h
index c028341e84e59a6b1b16107fd74feb21f70b12ab..d385418ac34e8f315f201801a2c65226c8f6fee2 100644
--- a/Source/WebCore/inspector/InspectorInstrumentationWebKit.h
+++ b/Source/WebCore/inspector/InspectorInstrumentationWebKit.h
@@ -33,6 +33,7 @@
 namespace WebCore {
 
 class LocalFrame;
+class Page;
 class ResourceLoader;
 class ResourceRequest;
 class ResourceResponse;
@@ -44,12 +45,14 @@ public:
     static bool shouldInterceptResponse(const LocalFrame*, const ResourceResponse&);
     static void interceptRequest(ResourceLoader&, Function<void(const ResourceRequest&)>&&);
     static void interceptResponse(const LocalFrame*, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler<void(const ResourceResponse&, RefPtr<FragmentedSharedBuffer>)>&&);
+    static void setStoppingLoadingDueToProcessSwap(Page*, bool);
 
 private:
     static bool shouldInterceptRequestInternal(const ResourceLoader&);
     static bool shouldInterceptResponseInternal(const LocalFrame&, const ResourceResponse&);
     static void interceptRequestInternal(ResourceLoader&, Function<void(const ResourceRequest&)>&&);
     static void interceptResponseInternal(const LocalFrame&, const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler<void(const ResourceResponse&, RefPtr<FragmentedSharedBuffer>)>&&);
+    static void setStoppingLoadingDueToProcessSwapInternal(Page*, bool);
 };
 
 inline bool InspectorInstrumentationWebKit::shouldInterceptRequest(const ResourceLoader& loader)
@@ -79,4 +82,10 @@ inline void InspectorInstrumentationWebKit::interceptResponse(const LocalFrame*
     interceptResponseInternal(*frame, response, identifier, WTFMove(handler));
 }
 
+inline void InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(Page* page, bool value)
+{
+    FAST_RETURN_IF_NO_FRONTENDS(void());
+    setStoppingLoadingDueToProcessSwapInternal(page, value);
+}
+
 }
diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
index 418700e6fc6432afb3b5091d12ced07a263cccea..a160505c5f419566d2ad83d62f368614dec16ea2 100644
--- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
+++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
@@ -55,6 +55,7 @@
 #include "ContainerNode.h"
 #include "Cookie.h"
 #include "CookieJar.h"
+#include "DirectoryFileListCreator.h"
 #include "DOMEditor.h"
 #include "DOMException.h"
 #include "DOMPatchSupport.h"
@@ -65,10 +66,15 @@
 #include "Event.h"
 #include "EventListener.h"
 #include "EventNames.h"
+#include "File.h"
+#include <FileChooser.h>
+#include "FileList.h"
 #include "FrameTree.h"
 #include "FullscreenManager.h"
+#include "FloatQuad.h"
 #include "HTMLElement.h"
 #include "HTMLFrameOwnerElement.h"
+#include "HTMLInputElement.h"
 #include "HTMLMediaElement.h"
 #include "HTMLNames.h"
 #include "HTMLScriptElement.h"
@@ -102,12 +108,14 @@
 #include "Pasteboard.h"
 #include "PseudoElement.h"
 #include "RenderGrid.h"
+#include "RenderLayer.h"
 #include "RenderObject.h"
 #include "RenderStyle.h"
 #include "RenderStyleConstants.h"
 #include "ScriptController.h"
 #include "SelectorChecker.h"
 #include "ShadowRoot.h"
+#include "SharedBuffer.h"
 #include "StaticNodeList.h"
 #include "StyleProperties.h"
 #include "StyleResolver.h"
@@ -149,7 +157,8 @@ using namespace HTMLNames;
 static const size_t maxTextSize = 10000;
 static const UChar horizontalEllipsisUChar[] = { horizontalEllipsis, 0 };
 
-static std::optional<Color> parseColor(RefPtr<JSON::Object>&& colorObject)
+// static
+std::optional<Color> InspectorDOMAgent::parseColor(RefPtr<JSON::Object>&& colorObject)
 {
     if (!colorObject)
         return std::nullopt;
@@ -168,7 +177,7 @@ static std::optional<Color> parseColor(RefPtr<JSON::Object>&& colorObject)
 
 static std::optional<Color> parseRequiredConfigColor(const String& fieldName, JSON::Object& configObject)
 {
-    return parseColor(configObject.getObject(fieldName));
+    return InspectorDOMAgent::parseColor(configObject.getObject(fieldName));
 }
 
 static Color parseOptionalConfigColor(const String& fieldName, JSON::Object& configObject)
@@ -195,6 +204,20 @@ static bool parseQuad(Ref<JSON::Array>&& quadArray, FloatQuad* quad)
     return true;
 }
 
+static void CollectQuads(Node* node, Vector<FloatQuad>& quads)
+{
+    Element* element = dynamicDowncast<Element>(node);
+    if (element && element->hasDisplayContents()) {
+        // display:contents elements do not render themselves, so we look into children.
+        for (auto& child : composedTreeChildren(*element))
+            CollectQuads(&child, quads);
+        return;
+    }
+    RenderObject* renderer = node->renderer();
+    if (renderer)
+        renderer->absoluteQuads(quads);
+}
+
 class RevalidateStyleAttributeTask final : public CanMakeCheckedPtr<RevalidateStyleAttributeTask> {
     WTF_MAKE_TZONE_ALLOCATED_INLINE(RevalidateStyleAttributeTask);
     WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(RevalidateStyleAttributeTask);
@@ -476,6 +499,20 @@ Node* InspectorDOMAgent::assertNode(Inspector::Protocol::ErrorString& errorStrin
     return node.get();
 }
 
+Node* InspectorDOMAgent::assertNode(Protocol::ErrorString& errorString, std::optional<Protocol::DOM::NodeId>&& nodeId, const String& objectId)
+{
+    Node* node = nullptr;
+    if (nodeId) {
+        node = assertNode(errorString, *nodeId);
+    } else if (!!objectId) {
+        node = nodeForObjectId(objectId);
+        if (!node)
+            errorString = "Missing node for given objectId"_s;
+    } else
+        errorString = "Either nodeId or objectId must be specified"_s;
+    return node;
+}
+
 Document* InspectorDOMAgent::assertDocument(Inspector::Protocol::ErrorString& errorString, Inspector::Protocol::DOM::NodeId nodeId)
 {
     RefPtr node = assertNode(errorString, nodeId);
@@ -1550,16 +1587,7 @@ Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::highlightNode(std::o
 Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::highlightNode(std::optional<Inspector::Protocol::DOM::NodeId>&& nodeId, const Inspector::Protocol::Runtime::RemoteObjectId& objectId, Ref<JSON::Object>&& highlightInspectorObject, RefPtr<JSON::Object>&& gridOverlayInspectorObject, RefPtr<JSON::Object>&& flexOverlayInspectorObject, std::optional<bool>&& showRulers)
 {
     Inspector::Protocol::ErrorString errorString;
-
-    Node* node = nullptr;
-    if (nodeId)
-        node = assertNode(errorString, *nodeId);
-    else if (!!objectId) {
-        node = nodeForObjectId(objectId);
-        errorString = "Missing node for given objectId"_s;
-    } else
-        errorString = "Either nodeId or objectId must be specified"_s;
-
+    Node* node = assertNode(errorString, WTFMove(nodeId), objectId);
     if (!node)
         return makeUnexpected(errorString);
 
@@ -1814,15 +1842,155 @@ Inspector::Protocol::ErrorStringOr<void> InspectorDOMAgent::setInspectedNode(Ins
     return { };
 }
 
-Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::Runtime::RemoteObject>> InspectorDOMAgent::resolveNode(Inspector::Protocol::DOM::NodeId nodeId, const String& objectGroup)
+static FloatPoint contentsToRootView(LocalFrameView& containingView, const FloatPoint& point)
+{
+    return containingView.convertToRootView(point - toFloatSize(containingView.documentScrollPositionRelativeToViewOrigin()));
+}
+
+static void frameQuadToViewport(LocalFrameView& containingView, FloatQuad& quad, 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<Inspector::Protocol::DOM::Quad> 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<JSON::ArrayOf<Inspector::Protocol::DOM::Quad>> buildArrayOfQuads(const Vector<FloatQuad>& quads)
+{
+    auto result = JSON::ArrayOf<Inspector::Protocol::DOM::Quad>::create();
+    for (const auto& quad : quads)
+        result->addItem(buildObjectForQuad(quad));
+    return result;
+}
+
+Inspector::Protocol::ErrorStringOr<std::tuple<String /* contentFrameId */, String /* ownerFrameId */>> 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<HTMLFrameOwnerElement>(*node)) {
+        const auto& frameOwner = downcast<HTMLFrameOwnerElement>(*node);
+        // TODO(playwright): Unnecessary downcast to LocalFrame?
+        String frameId = pageAgent->frameId(dynamicDowncast<LocalFrame>(frameOwner.contentFrame()));
+        if (!frameId.isEmpty())
+            contentFrameId = frameId;
+    }
+
+    return { { contentFrameId, ownerFrameId } };
+}
+
+Protocol::ErrorStringOr<void> InspectorDOMAgent::scrollIntoViewIfNeeded(const String& objectId, RefPtr<JSON::Object>&& rect)
+{
+    Node* node = nodeForObjectId(objectId);
+    if (!node)
+        return makeUnexpected("Node not found"_s);
+
+    m_inspectedPage.isolatedUpdateRendering();
+    if (!node->isConnected())
+        return makeUnexpected("Node is detached from document"_s);
+
+    RenderObject* renderer = node->renderer();
+    auto* containerNode = dynamicDowncast<ContainerNode>(*node);
+    if (!renderer && containerNode) {
+        // Find the first descendant with a renderer, to account for
+        // containers without a renderer like display:contents elements.
+        for (auto& descendant : composedTreeDescendants(*containerNode)) {
+            renderer = descendant.renderer();
+            if (renderer)
+                break;
+        }
+    }
+    if (!renderer)
+        return makeUnexpected("Node does not have a layout object"_s);
+
+    bool insideFixed = false;
+    LayoutRect absoluteBounds = renderer->absoluteBoundingBoxRect(true, &insideFixed);
+    if (rect) {
+        std::optional<double> x = rect->getDouble("x"_s);
+        std::optional<double> y = rect->getDouble("y"_s);
+        std::optional<double> width = rect->getDouble("width"_s);
+        std::optional<double> height = rect->getDouble("height"_s);
+        if (!x || !y || !width || !height)
+            return makeUnexpected("Malformed rect"_s);
+
+        absoluteBounds.setX(absoluteBounds.x() + LayoutUnit(*x));
+        absoluteBounds.setY(absoluteBounds.y() + LayoutUnit(*y));
+        absoluteBounds.setWidth(LayoutUnit(std::max(*width, 1.0)));
+        absoluteBounds.setHeight(LayoutUnit(std::max(*height, 1.0)));
+    }
+    ScrollAlignment alignment = ScrollAlignment::alignCenterIfNeeded;
+    alignment.m_enableLegacyHorizontalVisibilityThreshold = false; // Disable RenderLayer minium horizontal scroll threshold.
+    LocalFrameView::scrollRectToVisible(absoluteBounds, *renderer, insideFixed, { SelectionRevealMode::Reveal, alignment, alignment, ShouldAllowCrossOriginScrolling::Yes, ScrollBehavior::Instant });
+    return { };
+}
+
+Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Protocol::DOM::Quad>>> InspectorDOMAgent::getContentQuads(const String& objectId)
+{
+    Node* node = nodeForObjectId(objectId);
+    if (!node)
+        return makeUnexpected("Node not found"_s);
+
+    // Ensure quads are up to date.
+    m_inspectedPage.isolatedUpdateRendering();
+
+    LocalFrameView* containingView = node->document().view();
+    if (!containingView)
+        return makeUnexpected("Internal error: no containing view"_s);
+
+    Vector<FloatQuad> quads;
+    CollectQuads(node, quads);
+    for (auto& quad : quads)
+        frameQuadToViewport(*containingView, quad, m_inspectedPage.pageScaleFactor());
+    return buildArrayOfQuads(quads);
+}
+
+Inspector::Protocol::ErrorStringOr<Ref<Protocol::Runtime::RemoteObject>> InspectorDOMAgent::resolveNode(std::optional<Inspector::Protocol::DOM::NodeId>&& nodeId, const String& objectId, const Inspector::Protocol::Network::FrameId& frameId, std::optional<int>&& contextId, const String& objectGroup)
 {
     Inspector::Protocol::ErrorString errorString;
+    Node* node = nullptr;
+    if (!!frameId) {
+        auto* pageAgent = m_instrumentingAgents.enabledPageAgent();
+        if (!pageAgent)
+            return makeUnexpected("Page domain must be enabled"_s);
 
-    Node* node = assertNode(errorString, nodeId);
+        auto* frame = pageAgent->assertFrame(errorString, frameId);
+        if (!frame)
+            return makeUnexpected(errorString);
+
+        node = frame->ownerElement();
+    } else {
+        node = assertNode(errorString, WTFMove(nodeId), objectId);
+    }
     if (!node)
         return makeUnexpected(errorString);
 
-    auto object = resolveNode(node, objectGroup);
+    auto object = resolveNode(node, objectGroup, WTFMove(contextId));
     if (!object)
         return makeUnexpected("Missing injected script for given nodeId"_s);
 
@@ -3088,7 +3256,7 @@ Inspector::Protocol::ErrorStringOr<Inspector::Protocol::DOM::NodeId> InspectorDO
     return makeUnexpected("Missing node for given path"_s);
 }
 
-RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup)
+RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNode(Node* node, const String& objectGroup, std::optional<int>&& contextId)
 {
     Document* document = &node->document();
     if (auto* templateHost = document->templateDocumentHost())
@@ -3097,12 +3265,18 @@ RefPtr<Inspector::Protocol::Runtime::RemoteObject> InspectorDOMAgent::resolveNod
     if (!frame)
         return nullptr;
 
-    auto& globalObject = mainWorldGlobalObject(*frame);
-    auto injectedScript = m_injectedScriptManager.injectedScriptFor(&globalObject);
+    InjectedScript injectedScript;
+    if (contextId) {
+        injectedScript = m_injectedScriptManager.injectedScriptForId(*contextId);
+    } else {
+        auto& globalObject = mainWorldGlobalObject(*frame);
+        injectedScript = m_injectedScriptManager.injectedScriptFor(&globalObject);
+    }
+
     if (injectedScript.hasNoValue())
         return nullptr;
 
-    return injectedScript.wrapObject(nodeAsScriptValue(globalObject, node), objectGroup);
+    return injectedScript.wrapObject(nodeAsScriptValue(*injectedScript.globalObject(), node), objectGroup);
 }
 
 Node* InspectorDOMAgent::scriptValueAsNode(JSC::JSValue value)
@@ -3210,4 +3384,89 @@ Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::DOM::MediaStats>> In
 #endif
 }
 
+void InspectorDOMAgent::setInputFiles(const String& objectId, RefPtr<JSON::Array>&& files, RefPtr<JSON::Array>&& paths, Ref<SetInputFilesCallback>&& callback) {
+    InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(objectId);
+    if (injectedScript.hasNoValue()) {
+        callback->sendFailure("Can not find element's context for given id"_s);
+        return;
+    }
+
+    Node* node = scriptValueAsNode(injectedScript.findObjectById(objectId));
+    if (!node) {
+        callback->sendFailure("Can not find element for given id"_s);
+        return;
+    }
+
+    if (node->nodeType() != Node::ELEMENT_NODE || node->nodeName() != "INPUT"_s) {
+        callback->sendFailure("Not an input node"_s);
+        return;
+    }
+
+    if (!(bool(files) ^ bool(paths))) {
+        callback->sendFailure("Exactly one of files and paths should be specified"_s);
+        return;
+    }
+
+    HTMLInputElement* element = static_cast<HTMLInputElement*>(node);
+    Vector<Ref<File>> fileObjects;
+    if (files) {
+        for (unsigned i = 0; i < files->length(); ++i) {
+            RefPtr<JSON::Value> item = files->get(i);
+            RefPtr<JSON::Object> obj = item->asObject();
+            if (!obj) {
+                callback->sendFailure("Invalid file payload format"_s);
+                return;
+            }
+
+            String name;
+            String type;
+            String data;
+            if (!obj->getString("name"_s, name) || !obj->getString("type"_s, type) || !obj->getString("data"_s, data)) {
+                callback->sendFailure("Invalid file payload format"_s);
+                return;
+            }
+
+            std::optional<Vector<uint8_t>> buffer = base64Decode(data);
+            if (!buffer) {
+                callback->sendFailure("Unable to decode given content"_s);
+                return;
+            }
+
+            ScriptExecutionContext* context = element->scriptExecutionContext();
+            fileObjects.append(File::create(context, Blob::create(context, WTFMove(*buffer), type), name));
+        }
+        RefPtr<FileList> fileList = FileList::create(WTFMove(fileObjects));
+        element->setFiles(WTFMove(fileList));
+        callback->sendSuccess();
+    } else {
+        if (element->hasAttributeWithoutSynchronization(webkitdirectoryAttr)) {
+            auto directoryFileListCreator = DirectoryFileListCreator::create([element = RefPtr { element }, callback = WTFMove(callback)](Ref<FileList>&& fileList) mutable {
+                ASSERT(isMainThread());
+                element->setFiles(WTFMove(fileList));
+                callback->sendSuccess();
+            });
+            Vector<FileChooserFileInfo> fileChooserFiles;
+            for (size_t i = 0; i < paths->length(); ++i) {
+                fileChooserFiles.append(FileChooserFileInfo { paths->get(i)->asString(), nullString(), { } });
+            }
+            directoryFileListCreator->start(m_document.get(), fileChooserFiles);
+        } else {
+            for (unsigned i = 0; i < paths->length(); ++i) {
+                RefPtr<JSON::Value> item = paths->get(i);
+                String path = item->asString();
+                if (path.isEmpty()) {
+                    callback->sendFailure("Invalid file path"_s);
+                    return;
+                }
+
+                ScriptExecutionContext* context = element->scriptExecutionContext();
+                fileObjects.append(File::create(context, path));
+            }
+            RefPtr<FileList> fileList = FileList::create(WTFMove(fileObjects));
+            element->setFiles(WTFMove(fileList));
+            callback->sendSuccess();
+        }
+    }
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h
index ab0499c5e381855f55fa89227f4da05c7bcf40b1..e506a903ba60173b47135d5b18cfa0d3cdd8783e 100644
--- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h
+++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h
@@ -59,6 +59,7 @@ namespace WebCore {
 
 class AXCoreObject;
 class CharacterData;
+class Color;
 class DOMEditor;
 class Document;
 class Element;
@@ -94,6 +95,7 @@ public:
     static String toErrorString(Exception&&);
 
     static String documentURLString(Document*);
+    static std::optional<Color> parseColor(RefPtr<JSON::Object>&&);
 
     // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently.
     // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics.
@@ -137,7 +139,7 @@ public:
     Inspector::Protocol::ErrorStringOr<std::tuple<String /* searchId */, int /* resultCount */>> performSearch(const String& query, RefPtr<JSON::Array>&& nodeIds, std::optional<bool>&& caseSensitive);
     Inspector::Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Inspector::Protocol::DOM::NodeId>>> getSearchResults(const String& searchId, int fromIndex, int toIndex);
     Inspector::Protocol::ErrorStringOr<void> discardSearchResults(const String& searchId);
-    Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::Runtime::RemoteObject>> resolveNode(Inspector::Protocol::DOM::NodeId, const String& objectGroup);
+    Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::Runtime::RemoteObject>> resolveNode(std::optional<Inspector::Protocol::DOM::NodeId>&& nodeId, const String& objectId, const Inspector::Protocol::Network::FrameId& frameId, std::optional<int>&& contextId, const String& objectGroup);
     Inspector::Protocol::ErrorStringOr<Ref<JSON::ArrayOf<String>>> getAttributes(Inspector::Protocol::DOM::NodeId);
 #if PLATFORM(IOS_FAMILY)
     Inspector::Protocol::ErrorStringOr<void> setInspectModeEnabled(bool, RefPtr<JSON::Object>&& highlightConfig, RefPtr<JSON::Object>&& gridOverlayConfig, RefPtr<JSON::Object>&& flexOverlayConfig);
@@ -174,6 +176,10 @@ public:
     Inspector::Protocol::ErrorStringOr<void> setInspectedNode(Inspector::Protocol::DOM::NodeId);
     Inspector::Protocol::ErrorStringOr<void> setAllowEditingUserAgentShadowTrees(bool);
     Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::DOM::MediaStats>> getMediaStats(Inspector::Protocol::DOM::NodeId);
+    Inspector::Protocol::ErrorStringOr<std::tuple<String /* contentFrameId */, String /* ownerFrameId */>> describeNode(const String& objectId);
+    Inspector::Protocol::ErrorStringOr<void> scrollIntoViewIfNeeded(const String& objectId, RefPtr<JSON::Object>&& rect);
+    Inspector::Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Inspector::Protocol::DOM::Quad>>> getContentQuads(const String& objectId);
+    void setInputFiles(const String& objectId, RefPtr<JSON::Array>&& files, RefPtr<JSON::Array>&& paths, Ref<SetInputFilesCallback>&& callback);
 
     // InspectorInstrumentation
     Inspector::Protocol::DOM::NodeId identifierForNode(Node&);
@@ -215,7 +221,7 @@ public:
     Node* nodeForId(Inspector::Protocol::DOM::NodeId);
     Inspector::Protocol::DOM::NodeId boundNodeId(const Node*);
 
-    RefPtr<Inspector::Protocol::Runtime::RemoteObject> resolveNode(Node*, const String& objectGroup);
+    RefPtr<Inspector::Protocol::Runtime::RemoteObject> resolveNode(Node*, const String& objectGroup, std::optional<int>&& contextId);
     bool handleMousePress();
     void mouseDidMoveOverElement(const HitTestResult&, OptionSet<PlatformEventModifier>);
     void inspect(Node*);
@@ -227,12 +233,15 @@ public:
     void reset();
 
     Node* assertNode(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId);
+    Node* assertNode(Inspector::Protocol::ErrorString&, std::optional<Inspector::Protocol::DOM::NodeId>&& nodeId, const String& objectId);
     Element* assertElement(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId);
     Document* assertDocument(Inspector::Protocol::ErrorString&, Inspector::Protocol::DOM::NodeId);
 
     RefPtr<JSC::Breakpoint> 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();
@@ -262,7 +271,6 @@ private:
     void processAccessibilityChildren(AXCoreObject&, JSON::ArrayOf<Inspector::Protocol::DOM::NodeId>&);
     
     Node* nodeForPath(const String& path);
-    Node* nodeForObjectId(const Inspector::Protocol::Runtime::RemoteObjectId&);
 
     void discardBindings();
 
diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp
index fb89241329b3d1c4ae05c985070b27f2c360ccf6..442a3d263b6ec7e72ff60ec0d3507d96ed5642eb 100644
--- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp
+++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp
@@ -59,6 +59,7 @@
 #include "MIMETypeRegistry.h"
 #include "MemoryCache.h"
 #include "NetworkResourcesData.h"
+#include "NetworkStateNotifier.h"
 #include "Page.h"
 #include "PlatformStrategies.h"
 #include "ProgressTracker.h"
@@ -345,8 +346,8 @@ static Ref<Inspector::Protocol::Network::Request> buildObjectForResourceRequest(
         .release();
 
     if (request.httpBody() && !request.httpBody()->isEmpty()) {
-        auto bytes = request.httpBody()->flatten();
-        requestObject->setPostData(String::fromUTF8WithLatin1Fallback(bytes.span()));
+        Vector<uint8_t> bytes = request.httpBody()->flatten();
+        requestObject->setPostData(base64EncodeToString(bytes));
     }
 
     if (resourceLoader) {
@@ -399,6 +400,8 @@ RefPtr<Inspector::Protocol::Network::Response> InspectorNetworkAgent::buildObjec
         .setSource(responseSource(response.source()))
         .release();
 
+    responseObject->setRequestHeaders(buildObjectForHeaders(response.m_httpRequestHeaderFields));
+
     if (resourceLoader) {
         auto* metrics = response.deprecatedNetworkLoadMetricsOrNull();
         responseObject->setTiming(buildObjectForTiming(metrics ? *metrics : NetworkLoadMetrics::emptyMetrics(), *resourceLoader));
@@ -685,6 +688,9 @@ void InspectorNetworkAgent::didFailLoading(ResourceLoaderIdentifier identifier,
     String requestId = IdentifiersFactory::requestId(identifier.toUInt64());
 
     if (loader && m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
+        if (m_stoppingLoadingDueToProcessSwap)
+            return;
+
         auto* frame = loader->frame();
         if (frame && frame->loader().documentLoader() && frame->document()) {
             m_resourcesData->addResourceSharedBuffer(requestId,
@@ -914,6 +920,7 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::disable()
     m_instrumentingAgents.setEnabledNetworkAgent(nullptr);
     m_resourcesData->clear();
     m_extraRequestHeaders.clear();
+    m_stoppingLoadingDueToProcessSwap = false;
 
     continuePendingRequests();
     continuePendingResponses();
@@ -966,6 +973,7 @@ void InspectorNetworkAgent::continuePendingResponses()
 
 Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::setExtraHTTPHeaders(Ref<JSON::Object>&& headers)
 {
+    m_extraRequestHeaders.clear();
     for (auto& entry : headers.get()) {
         auto stringValue = entry.value->asString();
         if (!!stringValue)
@@ -1215,6 +1223,11 @@ void InspectorNetworkAgent::interceptResponse(const ResourceResponse& response,
     m_frontendDispatcher->responseIntercepted(requestId, resourceResponse.releaseNonNull());
 }
 
+void InspectorNetworkAgent::setStoppingLoadingDueToProcessSwap(bool stopping)
+{
+    m_stoppingLoadingDueToProcessSwap = stopping;
+}
+
 Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptContinue(const Inspector::Protocol::Network::RequestId& requestId, Inspector::Protocol::Network::NetworkStage networkStage)
 {
     switch (networkStage) {
@@ -1244,6 +1257,9 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptWithReq
         return makeUnexpected("Missing pending intercept request for given requestId"_s);
 
     auto& loader = *pendingRequest->m_loader;
+    if (loader.reachedTerminalState())
+        return makeUnexpected("Unable to intercept request, it has already been processed"_s);
+
     ResourceRequest request = loader.request();
     if (!!url)
         request.setURL(URL({ }, url));
@@ -1339,14 +1355,23 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::interceptRequest
     response.setHTTPStatusCode(status);
     response.setHTTPStatusText(String { statusText });
     HTTPHeaderMap explicitHeaders;
+    String setCookieValue;
     for (auto& header : headers.get()) {
         auto headerValue = header.value->asString();
-        if (!!headerValue)
+        if (equalIgnoringASCIICase(header.key, "Set-Cookie"_s))
+            setCookieValue = headerValue;
+        else if (!!headerValue)
             explicitHeaders.add(header.key, headerValue);
+
     }
     response.setHTTPHeaderFields(WTFMove(explicitHeaders));
     response.setHTTPHeaderField(HTTPHeaderName::ContentType, response.mimeType());
-    loader->didReceiveResponse(response, [loader, buffer = data.releaseNonNull()]() {
+
+    auto* frame = loader->frame();
+    if (!setCookieValue.isEmpty() && frame && frame->page())
+        frame->page()->cookieJar().setCookieFromResponse(*loader.get(), setCookieValue);
+
+    loader->didReceiveResponse(response, [loader, buffer = data.releaseNonNull()]() mutable {
         if (loader->reachedTerminalState())
             return;
 
@@ -1409,6 +1434,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::setEmulatedCondi
 
 #endif // ENABLE(INSPECTOR_NETWORK_THROTTLING)
 
+Inspector::Protocol::ErrorStringOr<void> InspectorNetworkAgent::setEmulateOfflineState(bool offline)
+{
+    platformStrategies()->loaderStrategy()->setEmulateOfflineState(offline);
+    return { };
+}
+
 bool InspectorNetworkAgent::shouldTreatAsText(const String& mimeType)
 {
     return startsWithLettersIgnoringASCIICase(mimeType, "text/"_s)
diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h
index eda400879afb10b687fcbb317c9fdbb3be9c94cd..f3a382c44b53e6b1507fc046e22bff684abd55f9 100644
--- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h
+++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h
@@ -34,6 +34,8 @@
 #include "InspectorInstrumentation.h"
 #include "InspectorPageAgent.h"
 #include "InspectorWebAgentBase.h"
+#include "ResourceError.h"
+#include "SharedBuffer.h"
 #include "WebSocket.h"
 #include <JavaScriptCore/InspectorBackendDispatchers.h>
 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
@@ -102,6 +104,7 @@ public:
 #if ENABLE(INSPECTOR_NETWORK_THROTTLING)
     Inspector::Protocol::ErrorStringOr<void> setEmulatedConditions(std::optional<int>&& bytesPerSecondLimit) final;
 #endif
+    Inspector::Protocol::ErrorStringOr<void> setEmulateOfflineState(bool offline) final;
 
     // InspectorInstrumentation
     void willRecalculateStyle();
@@ -133,6 +136,7 @@ public:
     bool shouldInterceptResponse(const ResourceResponse&);
     void interceptResponse(const ResourceResponse&, ResourceLoaderIdentifier, CompletionHandler<void(const ResourceResponse&, RefPtr<FragmentedSharedBuffer>)>&&);
     void interceptRequest(ResourceLoader&, Function<void(const ResourceRequest&)>&&);
+    void setStoppingLoadingDueToProcessSwap(bool);
 
     void searchOtherRequests(const JSC::Yarr::RegularExpression&, Ref<JSON::ArrayOf<Inspector::Protocol::Page::SearchResult>>&);
     void searchInRequest(Inspector::Protocol::ErrorString&, const Inspector::Protocol::Network::RequestId&, const String& query, bool caseSensitive, bool isRegex, RefPtr<JSON::ArrayOf<Inspector::Protocol::GenericTypes::SearchMatch>>&);
@@ -259,6 +263,7 @@ private:
     bool m_enabled { false };
     bool m_loadingXHRSynchronously { false };
     bool m_interceptionEnabled { false };
+    bool m_stoppingLoadingDueToProcessSwap { false };
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp
index 4393f2d882d6fc829ce69115e6f5e6db93eee1a6..9e58595296aaa3770ad660515e362c7045ad6082 100644
--- a/Source/WebCore/inspector/agents/InspectorPageAgent.cpp
+++ b/Source/WebCore/inspector/agents/InspectorPageAgent.cpp
@@ -32,19 +32,27 @@
 #include "config.h"
 #include "InspectorPageAgent.h"
 
+#include "AXCoreObject.h"
+#include "AXObjectCache.h"
+#include "BackForwardController.h"
 #include "CachedResource.h"
 #include "CachedResourceLoader.h"
 #include "Cookie.h"
 #include "CookieJar.h"
+#include "CustomHeaderFields.h"
 #include "DOMWrapperWorld.h"
 #include "DocumentInlines.h"
 #include "DocumentLoader.h"
+#include "Editor.h"
 #include "ElementInlines.h"
+#include "FocusController.h"
 #include "ForcedAccessibilityValue.h"
 #include "FrameLoadRequest.h"
 #include "FrameLoader.h"
+#include "FrameLoaderClient.h"
 #include "FrameSnapshotting.h"
 #include "HTMLFrameOwnerElement.h"
+#include "HTMLInputElement.h"
 #include "HTMLNames.h"
 #include "ImageBuffer.h"
 #include "InspectorClient.h"
@@ -57,8 +65,12 @@
 #include "MIMETypeRegistry.h"
 #include "MemoryCache.h"
 #include "Page.h"
+#include "PageRuntimeAgent.h"
+#include "PlatformScreen.h"
 #include "RenderObject.h"
 #include "RenderTheme.h"
+#include "DeprecatedGlobalSettings.h"
+#include "SimpleRange.h"
 #include "ScriptController.h"
 #include "ScriptSourceCode.h"
 #include "SecurityOrigin.h"
@@ -66,14 +78,23 @@
 #include "StyleScope.h"
 #include "Theme.h"
 #include <pal/text/TextEncoding.h>
+#include "TextIterator.h"
+#include "TypingCommand.h"
 #include "UserGestureIndicator.h"
 #include <JavaScriptCore/ContentSearchUtilities.h>
 #include <JavaScriptCore/IdentifiersFactory.h>
+#include <JavaScriptCore/InjectedScriptManager.h>
 #include <JavaScriptCore/RegularExpression.h>
+#include <wtf/DateMath.h>
 #include <wtf/ListHashSet.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/ObjectIdentifier.h>
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
 #include <wtf/Stopwatch.h>
 #include <wtf/TZoneMallocInlines.h>
 #include <wtf/text/Base64.h>
+#include <wtf/text/MakeString.h>
 #include <wtf/text/StringBuilder.h>
 
 #if ENABLE(APPLICATION_MANIFEST)
@@ -95,6 +116,11 @@ using namespace Inspector;
 
 WTF_MAKE_TZONE_ALLOCATED_IMPL(InspectorPageAgent);
 
+static UncheckedKeyHashMap<String, Ref<DOMWrapperWorld>>& createdUserWorlds() {
+    static NeverDestroyed<UncheckedKeyHashMap<String, Ref<DOMWrapperWorld>>> nameToWorld;
+    return nameToWorld;
+}
+
 static bool decodeBuffer(std::span<const uint8_t> buffer, const String& textEncodingName, String* result)
 {
     if (buffer.data()) {
@@ -347,6 +373,7 @@ InspectorPageAgent::InspectorPageAgent(PageAgentContext& context, InspectorClien
     , m_frontendDispatcher(makeUnique<Inspector::PageFrontendDispatcher>(context.frontendRouter))
     , m_backendDispatcher(Inspector::PageBackendDispatcher::create(context.backendDispatcher, this))
     , m_inspectedPage(context.inspectedPage)
+    , m_injectedScriptManager(context.injectedScriptManager)
     , m_client(client)
     , m_overlay(overlay)
 {
@@ -376,12 +403,20 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::enable()
 
     defaultUserPreferencesDidChange();
 
+    if (!createdUserWorlds().isEmpty()) {
+        Vector<DOMWrapperWorld*> worlds;
+        for (const auto& world : createdUserWorlds().values())
+            worlds.append(world.ptr());
+        ensureUserWorldsExistInAllFrames(worlds);
+    }
     return { };
 }
 
 Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::disable()
 {
     m_instrumentingAgents.setEnabledPageAgent(nullptr);
+    m_interceptFileChooserDialog = false;
+    m_bypassCSP = false;
 
     setShowPaintRects(false);
 #if !PLATFORM(IOS_FAMILY)
@@ -434,6 +469,22 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::reload(std::optiona
     return { };
 }
 
+Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::goBack()
+{
+    if (!m_inspectedPage.backForward().goBack())
+        return makeUnexpected("Failed to go back"_s);
+
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::goForward()
+{
+    if (!m_inspectedPage.backForward().goForward())
+        return makeUnexpected("Failed to go forward"_s);
+
+    return { };
+}
+
 Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::navigate(const String& url)
 {
     auto* localMainFrame = dynamicDowncast<LocalFrame>(m_inspectedPage.mainFrame());
@@ -457,6 +508,13 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideUserAgent(c
     return { };
 }
 
+Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overridePlatform(const String& value)
+{
+    m_platformOverride = value;
+
+    return { };
+}
+
 Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Inspector::Protocol::Page::Setting setting, std::optional<bool>&& value)
 {
     auto& inspectedPageSettings = m_inspectedPage.settings();
@@ -470,6 +528,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins
         inspectedPageSettings.setAuthorAndUserStylesEnabledInspectorOverride(value);
         return { };
 
+#if ENABLE(DEVICE_ORIENTATION)
+    case Protocol::Page::Setting::DeviceOrientationEventEnabled:
+        inspectedPageSettings.setDeviceOrientationEventEnabled(value.value_or(false));
+        return { };
+#endif
+
     case Inspector::Protocol::Page::Setting::ICECandidateFilteringEnabled:
         inspectedPageSettings.setICECandidateFilteringEnabledInspectorOverride(value);
         return { };
@@ -496,6 +560,45 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins
         m_client->setDeveloperPreferenceOverride(InspectorClient::DeveloperPreference::NeedsSiteSpecificQuirks, value);
         return { };
 
+#if ENABLE(NOTIFICATIONS)
+    case Protocol::Page::Setting::NotificationsEnabled:
+        inspectedPageSettings.setNotificationsEnabled(value.value_or(false));
+        return { };
+#endif
+
+#if ENABLE(FULLSCREEN_API)
+    case Protocol::Page::Setting::FullScreenEnabled:
+        inspectedPageSettings.setFullScreenEnabled(value.value_or(false));
+        return { };
+#endif
+
+    case Protocol::Page::Setting::InputTypeMonthEnabled:
+// Playwright client sends it even if it's not supported.
+#if ENABLE(INPUT_TYPE_MONTH)
+        inspectedPageSettings.setInputTypeMonthEnabled(value.value_or(false));
+#endif
+        return { };
+
+    case Protocol::Page::Setting::InputTypeWeekEnabled:
+// Playwright client sends it even if it's not supported.
+#if ENABLE(INPUT_TYPE_WEEK)
+        inspectedPageSettings.setInputTypeWeekEnabled(value.value_or(false));
+#endif
+        return { };
+
+    case Protocol::Page::Setting::FixedBackgroundsPaintRelativeToDocument:
+        // Enable this setting similar to iOS to ensure scrolling works with
+        // `background-attachment: fixed`.
+        // See https://github.com/microsoft/playwright/issues/31551.
+        inspectedPageSettings.setFixedBackgroundsPaintRelativeToDocument(value.value_or(false));
+        return { };
+
+#if ENABLE(POINTER_LOCK)
+    case Protocol::Page::Setting::PointerLockEnabled:
+        inspectedPageSettings.setPointerLockEnabled(value.value_or(false));
+        return { };
+#endif
+
     case Inspector::Protocol::Page::Setting::ScriptEnabled:
         inspectedPageSettings.setScriptEnabledInspectorOverride(value);
         return { };
@@ -508,6 +611,12 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::overrideSetting(Ins
         inspectedPageSettings.setShowRepaintCounterInspectorOverride(value);
         return { };
 
+#if ENABLE(MEDIA_STREAM)
+    case Protocol::Page::Setting::SpeechRecognitionEnabled:
+        inspectedPageSettings.setSpeechRecognitionEnabled(value.value_or(false));
+        return { };
+#endif
+
     case Inspector::Protocol::Page::Setting::WebSecurityEnabled:
         inspectedPageSettings.setWebSecurityEnabledInspectorOverride(value);
         return { };
@@ -908,15 +1017,16 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setShowPaintRects(b
     return { };
 }
 
-void InspectorPageAgent::domContentEventFired()
+void InspectorPageAgent::domContentEventFired(LocalFrame& frame)
 {
-    m_isFirstLayoutAfterOnLoad = true;
-    m_frontendDispatcher->domContentEventFired(timestamp());
+    if (frame.isMainFrame())
+        m_isFirstLayoutAfterOnLoad = true;
+    m_frontendDispatcher->domContentEventFired(timestamp(), frameId(&frame));
 }
 
-void InspectorPageAgent::loadEventFired()
+void InspectorPageAgent::loadEventFired(LocalFrame& frame)
 {
-    m_frontendDispatcher->loadEventFired(timestamp());
+    m_frontendDispatcher->loadEventFired(timestamp(), frameId(&frame));
 }
 
 void InspectorPageAgent::frameNavigated(LocalFrame& frame)
@@ -924,13 +1034,38 @@ void InspectorPageAgent::frameNavigated(LocalFrame& frame)
     m_frontendDispatcher->frameNavigated(buildObjectForFrame(&frame));
 }
 
+String InspectorPageAgent::serializeFrameID(FrameIdentifier frameID)
+{
+    return makeString(frameID.processIdentifier().toUInt64(), '.', frameID.object().toUInt64());
+}
+
+std::optional<FrameIdentifier> InspectorPageAgent::parseFrameID(String frameID)
+{
+    size_t dotPos = frameID.find("."_s);
+    if (dotPos == notFound)
+        return std::nullopt;
+
+    if (!frameID.containsOnlyASCII())
+        return std::nullopt;
+
+    String processIDString = frameID.left(dotPos);
+    uint64_t pid = strtoull(processIDString.ascii().data(), 0, 10);
+    auto processID = ObjectIdentifier<WebCore::ProcessIdentifierType>(pid);
+    String frameIDString = frameID.substring(dotPos + 1);
+    uint64_t frameIDNumber = strtoull(frameIDString.ascii().data(), 0, 10);
+    return WebCore::FrameIdentifier {
+       ObjectIdentifier<WebCore::FrameIdentifierType>(frameIDNumber),
+       processID
+    };
+}
+
 void InspectorPageAgent::frameDetached(LocalFrame& frame)
 {
-    auto identifier = m_frameToIdentifier.take(frame);
-    if (identifier.isNull())
+    String identifier = serializeFrameID(frame.frameID());
+    if (!m_identifierToFrame.take(identifier))
         return;
+
     m_frontendDispatcher->frameDetached(identifier);
-    m_identifierToFrame.remove(identifier);
 }
 
 Frame* InspectorPageAgent::frameForId(const Inspector::Protocol::Network::FrameId& frameId)
@@ -942,20 +1077,21 @@ String InspectorPageAgent::frameId(Frame* frame)
 {
     if (!frame)
         return emptyString();
-    return m_frameToIdentifier.ensure(*frame, [this, frame] {
-        auto identifier = IdentifiersFactory::createIdentifier();
-        m_identifierToFrame.set(identifier, frame);
-        return identifier;
-    }).iterator->value;
+    String identifier = serializeFrameID(frame->frameID());
+    m_identifierToFrame.set(identifier, frame);
+    return identifier;
 }
 
 String InspectorPageAgent::loaderId(DocumentLoader* loader)
 {
     if (!loader)
         return emptyString();
-    return m_loaderToIdentifier.ensure(loader, [] {
-        return IdentifiersFactory::createIdentifier();
-    }).iterator->value;
+
+    auto navigationID = loader->navigationID();
+    if (!navigationID)
+        return emptyString();
+
+    return String::number(navigationID->toUInt64());
 }
 
 LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& errorString, const Inspector::Protocol::Network::FrameId& frameId)
@@ -966,11 +1102,6 @@ LocalFrame* InspectorPageAgent::assertFrame(Inspector::Protocol::ErrorString& er
     return frame;
 }
 
-void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader& loader)
-{
-    m_loaderToIdentifier.remove(&loader);
-}
-
 void InspectorPageAgent::frameStartedLoading(LocalFrame& frame)
 {
     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
@@ -981,9 +1112,9 @@ void InspectorPageAgent::frameStoppedLoading(LocalFrame& frame)
     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
 }
 
-void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay)
+void InspectorPageAgent::frameScheduledNavigation(Frame& frame, Seconds delay, bool targetIsCurrentFrame)
 {
-    m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value());
+    m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay.value(), targetIsCurrentFrame);
 }
 
 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
@@ -1030,6 +1161,12 @@ void InspectorPageAgent::defaultUserPreferencesDidChange()
     m_frontendDispatcher->defaultUserPreferencesDidChange(WTFMove(defaultUserPreferences));
 }
 
+void InspectorPageAgent::didNavigateWithinPage(LocalFrame& frame)
+{
+    String url = frame.document()->url().string();
+    m_frontendDispatcher->navigatedWithinDocument(frameId(&frame), url);
+}
+
 #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT)
 void InspectorPageAgent::defaultAppearanceDidChange()
 {
@@ -1043,6 +1180,9 @@ void InspectorPageAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapp
         return;
 
     if (m_bootstrapScript.isEmpty())
+       return;
+
+    if (m_ignoreDidClearWindowObject)
         return;
 
     frame.script().evaluateIgnoringException(ScriptSourceCode(m_bootstrapScript, JSC::SourceTaintedOrigin::Untainted, URL { "web-inspector://bootstrap.js"_str }));
@@ -1090,6 +1230,51 @@ void InspectorPageAgent::didRecalculateStyle()
     protectedOverlay()->update();
 }
 
+void InspectorPageAgent::runOpenPanel(HTMLInputElement* element, bool* intercept)
+{
+    if (m_interceptFileChooserDialog) {
+        *intercept = true;
+    } else {
+        return;
+    }
+    Document& document = element->document();
+    auto* frame =  document.frame();
+    if (!frame)
+        return;
+
+    auto& globalObject = mainWorldGlobalObject(*frame);
+    auto injectedScript = m_injectedScriptManager.injectedScriptFor(&globalObject);
+    if (injectedScript.hasNoValue())
+        return;
+
+    auto object = injectedScript.wrapObject(InspectorDOMAgent::nodeAsScriptValue(globalObject, element), WTF::String());
+    if (!object)
+        return;
+
+    m_frontendDispatcher->fileChooserOpened(frameId(frame), object.releaseNonNull());
+}
+
+void InspectorPageAgent::frameAttached(LocalFrame& frame)
+{
+    String parentFrameId = frameId(dynamicDowncast<LocalFrame>(frame.tree().parent()));
+    m_frontendDispatcher->frameAttached(frameId(&frame), parentFrameId);
+}
+
+bool InspectorPageAgent::shouldBypassCSP()
+{
+    return m_bypassCSP;
+}
+
+void InspectorPageAgent::willCheckNavigationPolicy(LocalFrame& frame)
+{
+    m_frontendDispatcher->willCheckNavigationPolicy(frameId(&frame));
+}
+
+void InspectorPageAgent::didCheckNavigationPolicy(LocalFrame& frame, bool cancel)
+{
+    m_frontendDispatcher->didCheckNavigationPolicy(frameId(&frame), cancel);
+}
+
 Ref<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(LocalFrame* frame)
 {
     ASSERT_ARG(frame, frame);
@@ -1187,6 +1372,12 @@ void InspectorPageAgent::applyUserAgentOverride(String& userAgent)
         userAgent = m_userAgentOverride;
 }
 
+void InspectorPageAgent::applyPlatformOverride(String& platform)
+{
+    if (!m_platformOverride.isEmpty())
+        platform = m_platformOverride;
+}
+
 void InspectorPageAgent::applyEmulatedMedia(AtomString& media)
 {
     if (!m_emulatedMedia.isEmpty())
@@ -1214,11 +1405,13 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotNode(Insp
     return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes);
 }
 
-Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem coordinateSystem)
+Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem coordinateSystem, std::optional<bool>&& omitDeviceScaleFactor)
 {
     SnapshotOptions options { { }, ImageBufferPixelFormat::BGRA8, DestinationColorSpace::SRGB() };
     if (coordinateSystem == Inspector::Protocol::Page::CoordinateSystem::Viewport)
         options.flags.add(SnapshotFlags::InViewCoordinates);
+    if (omitDeviceScaleFactor.has_value() && *omitDeviceScaleFactor)
+        options.flags.add(SnapshotFlags::OmitDeviceScaleFactor);
 
     IntRect rectangle(x, y, width, height);
     auto* localMainFrame = dynamicDowncast<LocalFrame>(m_inspectedPage.mainFrame());
@@ -1232,6 +1425,43 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::snapshotRect(int
     return snapshot->toDataURL("image/png"_s, std::nullopt, PreserveResolution::Yes);
 }
 
+Protocol::ErrorStringOr<void> InspectorPageAgent::setForcedColors(std::optional<Protocol::Page::ForcedColors>&& forcedColors)
+{
+    if (!forcedColors) {
+        m_inspectedPage.setUseForcedColorsOverride(std::nullopt);
+        return { };
+    }
+
+    switch (*forcedColors) {
+        case Protocol::Page::ForcedColors::Active:
+            m_inspectedPage.setUseForcedColorsOverride(true);
+            return { };
+        case Protocol::Page::ForcedColors::None:
+            m_inspectedPage.setUseForcedColorsOverride(false);
+            return { };
+    }
+
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::setTimeZone(const String& timeZone)
+{
+    bool success = WTF::setTimeZoneOverride(timeZone);
+    if (!success)
+        return makeUnexpected(makeString("Invalid time zone "_s, timeZone));
+
+    return { };
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::setTouchEmulationEnabled(bool enabled)
+{
+  setScreenHasTouchDeviceOverride(enabled);
+  m_inspectedPage.settings().setTouchEventDOMAttributesEnabled(enabled);
+  return { };
+}
+
+
 #if ENABLE(WEB_ARCHIVE) && USE(CF)
 Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::archive()
 {
@@ -1248,7 +1478,6 @@ Inspector::Protocol::ErrorStringOr<String> InspectorPageAgent::archive()
 }
 #endif
 
-#if !PLATFORM(COCOA)
 Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setScreenSizeOverride(std::optional<int>&& width, std::optional<int>&& height)
 {
     if (width.has_value() != height.has_value())
@@ -1266,6 +1495,498 @@ Inspector::Protocol::ErrorStringOr<void> InspectorPageAgent::setScreenSizeOverri
     localMainFrame->setOverrideScreenSize(FloatSize(width.value_or(0), height.value_or(0)));
     return { };
 }
-#endif
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::insertText(const String& text)
+{
+    UserGestureIndicator indicator { IsProcessingUserGesture::Yes };
+    RefPtr frame = m_inspectedPage.checkedFocusController()->focusedOrMainFrame();
+    if (!frame)
+        return { };
+
+    if (frame->editor().hasComposition()) {
+        frame->editor().confirmComposition(text);
+    } else {
+        Document* focusedDocument = frame->document();
+        TypingCommand::insertText(*focusedDocument, text, { });
+    }
+    return { };
+}
+
+static String roleFromObject(RefPtr<AXCoreObject> axObject)
+{
+    String computedRoleString = axObject->computedRoleString();
+    if (!computedRoleString.isEmpty())
+        return computedRoleString;
+    AccessibilityRole role = axObject->roleValue();
+    switch(role) {
+        case AccessibilityRole::Application:
+            return "Application"_s;
+        case AccessibilityRole::ApplicationAlert:
+            return "ApplicationAlert"_s;
+        case AccessibilityRole::ApplicationAlertDialog:
+            return "ApplicationAlertDialog"_s;
+        case AccessibilityRole::ApplicationDialog:
+            return "ApplicationDialog"_s;
+        case AccessibilityRole::ApplicationLog:
+            return "ApplicationLog"_s;
+        case AccessibilityRole::ApplicationMarquee:
+            return "ApplicationMarquee"_s;
+        case AccessibilityRole::ApplicationStatus:
+            return "ApplicationStatus"_s;
+        case AccessibilityRole::ApplicationTimer:
+            return "ApplicationTimer"_s;
+        case AccessibilityRole::Audio:
+            return "Audio"_s;
+        case AccessibilityRole::Blockquote:
+            return "Blockquote"_s;
+        case AccessibilityRole::Button:
+            return "Button"_s;
+        case AccessibilityRole::Canvas:
+            return "Canvas"_s;
+        case AccessibilityRole::Caption:
+            return "Caption"_s;
+        case AccessibilityRole::Cell:
+            return "Cell"_s;
+        case AccessibilityRole::Checkbox:
+            return "CheckBox"_s;
+        case AccessibilityRole::Code:
+            return "Code"_s;
+        case AccessibilityRole::ColorWell:
+            return "ColorWell"_s;
+        case AccessibilityRole::Column:
+            return "Column"_s;
+        case AccessibilityRole::ColumnHeader:
+            return "ColumnHeader"_s;
+        case AccessibilityRole::ComboBox:
+            return "ComboBox"_s;
+        case AccessibilityRole::DateTime:
+            return "DateTime"_s;
+        case AccessibilityRole::Definition:
+            return "Definition"_s;
+        case AccessibilityRole::Deletion:
+            return "Deletion"_s;
+        case AccessibilityRole::DescriptionList:
+            return "DescriptionList"_s;
+        case AccessibilityRole::DescriptionListTerm:
+            return "DescriptionListTerm"_s;
+        case AccessibilityRole::DescriptionListDetail:
+            return "DescriptionListDetail"_s;
+        case AccessibilityRole::Details:
+            return "Details"_s;
+        case AccessibilityRole::Directory:
+            return "Directory"_s;
+        case AccessibilityRole::Document:
+            return "Document"_s;
+        case AccessibilityRole::DocumentArticle:
+            return "DocumentArticle"_s;
+        case AccessibilityRole::DocumentMath:
+            return "DocumentMath"_s;
+        case AccessibilityRole::DocumentNote:
+            return "DocumentNote"_s;
+        case AccessibilityRole::Emphasis:
+            return "Emphasis"_s;
+        case AccessibilityRole::Feed:
+            return "Feed"_s;
+        case AccessibilityRole::Figure:
+            return "Figure"_s;
+        case AccessibilityRole::Footer:
+            return "Footer"_s;
+        case AccessibilityRole::Footnote:
+            return "Footnote"_s;
+        case AccessibilityRole::Form:
+            return "Form"_s;
+        case AccessibilityRole::Generic:
+            return "Generic"_s;
+        case AccessibilityRole::GraphicsDocument:
+            return "GraphicsDocument"_s;
+        case AccessibilityRole::GraphicsObject:
+            return "GraphicsObject"_s;
+        case AccessibilityRole::GraphicsSymbol:
+            return "GraphicsSymbol"_s;
+        case AccessibilityRole::Grid:
+            return "Grid"_s;
+        case AccessibilityRole::GridCell:
+            return "GridCell"_s;
+        case AccessibilityRole::Group:
+            return "Group"_s;
+        case AccessibilityRole::Heading:
+            return "Heading"_s;
+        case AccessibilityRole::HorizontalRule:
+            return "HorizontalRule"_s;
+        case AccessibilityRole::Ignored:
+            return "Ignored"_s;
+        case AccessibilityRole::Inline:
+            return "Inline"_s;
+        case AccessibilityRole::Image:
+            return "Image"_s;
+        case AccessibilityRole::ImageMap:
+            return "ImageMap"_s;
+        case AccessibilityRole::ImageMapLink:
+            return "ImageMapLink"_s;
+        case AccessibilityRole::Insertion:
+            return "Insertion"_s;
+        case AccessibilityRole::Label:
+            return "Label"_s;
+        case AccessibilityRole::LandmarkBanner:
+            return "LandmarkBanner"_s;
+        case AccessibilityRole::LandmarkComplementary:
+            return "LandmarkComplementary"_s;
+        case AccessibilityRole::LandmarkContentInfo:
+            return "LandmarkContentInfo"_s;
+        case AccessibilityRole::LandmarkDocRegion:
+            return "LandmarkDocRegion"_s;
+        case AccessibilityRole::LandmarkMain:
+            return "LandmarkMain"_s;
+        case AccessibilityRole::LandmarkNavigation:
+            return "LandmarkNavigation"_s;
+        case AccessibilityRole::LandmarkRegion:
+            return "LandmarkRegion"_s;
+        case AccessibilityRole::LandmarkSearch:
+            return "LandmarkSearch"_s;
+        case AccessibilityRole::Legend:
+            return "Legend"_s;
+        case AccessibilityRole::LineBreak:
+            return "LineBreak"_s;
+        case AccessibilityRole::Link:
+            return "Link"_s;
+        case AccessibilityRole::List:
+            return "List"_s;
+        case AccessibilityRole::ListBox:
+            return "ListBox"_s;
+        case AccessibilityRole::ListBoxOption:
+            return "ListBoxOption"_s;
+        case AccessibilityRole::ListItem:
+            return "ListItem"_s;
+        case AccessibilityRole::ListMarker:
+            return "ListMarker"_s;
+        case AccessibilityRole::Mark:
+            return "Mark"_s;
+        case AccessibilityRole::MathElement:
+            return "MathElement"_s;
+        case AccessibilityRole::Menu:
+            return "Menu"_s;
+        case AccessibilityRole::MenuBar:
+            return "MenuBar"_s;
+        case AccessibilityRole::MenuItem:
+            return "MenuItem"_s;
+        case AccessibilityRole::MenuItemCheckbox:
+            return "MenuItemCheckbox"_s;
+        case AccessibilityRole::MenuItemRadio:
+            return "MenuItemRadio"_s;
+        case AccessibilityRole::MenuListPopup:
+            return "MenuListPopup"_s;
+        case AccessibilityRole::MenuListOption:
+            return "MenuListOption"_s;
+        case AccessibilityRole::Meter:
+            return "Meter"_s;
+        case AccessibilityRole::Model:
+            return "Model"_s;
+        case AccessibilityRole::Paragraph:
+            return "Paragraph"_s;
+        case AccessibilityRole::PopUpButton:
+            return "PopUpButton"_s;
+        case AccessibilityRole::Pre:
+            return "Pre"_s;
+        case AccessibilityRole::Presentational:
+            return "Presentational"_s;
+        case AccessibilityRole::ProgressIndicator:
+            return "ProgressIndicator"_s;
+        case AccessibilityRole::RadioButton:
+            return "RadioButton"_s;
+        case AccessibilityRole::RadioGroup:
+            return "RadioGroup"_s;
+        case AccessibilityRole::RemoteFrame:
+            return "RemoteFrame"_s;
+        case AccessibilityRole::RowHeader:
+            return "RowHeader"_s;
+        case AccessibilityRole::Row:
+            return "Row"_s;
+        case AccessibilityRole::RowGroup:
+            return "RowGroup"_s;
+        case AccessibilityRole::RubyInline:
+            return "RubyInline"_s;
+        case AccessibilityRole::RubyText:
+            return "RubyText"_s;
+        case AccessibilityRole::ScrollArea:
+            return "ScrollArea"_s;
+        case AccessibilityRole::ScrollBar:
+            return "ScrollBar"_s;
+        case AccessibilityRole::SearchField:
+            return "SearchField"_s;
+        case AccessibilityRole::Slider:
+            return "Slider"_s;
+        case AccessibilityRole::SliderThumb:
+            return "SliderThumb"_s;
+        case AccessibilityRole::SpinButton:
+            return "SpinButton"_s;
+        case AccessibilityRole::SpinButtonPart:
+            return "SpinButtonPart"_s;
+        case AccessibilityRole::Splitter:
+            return "Splitter"_s;
+        case AccessibilityRole::StaticText:
+            return "StaticText"_s;
+        case AccessibilityRole::Strong:
+            return "Strong"_s;
+        case AccessibilityRole::Subscript:
+            return "Subscript"_s;
+        case AccessibilityRole::Suggestion:
+            return "Suggestion"_s;
+        case AccessibilityRole::Summary:
+            return "Summary"_s;
+        case AccessibilityRole::Superscript:
+            return "Superscript"_s;
+        case AccessibilityRole::Switch:
+            return "Switch"_s;
+        case AccessibilityRole::SVGRoot:
+            return "SVGRoot"_s;
+        case AccessibilityRole::SVGText:
+            return "SVGText"_s;
+        case AccessibilityRole::SVGTSpan:
+            return "SVGTSpan"_s;
+        case AccessibilityRole::SVGTextPath:
+            return "SVGTextPath"_s;
+        case AccessibilityRole::TabGroup:
+            return "TabGroup"_s;
+        case AccessibilityRole::TabList:
+            return "TabList"_s;
+        case AccessibilityRole::TabPanel:
+            return "TabPanel"_s;
+        case AccessibilityRole::Tab:
+            return "Tab"_s;
+        case AccessibilityRole::Table:
+            return "Table"_s;
+        case AccessibilityRole::TableHeaderContainer:
+            return "TableHeaderContainer"_s;
+        case AccessibilityRole::TextArea:
+            return "TextArea"_s;
+        case AccessibilityRole::TextGroup:
+            return "TextGroup"_s;
+        case AccessibilityRole::Term:
+            return "Term"_s;
+        case AccessibilityRole::Time:
+            return "Time"_s;
+        case AccessibilityRole::Tree:
+            return "Tree"_s;
+        case AccessibilityRole::TreeGrid:
+            return "TreeGrid"_s;
+        case AccessibilityRole::TreeItem:
+            return "TreeItem"_s;
+        case AccessibilityRole::TextField:
+            return "TextField"_s;
+        case AccessibilityRole::ToggleButton:
+            return "ToggleButton"_s;
+        case AccessibilityRole::Toolbar:
+            return "Toolbar"_s;
+        case AccessibilityRole::Unknown:
+            return "Unknown"_s;
+        case AccessibilityRole::UserInterfaceTooltip:
+            return "UserInterfaceTooltip"_s;
+        case AccessibilityRole::Video:
+            return "Video"_s;
+        case AccessibilityRole::WebApplication:
+            return "WebApplication"_s;
+        case AccessibilityRole::WebArea:
+            return "WebArea"_s;
+        case AccessibilityRole::WebCoreLink:
+            return "WebCoreLink"_s;
+    };
+    return "Unknown"_s;
+}
+
+static Ref<Inspector::Protocol::Page::AXNode> snapshotForAXObject(WTF::RefPtr<WebCore::AXCoreObject> axObject, Node* nodeToFind)
+{
+    auto axNode = Inspector::Protocol::Page::AXNode::create()
+        .setRole(roleFromObject(axObject))
+        .release();
+    auto* liveObject = dynamicDowncast<AccessibilityObject>(axObject.get());
+
+    if (liveObject && !liveObject->computedLabel().isEmpty())
+        axNode->setName(liveObject->computedLabel());
+    if (!axObject->stringValue().isEmpty())
+        axNode->setValue(JSON::Value::create(axObject->stringValue()));
+    if (liveObject && !liveObject->description().isEmpty())
+        axNode->setDescription(liveObject->description());
+    if (!axObject->keyShortcuts().isEmpty())
+        axNode->setKeyshortcuts(axObject->keyShortcuts());
+    if (!axObject->valueDescription().isEmpty())
+        axNode->setValuetext(axObject->valueDescription());
+    if (!axObject->roleDescription().isEmpty())
+        axNode->setRoledescription(axObject->roleDescription());
+    if (!axObject->isEnabled())
+        axNode->setDisabled(!axObject->isEnabled());
+    if (axObject->supportsExpanded())
+        axNode->setExpanded(axObject->isExpanded());
+    if (axObject->isFocused())
+        axNode->setFocused(axObject->isFocused());
+    if (axObject->isModalNode())
+        axNode->setModal(axObject->isModalNode());
+    if (axObject->isMultiSelectable())
+        axNode->setMultiselectable(axObject->isMultiSelectable());
+    if (liveObject && liveObject->supportsReadOnly() && !axObject->canSetValueAttribute() && axObject->isEnabled())
+        axNode->setReadonly(true);
+    if (axObject->supportsRequiredAttribute())
+        axNode->setRequired(axObject->isRequired());
+    if (axObject->isSelected())
+        axNode->setSelected(axObject->isSelected());
+    if (axObject->supportsChecked()) {
+        AccessibilityButtonState checkedState = axObject->checkboxOrRadioValue();
+        switch (checkedState) {
+            case AccessibilityButtonState::On:
+                axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::True);
+                break;
+            case AccessibilityButtonState::Off:
+                axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::False);
+                break;
+            case AccessibilityButtonState::Mixed:
+                axNode->setChecked(Inspector::Protocol::Page::AXNode::Checked::Mixed);
+                break;
+        }
+    }
+    unsigned level = axObject->hierarchicalLevel() ? axObject->hierarchicalLevel() : axObject->headingLevel();
+    if (level)
+        axNode->setLevel(level);
+    if (axObject->minValueForRange() != 0)
+        axNode->setValuemin(axObject->minValueForRange());
+    if (axObject->maxValueForRange() != 0)
+        axNode->setValuemax(axObject->maxValueForRange());
+    if (liveObject && liveObject->supportsAutoComplete())
+        axNode->setAutocomplete(axObject->autoCompleteValue());
+    if (axObject->hasPopup())
+        axNode->setHaspopup(axObject->popupValue());
+
+    String invalidValue = axObject->invalidStatus();
+    if (invalidValue != "false"_s) {
+        if (invalidValue == "grammar"_s)
+            axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Grammar);
+        else if (invalidValue == "spelling"_s)
+            axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::Spelling);
+        else // Future versions of ARIA may allow additional truthy values. Ex. format, order, or size.
+            axNode->setInvalid(Inspector::Protocol::Page::AXNode::Invalid::True);
+    }
+    switch (axObject->orientation()) {
+        case AccessibilityOrientation::Undefined:
+            break;
+        case AccessibilityOrientation::Vertical:
+            axNode->setOrientation("vertical"_s);
+            break;
+        case AccessibilityOrientation::Horizontal:
+            axNode->setOrientation("horizontal"_s);
+            break;
+    }
+
+    if (axObject->isKeyboardFocusable())
+        axNode->setFocusable(axObject->isKeyboardFocusable());
+
+    if (nodeToFind && axObject->node() == nodeToFind)
+        axNode->setFound(true);
+
+    if (!axObject->children().isEmpty()) {
+        Ref<JSON::ArrayOf<Inspector::Protocol::Page::AXNode>> children = JSON::ArrayOf<Inspector::Protocol::Page::AXNode>::create();
+        for (auto& childObject : axObject->children())
+            children->addItem(snapshotForAXObject(childObject.ptr(), nodeToFind));
+        axNode->setChildren(WTFMove(children));
+    }
+    return axNode;
+}
+
+
+Protocol::ErrorStringOr<Ref<Protocol::Page::AXNode>> InspectorPageAgent::accessibilitySnapshot(const String& objectId)
+{
+    if (!WebCore::AXObjectCache::accessibilityEnabled())
+        WebCore::AXObjectCache::enableAccessibility();
+
+    auto* localMainFrame = dynamicDowncast<LocalFrame>(m_inspectedPage.mainFrame());
+    if (!localMainFrame)
+        return makeUnexpected("No local main frame"_s);
+
+    RefPtr document = localMainFrame->document();
+    if (!document)
+        return makeUnexpected("No document for main frame"_s);
+
+    AXObjectCache* axObjectCache = document->axObjectCache();
+    if (!axObjectCache)
+        return makeUnexpected("No AXObjectCache for main document"_s);
+
+    AXCoreObject* axObject = axObjectCache->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<Inspector::Protocol::Page::AXNode> axNode = snapshotForAXObject(RefPtr { axObject }, node);
+    m_doingAccessibilitySnapshot = false;
+    return axNode;
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::setInterceptFileChooserDialog(bool enabled)
+{
+    m_interceptFileChooserDialog = enabled;
+    return { };
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::setDefaultBackgroundColorOverride(RefPtr<JSON::Object>&& color)
+{
+    auto* localFrame = dynamicDowncast<LocalFrame>(m_inspectedPage.mainFrame());
+    LocalFrameView* view = localFrame ? localFrame->view() : nullptr;
+    if (!view)
+        return makeUnexpected("Internal error: No frame view to set color two"_s);
+
+    if (!color) {
+        view->updateBackgroundRecursively(std::optional<Color>());
+        return { };
+    }
+
+    view->updateBackgroundRecursively(InspectorDOMAgent::parseColor(WTFMove(color)));
+    return { };
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::createUserWorld(const String& name)
+{
+    if (createdUserWorlds().contains(name))
+        return makeUnexpected("World with the given name already exists"_s);
+
+    Ref<DOMWrapperWorld> world = ScriptController::createWorld(name, ScriptController::WorldType::User);
+    ensureUserWorldsExistInAllFrames({world.ptr()});
+    createdUserWorlds().set(name, WTFMove(world));
+    return { };
+}
+
+void InspectorPageAgent::ensureUserWorldsExistInAllFrames(const Vector<DOMWrapperWorld*>& worlds)
+{
+    for (Frame* frame = &m_inspectedPage.mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        auto* localFrame = dynamicDowncast<LocalFrame>(frame);
+        for (auto* world : worlds)
+            localFrame->windowProxy().jsWindowProxy(*world)->window();
+    }
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::setBypassCSP(bool enabled)
+{
+    m_bypassCSP = enabled;
+    return { };
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::crash()
+{
+    CRASH();
+    return { };
+}
+
+Protocol::ErrorStringOr<void> InspectorPageAgent::updateScrollingState()
+{
+    auto* scrollingCoordinator = m_inspectedPage.scrollingCoordinator();
+    if (!scrollingCoordinator)
+        return {};
+    scrollingCoordinator->commitTreeStateIfNeeded();
+    return {};
+}
 
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/agents/InspectorPageAgent.h b/Source/WebCore/inspector/agents/InspectorPageAgent.h
index dee4a5033bc6e948e301e9b681d82758c4e92689..6a3db5c90e798693ac3cd6547207713dfa947364 100644
--- a/Source/WebCore/inspector/agents/InspectorPageAgent.h
+++ b/Source/WebCore/inspector/agents/InspectorPageAgent.h
@@ -32,8 +32,10 @@
 #pragma once
 
 #include "CachedResource.h"
+#include "FrameIdentifier.h"
 #include "InspectorWebAgentBase.h"
 #include "LayoutRect.h"
+#include "ProcessIdentifier.h"
 #include <JavaScriptCore/InspectorBackendDispatchers.h>
 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
 #include <JavaScriptCore/InspectorProtocolObjects.h>
@@ -43,11 +45,16 @@
 #include <wtf/WeakRef.h>
 #include <wtf/text/WTFString.h>
 
+namespace Inspector {
+class InjectedScriptManager;
+}
+
 namespace WebCore {
 
 class DOMWrapperWorld;
 class DocumentLoader;
 class Frame;
+class HTMLInputElement;
 class InspectorClient;
 class InspectorOverlay;
 class LocalFrame;
@@ -80,6 +87,8 @@ public:
         OtherResource,
     };
 
+    WEBCORE_EXPORT static String serializeFrameID(FrameIdentifier frameID);
+    WEBCORE_EXPORT static std::optional<FrameIdentifier> parseFrameID(String frameID);
     static bool sharedBufferContent(RefPtr<FragmentedSharedBuffer>&&, const String& textEncodingName, bool withBase64Encode, String* result);
     static Vector<CachedResource*> cachedResourcesForFrame(LocalFrame*);
     static void resourceContent(Inspector::Protocol::ErrorString&, LocalFrame*, const URL&, String* result, bool* base64Encoded);
@@ -100,8 +109,11 @@ public:
     Inspector::Protocol::ErrorStringOr<void> enable();
     Inspector::Protocol::ErrorStringOr<void> disable();
     Inspector::Protocol::ErrorStringOr<void> reload(std::optional<bool>&& ignoreCache, std::optional<bool>&& revalidateAllResources);
+    Inspector::Protocol::ErrorStringOr<void> goBack();
+    Inspector::Protocol::ErrorStringOr<void> goForward();
     Inspector::Protocol::ErrorStringOr<void> navigate(const String& url);
     Inspector::Protocol::ErrorStringOr<void> overrideUserAgent(const String&);
+    Inspector::Protocol::ErrorStringOr<void> overridePlatform(const String&);
     Inspector::Protocol::ErrorStringOr<void> overrideSetting(Inspector::Protocol::Page::Setting, std::optional<bool>&& value);
     Inspector::Protocol::ErrorStringOr<void> overrideUserPreference(Inspector::Protocol::Page::UserPreferenceName, std::optional<Inspector::Protocol::Page::UserPreferenceValue>&&);
     Inspector::Protocol::ErrorStringOr<Ref<JSON::ArrayOf<Inspector::Protocol::Page::Cookie>>> getCookies();
@@ -117,45 +129,65 @@ public:
 #endif
     Inspector::Protocol::ErrorStringOr<void> setShowPaintRects(bool);
     Inspector::Protocol::ErrorStringOr<void> setEmulatedMedia(const String&);
+    Inspector::Protocol::ErrorStringOr<void> setForcedColors(std::optional<Inspector::Protocol::Page::ForcedColors>&&);
+    Inspector::Protocol::ErrorStringOr<void> setTimeZone(const String&);
+    Inspector::Protocol::ErrorStringOr<void> setTouchEmulationEnabled(bool);
     Inspector::Protocol::ErrorStringOr<String> snapshotNode(Inspector::Protocol::DOM::NodeId);
-    Inspector::Protocol::ErrorStringOr<String> snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem);
+    Inspector::Protocol::ErrorStringOr<String> snapshotRect(int x, int y, int width, int height, Inspector::Protocol::Page::CoordinateSystem, std::optional<bool>&& omitDeviceScaleFactor);
 #if ENABLE(WEB_ARCHIVE) && USE(CF)
     Inspector::Protocol::ErrorStringOr<String> archive();
 #endif
-#if !PLATFORM(COCOA)
     Inspector::Protocol::ErrorStringOr<void> setScreenSizeOverride(std::optional<int>&& width, std::optional<int>&& height);
-#endif
+
+    Inspector::Protocol::ErrorStringOr<void> insertText(const String& text);
+    Inspector::Protocol::ErrorStringOr<Ref<Inspector::Protocol::Page::AXNode>> accessibilitySnapshot(const String& objectId);
+    Inspector::Protocol::ErrorStringOr<void> setInterceptFileChooserDialog(bool enabled);
+    Inspector::Protocol::ErrorStringOr<void> setDefaultBackgroundColorOverride(RefPtr<JSON::Object>&&);
+    Inspector::Protocol::ErrorStringOr<void> createUserWorld(const String&);
+    Inspector::Protocol::ErrorStringOr<void> setBypassCSP(bool);
+    Inspector::Protocol::ErrorStringOr<void> crash();
+    Inspector::Protocol::ErrorStringOr<void> updateScrollingState();
 
     // InspectorInstrumentation
-    void domContentEventFired();
-    void loadEventFired();
+    void domContentEventFired(LocalFrame&);
+    void loadEventFired(LocalFrame&);
     void frameNavigated(LocalFrame&);
     void frameDetached(LocalFrame&);
-    void loaderDetachedFromFrame(DocumentLoader&);
     void frameStartedLoading(LocalFrame&);
     void frameStoppedLoading(LocalFrame&);
-    void frameScheduledNavigation(Frame&, Seconds delay);
+    void frameScheduledNavigation(Frame&, Seconds delay, bool targetIsCurrentFrame);
     void frameClearedScheduledNavigation(Frame&);
     void accessibilitySettingsDidChange();
     void defaultUserPreferencesDidChange();
+    void didNavigateWithinPage(LocalFrame&);
 #if ENABLE(DARK_MODE_CSS) || HAVE(OS_DARK_MODE_SUPPORT)
     void defaultAppearanceDidChange();
 #endif
     void applyUserAgentOverride(String&);
+    void applyPlatformOverride(String&);
     void applyEmulatedMedia(AtomString&);
     void didClearWindowObjectInWorld(LocalFrame&, DOMWrapperWorld&);
     void didPaint(RenderObject&, const LayoutRect&);
     void didLayout();
     void didScroll();
     void didRecalculateStyle();
+    void runOpenPanel(HTMLInputElement* element, bool* intercept);
+    void frameAttached(LocalFrame&);
+    bool shouldBypassCSP();
+    void willCheckNavigationPolicy(LocalFrame&);
+    void didCheckNavigationPolicy(LocalFrame&, bool cancel);
+    bool doingAccessibilitySnapshot() const { return m_doingAccessibilitySnapshot; };
 
     Frame* frameForId(const Inspector::Protocol::Network::FrameId&);
     WEBCORE_EXPORT String frameId(Frame*);
     String loaderId(DocumentLoader*);
     LocalFrame* assertFrame(Inspector::Protocol::ErrorString&, const Inspector::Protocol::Network::FrameId&);
+    void setIgnoreDidClearWindowObject(bool ignore) { m_ignoreDidClearWindowObject = ignore; }
+    bool ignoreDidClearWindowObject() const { return m_ignoreDidClearWindowObject; }
 
 private:
     double timestamp();
+    void ensureUserWorldsExistInAllFrames(const Vector<DOMWrapperWorld*>&);
 
     Ref<InspectorOverlay> protectedOverlay() const;
 
@@ -173,17 +205,22 @@ private:
     RefPtr<Inspector::PageBackendDispatcher> m_backendDispatcher;
 
     Page& m_inspectedPage;
+    Inspector::InjectedScriptManager& m_injectedScriptManager;
     InspectorClient* m_client { nullptr };
     WeakRef<InspectorOverlay> m_overlay;
 
-    WeakHashMap<Frame, String> m_frameToIdentifier;
     MemoryCompactRobinHoodHashMap<String, WeakPtr<Frame>> m_identifierToFrame;
     HashMap<DocumentLoader*, String> m_loaderToIdentifier;
     String m_userAgentOverride;
+    String m_platformOverride;
     AtomString m_emulatedMedia;
     String m_bootstrapScript;
     bool m_isFirstLayoutAfterOnLoad { false };
     bool m_showPaintRects { false };
+    bool m_interceptFileChooserDialog { false };
+    bool m_bypassCSP { false };
+    bool m_doingAccessibilitySnapshot { false };
+    bool m_ignoreDidClearWindowObject { false };
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp
index 009092f4dd46f22aef63ffa0a9758884859e7385..545da93ce753072c18279c67b1589aefcc7e0b8d 100644
--- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp
+++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.cpp
@@ -34,6 +34,7 @@
 
 #include "DOMWrapperWorld.h"
 #include "Document.h"
+#include "FrameLoader.h"
 #include "InspectorPageAgent.h"
 #include "InstrumentingAgents.h"
 #include "JSDOMWindowCustom.h"
@@ -42,6 +43,7 @@
 #include "Page.h"
 #include "PageConsoleClient.h"
 #include "ScriptController.h"
+#include "ScriptSourceCode.h"
 #include "SecurityOrigin.h"
 #include "UserGestureEmulationScope.h"
 #include <JavaScriptCore/InjectedScript.h>
@@ -88,13 +90,73 @@ Inspector::Protocol::ErrorStringOr<void> PageRuntimeAgent::disable()
 {
     m_instrumentingAgents.setEnabledPageRuntimeAgent(nullptr);
 
+    m_bindingNames.clear();
+
     return InspectorRuntimeAgent::disable();
 }
 
 void PageRuntimeAgent::frameNavigated(LocalFrame& frame)
 {
+    auto* pageAgent = m_instrumentingAgents.enabledPageAgent();
+    if (pageAgent)
+        pageAgent->setIgnoreDidClearWindowObject(true);
     // Ensure execution context is created for the frame even if it doesn't have scripts.
     mainWorldGlobalObject(frame);
+    if (pageAgent)
+        pageAgent->setIgnoreDidClearWindowObject(false);
+}
+
+static JSC_DECLARE_HOST_FUNCTION(bindingCallback);
+
+JSC_DEFINE_HOST_FUNCTION(bindingCallback, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
+{
+    auto result = JSC::JSValue::encode(JSC::jsUndefined());
+    if (!callFrame->jsCallee())
+        return result;
+    String bindingName;
+    if (auto* function = JSC::jsDynamicCast<JSC::JSFunction*>(callFrame->jsCallee()))
+        bindingName = function->name(globalObject->vm());
+    auto client = globalObject->consoleClient();
+    if (!client)
+        return result;
+    if (callFrame->argumentCount() < 1)
+        return result;
+    auto value = callFrame->argument(0);
+    if (value.isUndefined())
+        return result;
+    String stringArg = value.toWTFString(globalObject);
+    client->bindingCalled(globalObject, bindingName, stringArg);
+    return result;
+}
+
+static void addBindingToFrame(LocalFrame& frame, const String& name)
+{
+    JSC::JSGlobalObject* globalObject = frame.script().globalObject(mainThreadNormalWorld());
+    auto& vm = globalObject->vm();
+    globalObject->putDirectNativeFunction(vm, globalObject, JSC::Identifier::fromString(vm, name), 1, bindingCallback, JSC::ImplementationVisibility::Public, JSC::NoIntrinsic, JSC::attributesForStructure(static_cast<unsigned>(JSC::PropertyAttribute::Function)));
+}
+
+Protocol::ErrorStringOr<void> PageRuntimeAgent::addBinding(const String& name)
+{
+    if (!m_bindingNames.add(name).isNewEntry)
+        return {};
+
+    m_inspectedPage.forEachLocalFrame([&](LocalFrame& frame) {
+        if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript))
+            return;
+
+        addBindingToFrame(frame, name);
+    });
+
+    return {};
+}
+
+void PageRuntimeAgent::bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg)
+{
+    auto injectedScript = injectedScriptManager().injectedScriptFor(globalObject);
+    if (injectedScript.hasNoValue())
+        return;
+    m_frontendDispatcher->bindingCalled(injectedScriptManager().injectedScriptIdFor(globalObject), name, arg);
 }
 
 void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapperWorld& world)
@@ -103,7 +165,26 @@ void PageRuntimeAgent::didClearWindowObjectInWorld(LocalFrame& frame, DOMWrapper
     if (!pageAgent)
         return;
 
+    if (pageAgent->ignoreDidClearWindowObject())
+        return;
+
+    if (world.isNormal()) {
+        for (const auto& name : m_bindingNames)
+            addBindingToFrame(frame, name);
+    }
+
+    pageAgent->setIgnoreDidClearWindowObject(true);
     notifyContextCreated(pageAgent->frameId(&frame), frame.script().globalObject(world), world);
+    pageAgent->setIgnoreDidClearWindowObject(false);
+}
+
+void PageRuntimeAgent::didReceiveMainResourceError(LocalFrame& frame)
+{
+    if (frame.loader().stateMachine().isDisplayingInitialEmptyDocument()) {
+        // Ensure execution context is created for the empty docment to make
+        // it usable in case loading failed.
+        mainWorldGlobalObject(frame);
+    }
 }
 
 InjectedScript PageRuntimeAgent::injectedScriptForEval(Inspector::Protocol::ErrorString& errorString, std::optional<Inspector::Protocol::Runtime::ExecutionContextId>&& executionContextId)
@@ -142,9 +223,6 @@ void PageRuntimeAgent::reportExecutionContextCreation()
         return;
 
     m_inspectedPage.forEachLocalFrame([&](LocalFrame& frame) {
-        if (!frame.script().canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript))
-            return;
-
         auto frameId = pageAgent->frameId(&frame);
 
         // Always send the main world first.
diff --git a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h
index b70ca7636463b9199bcbb21bfea055870ba33b34..25fdc23bfb71985fe1af04bddc360d118f329afe 100644
--- a/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h
+++ b/Source/WebCore/inspector/agents/page/PageRuntimeAgent.h
@@ -38,6 +38,7 @@
 
 namespace JSC {
 class CallFrame;
+class JSGlobalObject;
 }
 
 namespace WebCore {
@@ -59,10 +60,13 @@ public:
     Inspector::Protocol::ErrorStringOr<void> disable();
     Inspector::Protocol::ErrorStringOr<std::tuple<Ref<Inspector::Protocol::Runtime::RemoteObject>, std::optional<bool> /* wasThrown */, std::optional<int> /* savedResultIndex */>> evaluate(const String& expression, const String& objectGroup, std::optional<bool>&& includeCommandLineAPI, std::optional<bool>&& doNotPauseOnExceptionsAndMuteConsole, std::optional<Inspector::Protocol::Runtime::ExecutionContextId>&&, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& saveResult, std::optional<bool>&& emulateUserGesture);
     void callFunctionOn(const Inspector::Protocol::Runtime::RemoteObjectId&, const String& functionDeclaration, RefPtr<JSON::Array>&& arguments, std::optional<bool>&& doNotPauseOnExceptionsAndMuteConsole, std::optional<bool>&& returnByValue, std::optional<bool>&& generatePreview, std::optional<bool>&& emulateUserGesture, std::optional<bool>&& awaitPromise, Ref<CallFunctionOnCallback>&&);
+    Inspector::Protocol::ErrorStringOr<void> addBinding(const String& name);
 
     // InspectorInstrumentation
     void frameNavigated(LocalFrame&);
     void didClearWindowObjectInWorld(LocalFrame&, DOMWrapperWorld&);
+    void didReceiveMainResourceError(LocalFrame&);
+    void bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg);
 
 private:
     Inspector::InjectedScript injectedScriptForEval(Inspector::Protocol::ErrorString&, std::optional<Inspector::Protocol::Runtime::ExecutionContextId>&&);
@@ -77,6 +81,7 @@ private:
     InstrumentingAgents& m_instrumentingAgents;
 
     Page& m_inspectedPage;
+    HashSet<String> m_bindingNames;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/loader/CookieJar.h b/Source/WebCore/loader/CookieJar.h
index ae94a796b1d0c9fee05ec342cfa58b8a0248875b..c0b3bcdaca1f473cca7299db3de69329766daf0b 100644
--- a/Source/WebCore/loader/CookieJar.h
+++ b/Source/WebCore/loader/CookieJar.h
@@ -47,6 +47,7 @@ struct CookieStoreGetOptions;
 class NetworkStorageSession;
 class StorageSessionProvider;
 struct SameSiteInfo;
+class ResourceLoader;
 
 class WEBCORE_EXPORT CookieJar : public RefCountedAndCanMakeWeakPtr<CookieJar> {
 public:
@@ -79,6 +80,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 ef8c9cbc1c786172081c9b04bdc55a65ae40593e..8eff311ff2b9e88cb484c01d935b97f23eec47ba 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -765,8 +765,10 @@ void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc
     if (!didReceiveRedirectResponse)
         return completionHandler(WTFMove(newRequest));
 
+    InspectorInstrumentation::willCheckNavigationPolicy(*m_frame);
     auto navigationPolicyCompletionHandler = [this, protectedThis = Ref { *this }, protectedFrame = Ref { *m_frame }, completionHandler = WTFMove(completionHandler)] (ResourceRequest&& request, WeakPtr<FormState>&&, NavigationPolicyDecision navigationPolicyDecision) mutable {
         m_waitingForNavigationPolicy = false;
+        InspectorInstrumentation::didCheckNavigationPolicy(protectedFrame.get(), navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad);
         switch (navigationPolicyDecision) {
         case NavigationPolicyDecision::IgnoreLoad:
         case NavigationPolicyDecision::LoadWillContinueInAnotherProcess:
@@ -1535,11 +1537,17 @@ void DocumentLoader::detachFromFrame(LoadWillContinueInAnotherProcess loadWillCo
     if (auto navigationID = std::exchange(m_navigationID, { }))
         m_frame->loader().client().documentLoaderDetached(*navigationID, loadWillContinueInAnotherProcess);
 
-    InspectorInstrumentation::loaderDetachedFromFrame(*m_frame, *this);
-
     observeFrame(nullptr);
 }
 
+void DocumentLoader::replacedByFragmentNavigation(LocalFrame& frame)
+{
+    ASSERT(!this->frame());
+    // Notify WebPageProxy that the navigation has been converted into same page navigation.
+    if (auto navigationID = std::exchange(m_navigationID, { }))
+        frame.loader().client().documentLoaderDetached(*navigationID, LoadWillContinueInAnotherProcess::No);
+}
+
 void DocumentLoader::setNavigationID(NavigationIdentifier navigationID)
 {
     m_navigationID = navigationID;
diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h
index 710b76ba378d0242be7b9fb469203fcd9ec18252..23ebc0f38d5a5a19b23c748149fbbc8aa36059df 100644
--- a/Source/WebCore/loader/DocumentLoader.h
+++ b/Source/WebCore/loader/DocumentLoader.h
@@ -218,6 +218,8 @@ public:
 
     WEBCORE_EXPORT virtual void detachFromFrame(LoadWillContinueInAnotherProcess);
 
+    void replacedByFragmentNavigation(LocalFrame&);
+
     WEBCORE_EXPORT FrameLoader* frameLoader() const;
     RefPtr<FrameLoader> protectedFrameLoader() const;
     WEBCORE_EXPORT SubresourceLoader* mainResourceLoader() const;
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index b38b5938d46ef64d1736bc8b2eebd166d18983a9..0f315f7c0739ea210493a6d19520421c48c645d0 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -1323,6 +1323,7 @@ void FrameLoader::loadInSameDocument(URL url, RefPtr<SerializedScriptValue> stat
     }
 
     m_client->dispatchDidNavigateWithinPage();
+    InspectorInstrumentation::didNavigateWithinPage(m_frame);
 
     document->statePopped(stateObject ? stateObject.releaseNonNull() : SerializedScriptValue::nullValue());
     m_client->dispatchDidPopStateWithinPage();
@@ -1846,6 +1847,7 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
     const String& httpMethod = loader->request().httpMethod();
 
     if (shouldPerformFragmentNavigation(isFormSubmission, httpMethod, policyChecker().loadType(), newURL)) {
+        loader->replacedByFragmentNavigation(m_frame);
 
         RefPtr oldDocumentLoader = m_documentLoader;
         NavigationAction action { frame->protectedDocument().releaseNonNull(), loader->request(), InitiatedByMainFrame::Unknown, loader->isRequestFromClientOrUserInput(), policyChecker().loadType(), isFormSubmission };
@@ -1882,8 +1884,10 @@ void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
     }
 
     RELEASE_ASSERT(!isBackForwardLoadType(policyChecker().loadType()) || frame->history().provisionalItem());
+    InspectorInstrumentation::willCheckNavigationPolicy(m_frame);
     auto policyDecisionMode = loader->triggeringAction().isFromNavigationAPI() ? PolicyDecisionMode::Synchronous : PolicyDecisionMode::Asynchronous;
     policyChecker().checkNavigationPolicy(ResourceRequest(loader->request()), ResourceResponse { } /* redirectResponse */, loader, WTFMove(formState), [this, frame, allowNavigationToInvalidURL, completionHandler = completionHandlerCaller.release()] (const ResourceRequest& request, WeakPtr<FormState>&& weakFormState, NavigationPolicyDecision navigationPolicyDecision) mutable {
+        InspectorInstrumentation::didCheckNavigationPolicy(m_frame, navigationPolicyDecision != NavigationPolicyDecision::ContinueLoad);
         continueLoadAfterNavigationPolicy(request, RefPtr { weakFormState.get() }.get(), navigationPolicyDecision, allowNavigationToInvalidURL);
         completionHandler();
     }, policyDecisionMode);
@@ -3169,10 +3173,15 @@ String FrameLoader::userAgent(const URL& url) const
 
 String FrameLoader::navigatorPlatform() const
 {
+    String platform;
+
     auto customNavigatorPlatform = m_frame->mainFrame().customNavigatorPlatform();
     if (!customNavigatorPlatform.isEmpty())
-        return customNavigatorPlatform;
-    return String();
+        platform = customNavigatorPlatform;
+
+    InspectorInstrumentation::applyPlatformOverride(m_frame, platform);
+
+    return platform;
 }
 
 void FrameLoader::dispatchOnloadEvents()
@@ -3646,6 +3655,8 @@ void FrameLoader::receivedMainResourceError(const ResourceError& error, LoadWill
     checkCompleted();
     if (frame->page())
         checkLoadComplete(loadWillContinueInAnotherProcess);
+
+    InspectorInstrumentation::didReceiveMainResourceError(m_frame, error);
 }
 
 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, const SecurityOrigin* requesterOrigin, bool shouldContinue, NavigationHistoryBehavior historyHandling)
@@ -4530,9 +4541,6 @@ String FrameLoader::referrer() const
 
 void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
 {
-    if (!protectedFrame()->checkedScript()->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript))
-        return;
-
     Vector<Ref<DOMWrapperWorld>> worlds;
     ScriptController::getAllWorlds(worlds);
     for (auto& world : worlds)
@@ -4542,13 +4550,12 @@ void FrameLoader::dispatchDidClearWindowObjectsInAllWorlds()
 void FrameLoader::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld& world)
 {
     Ref frame = m_frame.get();
-    if (!frame->checkedScript()->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript) || !frame->windowProxy().existingJSWindowProxy(world))
-        return;
-
-    m_client->dispatchDidClearWindowObjectInWorld(world);
-
-    if (RefPtr page = frame->page())
-        page->inspectorController().didClearWindowObjectInWorld(frame, world);
+    if (frame->windowProxy().existingJSWindowProxy(world)) {
+        if (frame->checkedScript()->canExecuteScripts(ReasonForCallingCanExecuteScripts::NotAboutToExecuteScript))
+            m_client->dispatchDidClearWindowObjectInWorld(world);
+        if (RefPtr page = frame->page())
+            page->inspectorController().didClearWindowObjectInWorld(m_frame, world);
+    }
 
     InspectorInstrumentation::didClearWindowObjectInWorld(frame, world);
 }
diff --git a/Source/WebCore/loader/LoaderStrategy.h b/Source/WebCore/loader/LoaderStrategy.h
index 91340dc21042f545592b442bc42dbceed06219b2..f3591fe333761b10a25ddaf4a4f8d72170dfe336 100644
--- a/Source/WebCore/loader/LoaderStrategy.h
+++ b/Source/WebCore/loader/LoaderStrategy.h
@@ -86,6 +86,7 @@ public:
 
     virtual bool isOnLine() const = 0;
     virtual void addOnlineStateChangeListener(Function<void(bool)>&&) = 0;
+    virtual void setEmulateOfflineState(bool) {};
 
     virtual bool shouldPerformSecurityChecks() const { return false; }
     virtual bool havePerformedSecurityChecks(const ResourceResponse&) const { return false; }
diff --git a/Source/WebCore/loader/NavigationScheduler.cpp b/Source/WebCore/loader/NavigationScheduler.cpp
index 6ca24eb3b82344b60b33298989857a68ecdc39cb..ca17da3fb6148a1789618f501f85069c1c9b9ead 100644
--- a/Source/WebCore/loader/NavigationScheduler.cpp
+++ b/Source/WebCore/loader/NavigationScheduler.cpp
@@ -812,7 +812,7 @@ void NavigationScheduler::startTimer()
 
     Seconds delay = 1_s * m_redirect->delay();
     m_timer.startOneShot(delay);
-    InspectorInstrumentation::frameScheduledNavigation(frame, delay);
+    InspectorInstrumentation::frameScheduledNavigation(frame, delay, m_redirect->targetIsCurrentFrame());
     m_redirect->didStartTimer(frame, m_timer); // m_redirect may be null on return (e.g. the client canceled the load)
 }
 
diff --git a/Source/WebCore/loader/ProgressTracker.cpp b/Source/WebCore/loader/ProgressTracker.cpp
index ac208c49bca32e5f2215d881733f2c11396bd18f..7ea80906fea17a592a00c63c8d810a53d893ae45 100644
--- a/Source/WebCore/loader/ProgressTracker.cpp
+++ b/Source/WebCore/loader/ProgressTracker.cpp
@@ -161,6 +161,8 @@ void ProgressTracker::progressCompleted(LocalFrame& frame)
     if (!m_numProgressTrackedFrames || m_originatingProgressFrame == &frame)
         finalProgressComplete();
 
+    InspectorInstrumentation::frameStoppedLoading(frame);
+
     m_client->didChangeEstimatedProgress();
 }
 
@@ -187,8 +189,6 @@ void ProgressTracker::finalProgressComplete()
     m_client->progressFinished(*frame);
     protectedPage()->progressFinished(*frame);
     frame->protectedLoader()->loadProgressingStatusChanged();
-
-    InspectorInstrumentation::frameStoppedLoading(*frame);
 }
 
 void ProgressTracker::incrementProgress(ResourceLoaderIdentifier identifier, const ResourceResponse& response)
diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
index 3b4b56c0dc2845f6993cc1d60c65648be74b125f..f8ec6be1f5765b58ced741a348c62a82cf446d3c 100644
--- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp
+++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp
@@ -1154,8 +1154,11 @@ ResourceErrorOr<CachedResourceHandle<CachedResource>> CachedResourceLoader::requ
 
     request.updateReferrerPolicy(document() ? document()->referrerPolicy() : ReferrerPolicy::Default);
 
-    if (InspectorInstrumentation::willIntercept(frame.ptr(), request.resourceRequest()))
-        request.setCachingPolicy(CachingPolicy::DisallowCaching);
+    if (InspectorInstrumentation::willIntercept(frame.ptr(), request.resourceRequest())) {
+        // Playwright: we don't disable such caching in other browsers and it breaks css resource downloads,
+        // see https://github.com/microsoft/playwright/issues/19158
+        // request.setCachingPolicy(CachingPolicy::DisallowCaching);
+    }
 
     if (RefPtr documentLoader = m_documentLoader.get()) {
         bool madeHTTPS { request.resourceRequest().wasSchemeOptimisticallyUpgraded() };
@@ -1773,8 +1776,9 @@ Vector<Ref<SVGImage>> CachedResourceLoader::allCachedSVGImages() const
 
 ResourceErrorOr<CachedResourceHandle<CachedResource>> CachedResourceLoader::preload(CachedResource::Type type, CachedResourceRequest&& request)
 {
-    if (InspectorInstrumentation::willIntercept(protectedFrame().get(), request.resourceRequest()))
-        return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s });
+    // Playwright: <link rel=preload ... /> requests are intercepted (see https://github.com/microsoft/playwright/issues/16745)
+    // if (InspectorInstrumentation::willIntercept(protectedFrame().get(), request.resourceRequest()))
+    //     return makeUnexpected(ResourceError { errorDomainWebKitInternal, 0, request.resourceRequest().url(), "Inspector intercept"_s });
 
     ASSERT(m_document);
     if (request.charset().isEmpty() && m_document && (type == CachedResource::Type::Script || type == CachedResource::Type::CSSStyleSheet))
diff --git a/Source/WebCore/page/ChromeClient.h b/Source/WebCore/page/ChromeClient.h
index b7d2b467606fb5406769b1c49384aac7b41f7298..633dc036f990798a6d62bb0b50125c6cd5df44aa 100644
--- a/Source/WebCore/page/ChromeClient.h
+++ b/Source/WebCore/page/ChromeClient.h
@@ -351,7 +351,7 @@ public:
 #endif
 
 #if ENABLE(ORIENTATION_EVENTS)
-    virtual IntDegrees deviceOrientation() const = 0;
+    virtual IntDegrees 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 7e2577a7e448e543a2c5a8fcdae04a72dc4076f0..99348d9bf3c65d2c732a80a652fe592084d8441c 100644
--- a/Source/WebCore/page/EventHandler.cpp
+++ b/Source/WebCore/page/EventHandler.cpp
@@ -4398,6 +4398,12 @@ bool EventHandler::handleDrag(const MouseEventWithHitTestResults& event, CheckDr
     if (!document)
         return false;
 
+#if PLATFORM(MAC)
+    auto* page = m_frame->page();
+    if (page && !page->overrideDragPasteboardName().isEmpty())
+        dragState().dataTransfer = DataTransfer::createForDrag(*document, page->overrideDragPasteboardName());
+    else
+#endif
     dragState().dataTransfer = DataTransfer::createForDrag(*document);
     auto hasNonDefaultPasteboardData = HasNonDefaultPasteboardData::No;
     
@@ -4984,6 +4990,7 @@ static HitTestResult hitTestResultInFrame(LocalFrame* frame, const LayoutPoint&
     return result;
 }
 
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
 HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEvent& event)
 {
     Ref frame = m_frame.get();
@@ -5059,7 +5066,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve
 
         // Increment the platform touch id by 1 to avoid storing a key of 0 in the hashmap.
         unsigned touchPointTargetKey = point.id() + 1;
-#if PLATFORM(WPE)
+#if !ENABLE(IOS_TOUCH_EVENTS)
         bool pointerCancelled = false;
 #endif
         RefPtr<EventTarget> touchTarget;
@@ -5106,7 +5113,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve
             // we also remove it from the map.
             touchTarget = m_originatingTouchPointTargets.take(touchPointTargetKey);
 
-#if PLATFORM(WPE)
+#if !ENABLE(IOS_TOUCH_EVENTS)
             HitTestResult result = hitTestResultAtPoint(pagePoint, hitType | HitTestRequest::Type::AllowChildFrameContent);
             pointerTarget = result.targetElement();
             pointerCancelled = (pointerTarget != touchTarget);
@@ -5129,7 +5136,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve
         if (!targetFrame)
             continue;
 
-#if PLATFORM(WPE)
+#if !ENABLE(IOS_TOUCH_EVENTS)
         // FIXME: WPE currently does not send touch stationary events, so create a naive TouchReleased PlatformTouchPoint
         // on release if the hit test result changed since the previous TouchPressed or TouchMoved
         if (pointState == PlatformTouchPoint::TouchReleased && pointerCancelled) {
@@ -5219,6 +5226,7 @@ HandleUserInputEventResult EventHandler::handleTouchEvent(const PlatformTouchEve
 
     return swallowedEvent;
 }
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
 #endif // ENABLE(TOUCH_EVENTS) && !ENABLE(IOS_TOUCH_EVENTS)
 
 #if ENABLE(TOUCH_EVENTS)
diff --git a/Source/WebCore/page/FocusController.cpp b/Source/WebCore/page/FocusController.cpp
index b945aaa8fc59d043f8177acc443f0cbba2f5bb71..fc0c93ea6cdf66d7c9a38350230cda6ed9950f17 100644
--- a/Source/WebCore/page/FocusController.cpp
+++ b/Source/WebCore/page/FocusController.cpp
@@ -586,13 +586,14 @@ bool FocusController::relinquishFocusToChrome(FocusDirection direction)
         return false;
 
     Ref page = m_page.get();
-    if (!page->chrome().canTakeFocus(direction) || page->isControlledByAutomation())
+    if (!page->chrome().canTakeFocus(direction))
         return false;
 
     clearSelectionIfNeeded(frame.get(), nullptr, nullptr);
     document->setFocusedElement(nullptr);
     setFocusedFrame(nullptr);
-    page->chrome().takeFocus(direction);
+    if (!page->isControlledByAutomation())
+      page->chrome().takeFocus(direction);
     return true;
 }
 
diff --git a/Source/WebCore/page/FrameSnapshotting.cpp b/Source/WebCore/page/FrameSnapshotting.cpp
index ce7eca624ce26cdb4440ca6ce5e3c9f912d5f384..0104c784711709e04128495a6bf6b188fdd8021c 100644
--- a/Source/WebCore/page/FrameSnapshotting.cpp
+++ b/Source/WebCore/page/FrameSnapshotting.cpp
@@ -111,7 +111,7 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect&
     // Other paint behaviors are set by paintContentsForSnapshot.
     frame.view()->setPaintBehavior(paintBehavior);
 
-    float scaleFactor = frame.page()->deviceScaleFactor();
+    float scaleFactor = options.flags.contains(SnapshotFlags::OmitDeviceScaleFactor) ? 1 : frame.page()->deviceScaleFactor();
     if (options.flags.contains(SnapshotFlags::PaintWith3xBaseScale))
         scaleFactor = 3;
 
@@ -129,7 +129,13 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect&
     if (!buffer)
         return nullptr;
 
+#if !PLATFORM(MAC)
+    buffer->context().scale(scaleFactor);
+#endif
+
     buffer->context().translate(-imageRect.location());
+    if (coordinateSpace != LocalFrameView::ViewCoordinates)
+        buffer->context().scale(1 / frame.page()->pageScaleFactor());
 
     if (!clipRects.isEmpty()) {
         Path clipPath;
@@ -138,7 +144,10 @@ RefPtr<ImageBuffer> snapshotFrameRectWithClip(LocalFrame& frame, const IntRect&
         buffer->context().clipPath(clipPath);
     }
 
-    frame.view()->paintContentsForSnapshot(buffer->context(), imageRect, shouldIncludeSelection, coordinateSpace);
+    FloatRect fr = imageRect;
+    if (coordinateSpace != LocalFrameView::ViewCoordinates)
+        fr.scale(frame.page()->pageScaleFactor());
+    frame.view()->paintContentsForSnapshot(buffer->context(), enclosingIntRect(fr), shouldIncludeSelection, coordinateSpace);
     return buffer;
 }
 
diff --git a/Source/WebCore/page/FrameSnapshotting.h b/Source/WebCore/page/FrameSnapshotting.h
index 3ab70c27fef52f5d933cd2338a7c2f96e2debc88..39fc13df5ce132f8d028cd5039c607fe8963ddcf 100644
--- a/Source/WebCore/page/FrameSnapshotting.h
+++ b/Source/WebCore/page/FrameSnapshotting.h
@@ -56,6 +56,7 @@ enum class SnapshotFlags : uint16_t {
     Accelerated = 1 << 8,
     ExcludeReplacedContent = 1 << 9,
     PaintWith3xBaseScale = 1 << 10,
+    OmitDeviceScaleFactor = 1 << 11,
 };
 
 struct SnapshotOptions {
diff --git a/Source/WebCore/page/History.cpp b/Source/WebCore/page/History.cpp
index c114526d3b536993fe20cb2452b913c01d3f65dc..0cdd416742e5a9205f8114ef84ddea3cfce03293 100644
--- a/Source/WebCore/page/History.cpp
+++ b/Source/WebCore/page/History.cpp
@@ -32,6 +32,7 @@
 #include "FrameLoader.h"
 #include "HistoryController.h"
 #include "HistoryItem.h"
+#include "InspectorInstrumentation.h"
 #include "LocalFrame.h"
 #include "LocalFrameLoaderClient.h"
 #include "Logging.h"
@@ -309,6 +310,8 @@ ExceptionOr<void> History::stateObjectAdded(RefPtr<SerializedScriptValue>&& data
     }
 
     frame->loader().updateURLAndHistory(fullURL, WTFMove(data), historyBehavior);
+    InspectorInstrumentation::didNavigateWithinPage(*frame);
+
     return { };
 }
 
diff --git a/Source/WebCore/page/LocalFrame.cpp b/Source/WebCore/page/LocalFrame.cpp
index 43cbdcdc0a278fda65592af1a7b20babf0e055e4..11efd76361ace87f0ad276525cec399e2a103595 100644
--- a/Source/WebCore/page/LocalFrame.cpp
+++ b/Source/WebCore/page/LocalFrame.cpp
@@ -41,6 +41,7 @@
 #include "CachedResourceLoader.h"
 #include "Chrome.h"
 #include "ChromeClient.h"
+#include "ComposedTreeIterator.h"
 #include "DocumentLoader.h"
 #include "DocumentType.h"
 #include "Editing.h"
@@ -57,6 +58,7 @@
 #include "FrameSelection.h"
 #include "GraphicsContext.h"
 #include "GraphicsLayer.h"
+#include "HTMLAreaElement.h"
 #include "HTMLAttachmentElement.h"
 #include "HTMLFormControlElement.h"
 #include "HTMLFormElement.h"
@@ -77,6 +79,7 @@
 #include "Logging.h"
 #include "Navigator.h"
 #include "NodeList.h"
+#include "NodeRenderStyle.h"
 #include "NodeTraversal.h"
 #include "Page.h"
 #include "ProcessSyncClient.h"
@@ -193,6 +196,7 @@ LocalFrame::LocalFrame(Page& page, ClientCreator&& clientCreator, FrameIdentifie
 
 void LocalFrame::init()
 {
+    InspectorInstrumentation::frameAttached(this);
     protectedLoader()->init();
 }
 
@@ -409,7 +413,7 @@ void LocalFrame::orientationChanged()
 IntDegrees LocalFrame::orientation() const
 {
     if (RefPtr page = this->page())
-        return page->chrome().client().deviceOrientation();
+        return page->orientation();
     return 0;
 }
 #endif // ENABLE(ORIENTATION_EVENTS)
@@ -1381,6 +1385,364 @@ void LocalFrame::setScrollingMode(ScrollbarMode scrollingMode)
         view->setCanHaveScrollbars(m_scrollingMode != ScrollbarMode::AlwaysOff);
 }
 
+#if !PLATFORM(IOS_FAMILY)
+
+void LocalFrame::betterApproximateNode(const IntPoint& testPoint, const NodeQualifier& nodeQualifierFunction, Node*& best, Node* failedNode, IntPoint& bestPoint, IntRect& bestRect, const IntRect& testRect)
+{
+    IntRect candidateRect;
+    constexpr OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly };
+    auto* candidate = nodeQualifierFunction(eventHandler().hitTestResultAtPoint(testPoint, hitType), failedNode, &candidateRect);
+
+    // Bail if we have no candidate, or the candidate is already equal to our current best node,
+    // or our candidate is the avoidedNode and there is a current best node.
+    if (!candidate || candidate == best)
+        return;
+
+    // The document should never be considered the best alternative.
+    if (candidate->isDocumentNode())
+        return;
+
+    if (best) {
+        IntRect bestIntersect = intersection(testRect, bestRect);
+        IntRect candidateIntersect = intersection(testRect, candidateRect);
+        // if the candidate intersection is smaller than the current best intersection, bail.
+        if (candidateIntersect.width() * candidateIntersect.height() <= bestIntersect.width() * bestIntersect.height())
+            return;
+    }
+
+    // At this point we either don't have a previous best, or our current candidate has a better intersection.
+    best = candidate;
+    bestPoint = testPoint;
+    bestRect = candidateRect;
+}
+
+bool LocalFrame::hitTestResultAtViewportLocation(const FloatPoint& viewportLocation, HitTestResult& hitTestResult, IntPoint& center)
+{
+    if (!m_doc || !m_doc->renderView())
+        return false;
+
+    FrameView* view = m_view.get();
+    if (!view)
+        return false;
+
+    center = view->windowToContents(roundedIntPoint(viewportLocation));
+    constexpr OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowVisibleChildFrameContentOnly };
+    hitTestResult = eventHandler().hitTestResultAtPoint(center, hitType);
+    return true;
+}
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
+Node* LocalFrame::qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier& nodeQualifierFunction, ShouldApproximate shouldApproximate, ShouldFindRootEditableElement shouldFindRootEditableElement)
+{
+    adjustedViewportLocation = viewportLocation;
+
+    IntPoint testCenter;
+    HitTestResult candidateInfo;
+    if (!hitTestResultAtViewportLocation(viewportLocation, candidateInfo, testCenter))
+        return nullptr;
+
+    IntPoint bestPoint = testCenter;
+
+    // We have the candidate node at the location, check whether it or one of its ancestors passes
+    // the qualifier function, which typically checks if the node responds to a particular event type.
+    Node* approximateNode = nodeQualifierFunction(candidateInfo, 0, 0);
+
+    if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode && approximateNode->isContentEditable()) {
+        // If we are in editable content, we look for the root editable element.
+        approximateNode = approximateNode->rootEditableElement();
+        // If we have a focusable node, there is no need to approximate.
+        if (approximateNode)
+            shouldApproximate = ShouldApproximate::No;
+    }
+
+    float scale = page() ? page()->pageScaleFactor() : 1;
+#if PLATFORM(IOS_FAMILY)
+    float ppiFactor = screenPPIFactor();
+#else
+    float ppiFactor = 326; // most popular iPhone PPI
+#endif
+
+    static const float unscaledSearchRadius = 15;
+    int searchRadius = static_cast<int>(unscaledSearchRadius * ppiFactor / scale);
+
+    if (approximateNode && shouldApproximate == ShouldApproximate::Yes) {
+        const float testOffsets[] = {
+            -.3f, -.3f,
+            -.6f, -.6f,
+            +.3f, +.3f,
+            -.9f, -.9f,
+        };
+
+        Node* originalApproximateNode = approximateNode;
+        for (unsigned n = 0; n < std::size(testOffsets); n += 2) {
+            IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius);
+            IntPoint testPoint = testCenter + testOffset;
+
+            constexpr OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowChildFrameContent };
+            auto candidateInfo = eventHandler().hitTestResultAtPoint(testPoint, hitType);
+            Node* candidateNode = nodeQualifierFunction(candidateInfo, 0, 0);
+            if (candidateNode && candidateNode->isDescendantOf(originalApproximateNode)) {
+                approximateNode = candidateNode;
+                bestPoint = testPoint;
+                break;
+            }
+        }
+    } else if (!approximateNode && shouldApproximate == ShouldApproximate::Yes) {
+        // Grab the closest parent element of our failed candidate node.
+        Node* candidate = candidateInfo.innerNode();
+        Node* failedNode = candidate;
+
+        while (candidate && !candidate->isElementNode())
+            candidate = candidate->parentInComposedTree();
+
+        if (candidate)
+            failedNode = candidate;
+
+        // The center point was tested earlier.
+        const float testOffsets[] = {
+            -.3f, -.3f,
+            +.3f, -.3f,
+            -.3f, +.3f,
+            +.3f, +.3f,
+            -.6f, -.6f,
+            +.6f, -.6f,
+            -.6f, +.6f,
+            +.6f, +.6f,
+            -1.f, 0,
+            +1.f, 0,
+            0, +1.f,
+            0, -1.f,
+        };
+        IntRect bestFrame;
+        IntRect testRect(testCenter, IntSize());
+        testRect.inflate(searchRadius);
+        int currentTestRadius = 0;
+        for (unsigned n = 0; n < std::size(testOffsets); n += 2) {
+            IntSize testOffset(testOffsets[n] * searchRadius, testOffsets[n + 1] * searchRadius);
+            IntPoint testPoint = testCenter + testOffset;
+            int testRadius = std::max(abs(testOffset.width()), abs(testOffset.height()));
+            if (testRadius > currentTestRadius) {
+                // Bail out with the best match within a radius
+                currentTestRadius = testRadius;
+                if (approximateNode)
+                    break;
+            }
+            betterApproximateNode(testPoint, nodeQualifierFunction, approximateNode, failedNode, bestPoint, bestFrame, testRect);
+        }
+    }
+
+    if (approximateNode) {
+        IntPoint p = m_view->contentsToWindow(bestPoint);
+        adjustedViewportLocation = p;
+        if (shouldFindRootEditableElement == ShouldFindRootEditableElement::Yes && approximateNode->isContentEditable()) {
+            // When in editable content, look for the root editable node again,
+            // since this could be the node found with the approximation.
+            approximateNode = approximateNode->rootEditableElement();
+        }
+    }
+
+    return approximateNode;
+}
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_END
+
+Node* LocalFrame::deepestNodeAtLocation(const FloatPoint& viewportLocation)
+{
+    IntPoint center;
+    HitTestResult hitTestResult;
+    if (!hitTestResultAtViewportLocation(viewportLocation, hitTestResult, center))
+        return nullptr;
+
+    return hitTestResult.innerNode();
+}
+
+static bool nodeIsMouseFocusable(Node& node)
+{
+    if (!is<Element>(node))
+        return false;
+
+    auto& element = downcast<Element>(node);
+    if (element.isMouseFocusable())
+        return true;
+
+    if (RefPtr shadowRoot = element.shadowRoot()) {
+        if (shadowRoot->delegatesFocus()) {
+            for (auto& node : composedTreeDescendants(element)) {
+                if (is<Element>(node) && downcast<Element>(node).isMouseFocusable())
+                    return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+static bool nodeWillRespondToMouseEvents(Node& node)
+{
+    return node.willRespondToMouseClickEvents() || node.willRespondToMouseMoveEvents() || nodeIsMouseFocusable(node);
+}
+
+Node* LocalFrame::approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation)
+{
+    // This function is only used for UIWebView.
+    auto&& ancestorRespondingToClickEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* {
+        bool bodyHasBeenReached = false;
+        bool pointerCursorStillValid = true;
+
+        if (nodeBounds)
+            *nodeBounds = IntRect();
+
+        auto node = hitTestResult.innerNode();
+        if (!node)
+            return nullptr;
+
+        Node* pointerCursorNode = nullptr;
+        for (; node && node != terminationNode; node = node->parentInComposedTree()) {
+            // We only accept pointer nodes before reaching the body tag.
+            if (node->hasTagName(HTMLNames::bodyTag)) {
+                // Make sure we cover the case of an empty editable body.
+                if (!pointerCursorNode && node->isContentEditable())
+                    pointerCursorNode = node;
+                bodyHasBeenReached = true;
+                pointerCursorStillValid = false;
+            }
+
+            // If we already have a pointer, and we reach a table, don't accept it.
+            if (pointerCursorNode && (node->hasTagName(HTMLNames::tableTag) || node->hasTagName(HTMLNames::tbodyTag)))
+                pointerCursorStillValid = false;
+
+            // If we haven't reached the body, and we are still paying attention to pointer cursors, and the node has a pointer cursor.
+            if (pointerCursorStillValid && node->renderStyle() && node->renderStyle()->cursor() == CursorType::Pointer)
+                pointerCursorNode = node;
+            else if (pointerCursorNode) {
+                // We want the lowest unbroken chain of pointer cursors.
+                pointerCursorStillValid = false;
+            }
+
+            if (nodeWillRespondToMouseEvents(*node)) {
+                // If we're at the body or higher, use the pointer cursor node (which may be null).
+                if (bodyHasBeenReached)
+                    node = pointerCursorNode;
+
+                // If we are interested about the frame, use it.
+                if (nodeBounds) {
+                    // This is a check to see whether this node is an area element. The only way this can happen is if this is the first check.
+                    if (node == hitTestResult.innerNode() && node != hitTestResult.innerNonSharedNode() && is<HTMLAreaElement>(*node))
+                        *nodeBounds = snappedIntRect(downcast<HTMLAreaElement>(*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<HTMLAreaElement>(*node))
+                        *nodeBounds = snappedIntRect(downcast<HTMLAreaElement>(*node).computeRect(hitTestResult.innerNonSharedNode()->renderer()));
+                    else if (node && node->renderer())
+                        *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true);
+                }
+
+                return node;
+            }
+        }
+
+        return nullptr;
+    };
+}
+
+Node* LocalFrame::nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* securityOrigin)
+{
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(securityOrigin), ShouldApproximate::Yes);
+}
+
+Node* LocalFrame::nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation)
+{
+    auto&& ancestorRespondingToDoubleClickEvent = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* {
+        if (nodeBounds)
+            *nodeBounds = IntRect();
+
+        auto* node = hitTestResult.innerNode();
+        if (!node)
+            return nullptr;
+
+        for (; node && node != terminationNode; node = node->parentInComposedTree()) {
+            if (!node->hasEventListeners(eventNames().dblclickEvent))
+                continue;
+#if ENABLE(TOUCH_EVENTS)
+            if (!node->allowsDoubleTapGesture())
+                continue;
+#endif
+            if (nodeBounds && node->renderer())
+                *nodeBounds = node->renderer()->absoluteBoundingBoxRect(true);
+            return node;
+        }
+        return nullptr;
+    };
+
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToDoubleClickEvent), ShouldApproximate::Yes);
+}
+
+Node* LocalFrame::nodeRespondingToInteraction(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation)
+{
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, ancestorRespondingToClickEventsNodeQualifier(), ShouldApproximate::Yes, ShouldFindRootEditableElement::No);
+}
+
+Node* LocalFrame::nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation)
+{
+    auto&& ancestorRespondingToScrollWheelEvents = [](const HitTestResult& hitTestResult, Node* terminationNode, IntRect* nodeBounds) -> Node* {
+        if (nodeBounds)
+            *nodeBounds = IntRect();
+
+        Node* scrollingAncestor = nullptr;
+        for (Node* node = hitTestResult.innerNode(); node && node != terminationNode && !node->hasTagName(HTMLNames::bodyTag); node = node->parentNode()) {
+            RenderObject* renderer = node->renderer();
+            if (!renderer)
+                continue;
+
+            if ((renderer->isRenderTextControlSingleLine() || renderer->isRenderTextControlMultiLine()) && downcast<RenderTextControl>(*renderer).canScroll()) {
+                scrollingAncestor = node;
+                continue;
+            }
+
+            auto& style = renderer->style();
+
+            if (renderer->hasNonVisibleOverflow()
+                && (style.overflowY() == Overflow::Auto || style.overflowY() == Overflow::Scroll
+                || style.overflowX() == Overflow::Auto || style.overflowX() == Overflow::Scroll)) {
+                scrollingAncestor = node;
+            }
+        }
+
+        return scrollingAncestor;
+    };
+
+    FloatPoint adjustedViewportLocation;
+    return qualifyingNodeAtViewportLocation(viewportLocation, adjustedViewportLocation, WTFMove(ancestorRespondingToScrollWheelEvents), ShouldApproximate::No);
+}
+
+#endif // !PLATFORM(IOS_FAMILY)
+
 } // namespace WebCore
 
 #undef FRAME_RELEASE_LOG_ERROR
diff --git a/Source/WebCore/page/LocalFrame.h b/Source/WebCore/page/LocalFrame.h
index a585d427d1e7fd0f04defd8bb0e80841356f4948..05434b295c929791a1f14ab674ea7e0390e8e0ff 100644
--- a/Source/WebCore/page/LocalFrame.h
+++ b/Source/WebCore/page/LocalFrame.h
@@ -28,8 +28,10 @@
 #pragma once
 
 #include "AdjustViewSizeOrNot.h"
+#include "DOMPasteAccess.h"
 #include "Document.h"
 #include "Frame.h"
+#include "IntDegrees.h"
 #include "ScrollTypes.h"
 #include "UserScriptTypes.h"
 #include <wtf/CheckedRef.h>
@@ -115,8 +117,8 @@ enum {
 };
 
 enum OverflowScrollAction { DoNotPerformOverflowScroll, PerformOverflowScroll };
-using NodeQualifier = Function<Node* (const HitTestResult&, Node* terminationNode, IntRect* nodeBounds)>;
 #endif
+using NodeQualifier = Function<Node* (const HitTestResult&, Node* terminationNode, IntRect* nodeBounds)>;
 
 class LocalFrame final : public Frame {
 public:
@@ -227,10 +229,6 @@ public:
     WEBCORE_EXPORT DataDetectionResultsStorage& dataDetectionResults();
 #endif
 
-#if PLATFORM(IOS_FAMILY)
-    const ViewportArguments& viewportArguments() const;
-    WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&);
-
     WEBCORE_EXPORT Node* deepestNodeAtLocation(const FloatPoint& viewportLocation);
     WEBCORE_EXPORT Node* nodeRespondingToClickEvents(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, SecurityOrigin* = nullptr);
     WEBCORE_EXPORT Node* nodeRespondingToDoubleClickEvent(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation);
@@ -238,6 +236,10 @@ public:
     WEBCORE_EXPORT Node* nodeRespondingToScrollWheelEvents(const FloatPoint& viewportLocation);
     WEBCORE_EXPORT Node* approximateNodeAtViewportLocationLegacy(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation);
 
+#if PLATFORM(IOS_FAMILY)
+    const ViewportArguments& viewportArguments() const;
+    WEBCORE_EXPORT void setViewportArguments(const ViewportArguments&);
+
     WEBCORE_EXPORT NSArray *wordsInCurrentParagraph() const;
     WEBCORE_EXPORT CGRect renderRectForPoint(CGPoint, bool* isReplaced, float* fontSize) const;
 
@@ -305,6 +307,7 @@ public:
 
     WEBCORE_EXPORT FloatSize screenSize() const;
     void setOverrideScreenSize(FloatSize&&);
+    bool hasScreenSizeOverride() const { return !m_overrideScreenSize.isEmpty(); }
 
     void selfOnlyRef();
     void selfOnlyDeref();
@@ -368,7 +371,6 @@ private:
 #if ENABLE(DATA_DETECTION)
     std::unique_ptr<DataDetectionResultsStorage> 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);
 
@@ -376,6 +378,7 @@ private:
     enum class ShouldFindRootEditableElement : bool { No, Yes };
     Node* qualifyingNodeAtViewportLocation(const FloatPoint& viewportLocation, FloatPoint& adjustedViewportLocation, const NodeQualifier&, ShouldApproximate, ShouldFindRootEditableElement = ShouldFindRootEditableElement::Yes);
 
+#if PLATFORM(IOS_FAMILY)
     void setTimersPausedInternal(bool);
 
     ViewportArguments m_viewportArguments;
diff --git a/Source/WebCore/page/Page.cpp b/Source/WebCore/page/Page.cpp
index 45764553395dc05bb5dbbcebca65ae441b827ee6..4452870fa80d2233bf22720e6730ebcfb5763557 100644
--- a/Source/WebCore/page/Page.cpp
+++ b/Source/WebCore/page/Page.cpp
@@ -632,6 +632,45 @@ void Page::setOverrideViewportArguments(const std::optional<ViewportArguments>&
         document->updateViewportArguments();
 }
 
+FloatSize Page::screenSize()
+{
+    auto* localMainFrame = dynamicDowncast<LocalFrame>(mainFrame());
+    RefPtr frameView = localMainFrame ? localMainFrame->view() : nullptr;
+    if (!frameView)
+        return { };
+    return m_overrideScreenSize.value_or(screenRect(frameView.get()).size());
+}
+
+void Page::setOverrideScreenSize(std::optional<FloatSize> size)
+{
+    if (size == m_overrideScreenSize)
+        return;
+
+    m_overrideScreenSize = size;
+    auto* localMainFrame = dynamicDowncast<LocalFrame>(mainFrame());
+    if (auto* document = localMainFrame ? localMainFrame->document() : nullptr)
+        document->updateViewportArguments();
+}
+
+#if ENABLE(ORIENTATION_EVENTS)
+int Page::orientation() const
+{
+    return m_overrideOrientation.value_or(chrome().client().deviceOrientation());
+}
+
+void Page::setOverrideOrientation(std::optional<int> orientation)
+{
+    if (orientation == m_overrideOrientation)
+        return;
+
+    m_overrideOrientation = orientation;
+
+    auto* localMainFrame = dynamicDowncast<LocalFrame>(mainFrame());
+    if (localMainFrame)
+        localMainFrame->orientationChanged();
+}
+#endif
+
 ScrollingCoordinator* Page::scrollingCoordinator()
 {
     if (!m_scrollingCoordinator && m_settings->scrollingCoordinatorEnabled()) {
@@ -4018,6 +4057,26 @@ void Page::setUseDarkAppearanceOverride(std::optional<bool> valueOverride)
 #endif
 }
 
+void Page::setUseReducedMotionOverride(std::optional<bool> valueOverride)
+{
+    if (valueOverride == m_useReducedMotionOverride)
+        return;
+
+    m_useReducedMotionOverride = valueOverride;
+
+    appearanceDidChange();
+}
+
+void Page::setUseForcedColorsOverride(std::optional<bool> valueOverride)
+{
+    if (valueOverride == m_useForcedColorsOverride)
+        return;
+
+    m_useForcedColorsOverride = valueOverride;
+
+    appearanceDidChange();
+}
+
 void Page::setFullscreenInsets(const FloatBoxExtent& insets)
 {
     if (insets == m_fullscreenInsets)
diff --git a/Source/WebCore/page/Page.h b/Source/WebCore/page/Page.h
index 35b77368186161eef9637470b70d438f358ea6aa..2619738f4cb1e7c060435b22921aaca9e5003de0 100644
--- a/Source/WebCore/page/Page.h
+++ b/Source/WebCore/page/Page.h
@@ -360,6 +360,9 @@ public:
     const std::optional<ViewportArguments>& overrideViewportArguments() const { return m_overrideViewportArguments; }
     WEBCORE_EXPORT void setOverrideViewportArguments(const std::optional<ViewportArguments>&);
 
+    WEBCORE_EXPORT FloatSize screenSize();
+    void setOverrideScreenSize(std::optional<FloatSize> size);
+
     static void refreshPlugins(bool reload);
     WEBCORE_EXPORT PluginData& pluginData();
     void clearPluginData();
@@ -431,6 +434,10 @@ public:
 #if ENABLE(DRAG_SUPPORT)
     DragController& dragController() { return m_dragController.get(); }
     const DragController& dragController() const { return m_dragController.get(); }
+#if PLATFORM(MAC)
+    void setDragPasteboardName(const String& pasteboardName) { m_overrideDragPasteboardName = pasteboardName; }
+    const String& overrideDragPasteboardName() { return m_overrideDragPasteboardName; }
+#endif
 #endif
     FocusController& focusController() const { return *m_focusController; }
     WEBCORE_EXPORT CheckedRef<FocusController> checkedFocusController() const;
@@ -617,6 +624,10 @@ public:
     WEBCORE_EXPORT void setUseColorAppearance(bool useDarkAppearance, bool useElevatedUserInterfaceLevel);
     bool defaultUseDarkAppearance() const { return m_useDarkAppearance; }
     void setUseDarkAppearanceOverride(std::optional<bool>);
+    std::optional<bool> useReducedMotionOverride() const { return m_useReducedMotionOverride; }
+    void setUseReducedMotionOverride(std::optional<bool>);
+    std::optional<bool> useForcedColorsOverride() const { return m_useForcedColorsOverride; }
+    void setUseForcedColorsOverride(std::optional<bool>);
 
 #if ENABLE(TEXT_AUTOSIZING)
     float textAutosizingWidth() const { return m_textAutosizingWidth; }
@@ -1070,6 +1081,11 @@ public:
     WEBCORE_EXPORT void setInteractionRegionsEnabled(bool);
 #endif
 
+#if ENABLE(ORIENTATION_EVENTS)
+    int orientation() const;
+    WEBCORE_EXPORT void setOverrideOrientation(std::optional<int>);
+#endif
+
 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
     DeviceOrientationUpdateProvider* deviceOrientationUpdateProvider() const { return m_deviceOrientationUpdateProvider.get(); }
 #endif
@@ -1325,6 +1341,9 @@ private:
 
 #if ENABLE(DRAG_SUPPORT)
     UniqueRef<DragController> m_dragController;
+#if PLATFORM(MAC)
+    String m_overrideDragPasteboardName;
+#endif
 #endif
     std::unique_ptr<FocusController> m_focusController;
 #if ENABLE(CONTEXT_MENUS)
@@ -1405,6 +1424,8 @@ private:
     bool m_useElevatedUserInterfaceLevel { false };
     bool m_useDarkAppearance { false };
     std::optional<bool> m_useDarkAppearanceOverride;
+    std::optional<bool> m_useReducedMotionOverride;
+    std::optional<bool> m_useForcedColorsOverride;
 
 #if ENABLE(TEXT_AUTOSIZING)
     float m_textAutosizingWidth { 0 };
@@ -1585,6 +1606,11 @@ private:
 #endif
 
     std::optional<ViewportArguments> m_overrideViewportArguments;
+    std::optional<FloatSize> m_overrideScreenSize;
+
+#if ENABLE(ORIENTATION_EVENTS)
+    std::optional<int> m_overrideOrientation;
+#endif
 
 #if ENABLE(DEVICE_ORIENTATION) && PLATFORM(IOS_FAMILY)
     RefPtr<DeviceOrientationUpdateProvider> m_deviceOrientationUpdateProvider;
diff --git a/Source/WebCore/page/PageConsoleClient.cpp b/Source/WebCore/page/PageConsoleClient.cpp
index 7a951f2599ee142d22318055badaa4c6b1acc53a..51fda467e6ff06249e58ca1cda5d955e68370c6c 100644
--- a/Source/WebCore/page/PageConsoleClient.cpp
+++ b/Source/WebCore/page/PageConsoleClient.cpp
@@ -437,4 +437,9 @@ Ref<Page> PageConsoleClient::protectedPage() const
     return m_page.get();
 }
 
+void PageConsoleClient::bindingCalled(JSC::JSGlobalObject* globalObject, const String& name, const String& arg)
+{
+    InspectorInstrumentation::bindingCalled(m_page, globalObject, name, arg);
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/page/PageConsoleClient.h b/Source/WebCore/page/PageConsoleClient.h
index 153fc36199f26adbfb61cbef6744ffe31a68b951..cc667e06700013fd5e994467e19536d2e4cab189 100644
--- a/Source/WebCore/page/PageConsoleClient.h
+++ b/Source/WebCore/page/PageConsoleClient.h
@@ -86,6 +86,7 @@ private:
     void record(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override;
     void recordEnd(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override;
     void screenshot(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override;
+    void bindingCalled(JSC::JSGlobalObject*, const String& name, const String& arg) override;
 
     Ref<Page> protectedPage() const;
 
diff --git a/Source/WebCore/page/PointerCaptureController.cpp b/Source/WebCore/page/PointerCaptureController.cpp
index e24fbc296a8bbfb784eaeb3b773b6384c2679b7b..a172c06103bb20d20e905d7cacec0830fd464f02 100644
--- a/Source/WebCore/page/PointerCaptureController.cpp
+++ b/Source/WebCore/page/PointerCaptureController.cpp
@@ -204,7 +204,7 @@ bool PointerCaptureController::preventsCompatibilityMouseEventsForIdentifier(Poi
     return capturingData && capturingData->preventsCompatibilityMouseEvents;
 }
 
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
 static bool hierarchyHasCapturingEventListeners(Element* target, const AtomString& eventName)
 {
     for (RefPtr<ContainerNode> currentNode = target; currentNode; currentNode = currentNode->parentInComposedTree()) {
@@ -554,7 +554,7 @@ void PointerCaptureController::cancelPointer(PointerID pointerId, const IntPoint
     capturingData->pendingTargetOverride = nullptr;
     capturingData->state = CapturingData::State::Cancelled;
 
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
     capturingData->previousTarget = nullptr;
 #endif
 
diff --git a/Source/WebCore/page/PointerCaptureController.h b/Source/WebCore/page/PointerCaptureController.h
index 9245baa0c317bb3dfa8a2a1666953d320cb85ee1..55445eb29e095ef4b6d6918728885a267a3b8183 100644
--- a/Source/WebCore/page/PointerCaptureController.h
+++ b/Source/WebCore/page/PointerCaptureController.h
@@ -60,7 +60,7 @@ public:
 
     RefPtr<PointerEvent> pointerEventForMouseEvent(const MouseEvent&, PointerID, const String& pointerType);
 
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
     void dispatchEventForTouchAtIndex(EventTarget&, const PlatformTouchEvent&, unsigned, bool isPrimary, WindowProxy&, const IntPoint&);
 #endif
 
@@ -81,12 +81,12 @@ private:
         WeakPtr<Document, WeakPtrImplWithEventTargetData> activeDocument;
         RefPtr<Element> pendingTargetOverride;
         RefPtr<Element> targetOverride;
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
         RefPtr<Element> previousTarget;
 #endif
         bool hasAnyElement() const {
             return pendingTargetOverride || targetOverride
-#if ENABLE(TOUCH_EVENTS) && (PLATFORM(IOS_FAMILY) || PLATFORM(WPE))
+#if ENABLE(TOUCH_EVENTS)
                 || previousTarget
 #endif
                 ;
diff --git a/Source/WebCore/page/Screen.cpp b/Source/WebCore/page/Screen.cpp
index 24ed7c019bea4df52f2883db0e40bdbc2dc74ebd..a788f534d9e0e8124153c7f380b4fdb232c51a1a 100644
--- a/Source/WebCore/page/Screen.cpp
+++ b/Source/WebCore/page/Screen.cpp
@@ -124,6 +124,9 @@ int Screen::availLeft() const
     if (shouldApplyScreenFingerprintingProtections(*frame))
         return 0;
 
+    if (frame->hasScreenSizeOverride())
+        return 0;
+
     return static_cast<int>(screenAvailableRect(frame->protectedView().get()).x());
 }
 
@@ -139,6 +142,9 @@ int Screen::availTop() const
     if (shouldApplyScreenFingerprintingProtections(*frame))
         return 0;
 
+    if (frame->hasScreenSizeOverride())
+        return 0;
+
     return static_cast<int>(screenAvailableRect(frame->protectedView().get()).y());
 }
 
@@ -154,6 +160,9 @@ int Screen::availHeight() const
     if (shouldApplyScreenFingerprintingProtections(*frame))
         return static_cast<int>(frame->screenSize().height());
 
+    if (frame->hasScreenSizeOverride())
+        return static_cast<int>(frame->screenSize().height());
+
     return static_cast<int>(screenAvailableRect(frame->protectedView().get()).height());
 }
 
@@ -169,6 +178,9 @@ int Screen::availWidth() const
     if (shouldApplyScreenFingerprintingProtections(*frame))
         return static_cast<int>(frame->screenSize().width());
 
+    if (frame->hasScreenSizeOverride())
+        return static_cast<int>(frame->screenSize().width());
+
     return static_cast<int>(screenAvailableRect(frame->protectedView().get()).width());
 }
 
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
index 74e4e43482f969cf90c47d897f8226672d748cff..d2b491a7346677253891f4057b2cdb1d679fe08b 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
@@ -347,6 +347,8 @@ bool ContentSecurityPolicy::allowContentSecurityPolicySourceStarToMatchAnyProtoc
 template<typename Predicate, typename... Args>
 typename std::enable_if<!std::is_convertible<Predicate, ContentSecurityPolicy::ViolatedDirectiveCallback>::value, bool>::type ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, Predicate&& predicate, Args&&... args) const
 {
+    if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get()))
+        return true;
     bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly;
     for (auto& policy : m_policies) {
         if (policy->isReportOnly() != isReportOnly)
@@ -360,6 +362,8 @@ typename std::enable_if<!std::is_convertible<Predicate, ContentSecurityPolicy::V
 template<typename Predicate, typename... Args>
 bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposition, ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const
 {
+    if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get()))
+        return true;
     bool isReportOnly = disposition == ContentSecurityPolicy::Disposition::ReportOnly;
     bool isAllowed = true;
     for (auto& policy : m_policies) {
@@ -376,6 +380,8 @@ bool ContentSecurityPolicy::allPoliciesWithDispositionAllow(Disposition disposit
 template<typename Predicate, typename... Args>
 bool ContentSecurityPolicy::allPoliciesAllow(ViolatedDirectiveCallback&& callback, Predicate&& predicate, Args&&... args) const
 {
+    if (InspectorInstrumentation::shouldBypassCSP(m_scriptExecutionContext.get()))
+        return true;
     bool isAllowed = true;
     for (auto& policy : m_policies) {
         if (const ContentSecurityPolicyDirective* violatedDirective = (policy.get()->*predicate)(std::forward<Args>(args)...)) {
diff --git a/Source/WebCore/page/wpe/DragControllerWPE.cpp b/Source/WebCore/page/wpe/DragControllerWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..803239911006cfb3b03ea911c003f2d233f67600
--- /dev/null
+++ b/Source/WebCore/page/wpe/DragControllerWPE.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007-20 Apple Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DragController.h"
+
+#include "DataTransfer.h"
+#include "Document.h"
+#include "DragData.h"
+#include "Editor.h"
+#include "Element.h"
+#include "Frame.h"
+#include "FrameDestructionObserverInlines.h"
+#include "Pasteboard.h"
+#include "markup.h"
+
+namespace WebCore {
+
+// FIXME: These values are straight out of DragControllerMac, so probably have
+// little correlation with Gdk standards...
+const int DragController::MaxOriginalImageArea = 1500 * 1500;
+const int DragController::DragIconRightInset = 7;
+const int DragController::DragIconBottomInset = 3;
+
+const float DragController::DragImageAlpha = 0.75f;
+
+bool DragController::isCopyKeyDown(const DragData& dragData)
+{
+    return dragData.flags().contains(DragApplicationFlags::IsCopyKeyDown);
+}
+
+std::optional<DragOperation> DragController::dragOperation(const DragData& dragData)
+{
+    // FIXME: This logic is incomplete
+    if (dragData.containsURL())
+        return DragOperation::Copy;
+
+    return std::nullopt;
+}
+
+const IntSize& DragController::maxDragImageSize()
+{
+    static const IntSize maxDragImageSize(200, 200);
+    return maxDragImageSize;
+}
+
+void DragController::cleanupAfterSystemDrag()
+{
+}
+
+void DragController::declareAndWriteDragImage(DataTransfer& dataTransfer, Element& element, const URL& url, const String& label)
+{
+    auto* frame = element.document().frame();
+    ASSERT(frame);
+    frame->editor().writeImageToPasteboard(dataTransfer.pasteboard(), element, url, label);
+}
+
+}
diff --git a/Source/WebCore/platform/Cairo.cmake b/Source/WebCore/platform/Cairo.cmake
index 29492dd39b08db28aad2bf2439eb3e2bbcf25ad7..2b603cb8440b1b5057c87fcbd6909c61bae4ceb8 100644
--- a/Source/WebCore/platform/Cairo.cmake
+++ b/Source/WebCore/platform/Cairo.cmake
@@ -14,6 +14,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
     platform/graphics/cairo/ImageBufferCairoBackend.h
     platform/graphics/cairo/ImageBufferCairoImageSurfaceBackend.h
     platform/graphics/cairo/ImageBufferCairoSurfaceBackend.h
+    platform/graphics/cairo/ImageBufferUtilitiesCairo.h
     platform/graphics/cairo/RefPtrCairo.h
 )
 
diff --git a/Source/WebCore/platform/DragData.h b/Source/WebCore/platform/DragData.h
index 2ebb3221cb3818f20abc7b7c3307ea7644f49d49..e0bffb6f5adee0b0a202340f633c2def1955b384 100644
--- a/Source/WebCore/platform/DragData.h
+++ b/Source/WebCore/platform/DragData.h
@@ -47,7 +47,7 @@ typedef void* DragDataRef;
 
 #elif PLATFORM(WIN)
 typedef struct IDataObject* DragDataRef;
-#elif PLATFORM(GTK)
+#elif PLATFORM(GTK) || PLATFORM(WPE)
 namespace WebCore {
 class SelectionData;
 }
@@ -92,8 +92,8 @@ public:
     // is initialized by the decoder and not in the constructor.
     DragData() = default;
 #if PLATFORM(WIN)
-    WEBCORE_EXPORT DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<DragOperation> sourceOperationMask, OptionSet<DragApplicationFlags> = { }, std::optional<PageIdentifier> pageID = std::nullopt);
-    const DragDataMap& dragDataMap();
+    WEBCORE_EXPORT DragData(const DragDataMap&, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<DragOperation> sourceOperationMask, OptionSet<DragApplicationFlags> = { }, OptionSet<DragDestinationAction> = anyDragDestinationAction(), std::optional<PageIdentifier> pageID = std::nullopt);
+    WEBCORE_EXPORT const DragDataMap& dragDataMap() const;
     void getDragFileDescriptorData(int& size, String& pathname);
     void getDragFileContentData(int size, void* dataBlob);
 #endif
@@ -143,7 +143,7 @@ private:
     String m_pasteboardName;
 #endif
 #if PLATFORM(WIN)
-    DragDataMap m_dragDataMap;
+    mutable DragDataMap m_dragDataMap;
 #endif
     bool m_disallowFileAccess { false };
 };
diff --git a/Source/WebCore/platform/DragImage.cpp b/Source/WebCore/platform/DragImage.cpp
index c359242a7967dab94b8dc3c276a6df5473527145..64b0c6a0bfdf27a0305c25e8b8e0cda637450aa4 100644
--- a/Source/WebCore/platform/DragImage.cpp
+++ b/Source/WebCore/platform/DragImage.cpp
@@ -280,7 +280,7 @@ DragImage::~DragImage()
         deleteDragImage(m_dragImageRef);
 }
 
-#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN)
+#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WIN) && !PLATFORM(WPE)
 
 IntSize dragImageSize(DragImageRef)
 {
diff --git a/Source/WebCore/platform/Pasteboard.h b/Source/WebCore/platform/Pasteboard.h
index 33841aa5cc1fc15557514d60096d8274234447c3..2c91d472a24c591215d6f2861aca6f86a00d086a 100644
--- a/Source/WebCore/platform/Pasteboard.h
+++ b/Source/WebCore/platform/Pasteboard.h
@@ -46,7 +46,7 @@ OBJC_CLASS NSString;
 OBJC_CLASS NSArray;
 #endif
 
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
 #include "SelectionData.h"
 #endif
 
@@ -108,7 +108,7 @@ struct PasteboardURL {
 #if PLATFORM(MAC)
     String userVisibleForm;
 #endif
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
     String markup;
 #endif
 };
@@ -197,6 +197,11 @@ public:
 #endif
 #endif
 
+#if PLATFORM(WPE) && ENABLE(DRAG_SUPPORT)
+    explicit Pasteboard(std::unique_ptr<PasteboardContext>&&, SelectionData&);
+    explicit Pasteboard(std::unique_ptr<PasteboardContext>&&, SelectionData&&);
+#endif
+
 #if PLATFORM(WIN)
     explicit Pasteboard(std::unique_ptr<PasteboardContext>&&, IDataObject*);
     explicit Pasteboard(std::unique_ptr<PasteboardContext>&&, WCDataObject*);
@@ -264,6 +269,12 @@ public:
     int64_t changeCount() const;
 #endif
 
+#if PLATFORM(WPE)
+    const SelectionData& selectionData() const {
+        return *m_selectionData;
+    }
+#endif
+
 #if PLATFORM(IOS_FAMILY)
     explicit Pasteboard(std::unique_ptr<PasteboardContext>&&, int64_t changeCount);
     explicit Pasteboard(std::unique_ptr<PasteboardContext>&&, const String& pasteboardName);
@@ -306,6 +317,7 @@ public:
     COMPtr<IDataObject> dataObject() const { return m_dataObject; }
     WEBCORE_EXPORT void setExternalDataObject(IDataObject*);
     const DragDataMap& dragDataMap() const { return m_dragDataMap; }
+    WEBCORE_EXPORT DragDataMap createDragDataMap();
     void writeURLToWritableDataObject(const URL&, const String&);
     COMPtr<WCDataObject> writableDataObject() const { return m_writableDataObject; }
     void writeImageToDataObject(Element&, const URL&); // FIXME: Layering violation.
@@ -358,6 +370,10 @@ private:
     int64_t m_changeCount { 0 };
 #endif
 
+#if PLATFORM(WPE)
+    std::optional<SelectionData> m_selectionData;
+#endif
+
 #if PLATFORM(COCOA)
     String m_pasteboardName;
     int64_t m_changeCount;
@@ -373,6 +389,7 @@ private:
     COMPtr<IDataObject> m_dataObject;
     COMPtr<WCDataObject> m_writableDataObject;
     DragDataMap m_dragDataMap;
+    bool m_forDrag = false;
 #endif
 };
 
diff --git a/Source/WebCore/platform/PlatformKeyboardEvent.h b/Source/WebCore/platform/PlatformKeyboardEvent.h
index 63ffd6ca32c3baee03db2a9419c4f7e9de45388a..c60c7a8d1f110472117c8c4e969fd05fef71f908 100644
--- a/Source/WebCore/platform/PlatformKeyboardEvent.h
+++ b/Source/WebCore/platform/PlatformKeyboardEvent.h
@@ -135,6 +135,7 @@ namespace WebCore {
         static String keyCodeForHardwareKeyCode(unsigned);
         static String keyIdentifierForGdkKeyCode(unsigned);
         static int windowsKeyCodeForGdkKeyCode(unsigned);
+        static unsigned gdkKeyCodeForWindowsKeyCode(int);
         static String singleCharacterString(unsigned);
 #endif
 
@@ -143,6 +144,7 @@ namespace WebCore {
         static String keyCodeForHardwareKeyCode(unsigned);
         static String keyIdentifierForWPEKeyCode(unsigned);
         static int windowsKeyCodeForWPEKeyCode(unsigned);
+        static unsigned WPEKeyCodeForWindowsKeyCode(int);
         static String singleCharacterString(unsigned);
 #endif
 
diff --git a/Source/WebCore/platform/PlatformScreen.cpp b/Source/WebCore/platform/PlatformScreen.cpp
index ae46341ba71c7f6df7c607bd852338cdb7f83fe1..a11db190d86f5e3ec4c7cee6c5b3ea93f2380646 100644
--- a/Source/WebCore/platform/PlatformScreen.cpp
+++ b/Source/WebCore/platform/PlatformScreen.cpp
@@ -73,3 +73,25 @@ const ScreenData* screenData(PlatformDisplayID screenDisplayID)
 } // namespace WebCore
 
 #endif // PLATFORM(COCOA) || PLATFORM(GTK) || (PLATFORM(WPE) && ENABLE(WPE_PLATFORM))
+
+#if ENABLE(TOUCH_EVENTS)
+namespace WebCore {
+
+static std::optional<bool> screenHasTouchDeviceOverride = std::nullopt;
+void setScreenHasTouchDeviceOverride(bool value) {
+  screenHasTouchDeviceOverride = value;
+}
+
+bool screenHasTouchDevice() {
+    if (screenHasTouchDeviceOverride)
+        return screenHasTouchDeviceOverride.value();
+    return platformScreenHasTouchDevice();
+}
+bool screenIsTouchPrimaryInputDevice() {
+    if (screenHasTouchDeviceOverride)
+        return screenHasTouchDeviceOverride.value();
+    return platformScreenIsTouchPrimaryInputDevice();
+}
+
+} // namespace WebCore
+#endif
diff --git a/Source/WebCore/platform/PlatformScreen.h b/Source/WebCore/platform/PlatformScreen.h
index 6ffb85dbfcc01be76ef498f4f7478747912ca7d7..a6e0a3347e36a01b9aeca524747d14ff63f4c529 100644
--- a/Source/WebCore/platform/PlatformScreen.h
+++ b/Source/WebCore/platform/PlatformScreen.h
@@ -154,12 +154,16 @@ WEBCORE_EXPORT float screenScaleFactor(UIScreen * = nullptr);
 #endif
 
 #if ENABLE(TOUCH_EVENTS)
-#if PLATFORM(GTK) || PLATFORM(WPE)
+WEBCORE_EXPORT void setScreenHasTouchDeviceOverride(bool);
+
 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/PlatformTouchEvent.h b/Source/WebCore/platform/PlatformTouchEvent.h
index 23f011953c66f401553bedfaef3485af215ae083..a73da2ebe47f0d8dc57f3d0159e8f299abb61c96 100644
--- a/Source/WebCore/platform/PlatformTouchEvent.h
+++ b/Source/WebCore/platform/PlatformTouchEvent.h
@@ -42,7 +42,7 @@ public:
 
     const Vector<PlatformTouchEvent>& predictedEvents() const { return m_predictedEvents; }
 
-#if PLATFORM(WPE)
+#if !ENABLE(IOS_TOUCH_EVENTS)
     // FIXME: since WPE currently does not send touch stationary events, we need to be able to set
     // TouchCancelled touchPoints subsequently
     void setTouchPoints(Vector<PlatformTouchPoint>& touchPoints) { m_touchPoints = touchPoints; }
diff --git a/Source/WebCore/platform/PlatformTouchPoint.h b/Source/WebCore/platform/PlatformTouchPoint.h
index 34715d27b529750fc866db87cd330b5184286771..3eefa218af075f76d98012cdeae7e4b344850116 100644
--- a/Source/WebCore/platform/PlatformTouchPoint.h
+++ b/Source/WebCore/platform/PlatformTouchPoint.h
@@ -49,7 +49,7 @@ public:
     {
     }
 
-#if PLATFORM(WPE)
+#if !ENABLE(IOS_TOUCH_EVENTS)
     // FIXME: since WPE currently does not send touch stationary events, we need to be able to
     // create a PlatformTouchPoint of type TouchCancelled artificially
     PlatformTouchPoint(unsigned id, State state, IntPoint screenPos, IntPoint pos)
diff --git a/Source/WebCore/platform/Skia.cmake b/Source/WebCore/platform/Skia.cmake
index b3a6d971c8e9935c8ee6fe16c91f4210a8ee22dc..72380815f319976a132079bb4b41bf5b429c87e3 100644
--- a/Source/WebCore/platform/Skia.cmake
+++ b/Source/WebCore/platform/Skia.cmake
@@ -13,6 +13,7 @@ list(APPEND WebCore_PRIVATE_FRAMEWORK_HEADERS
 
     platform/graphics/skia/GraphicsContextSkia.h
     platform/graphics/skia/ImageBufferSkiaBackend.h
+    platform/graphics/skia/ImageBufferUtilitiesSkia.h
     platform/graphics/skia/SkiaHarfBuzzFont.h
     platform/graphics/skia/SkiaHarfBuzzFontCache.h
     platform/graphics/skia/SkiaPaintingEngine.h
diff --git a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp
index 8f36dda49adafd4a542e24e3c4dd33d42be00d27..953b6f88f8deb597d2179a8cec7b717b7cf6dc5a 100644
--- a/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp
+++ b/Source/WebCore/platform/adwaita/ScrollbarThemeAdwaita.cpp
@@ -46,7 +46,7 @@
 
 namespace WebCore {
 
-static const unsigned scrollbarSize = 21;
+static const unsigned scrollbarSize = 0;
 static const unsigned scrollbarBorderSize = 1;
 static const unsigned thumbBorderSize = 1;
 static const unsigned overlayThumbSize = 3;
diff --git a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp
index d137ffd1a8ed0b788bd28197c6d7e9f7d14e852f..dcf8bf3f7ee6b037a370712e2ac36b6e2e4bbebc 100644
--- a/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp
+++ b/Source/WebCore/platform/graphics/cairo/ImageBufferUtilitiesCairo.cpp
@@ -48,6 +48,13 @@
 #include <wtf/glib/GUniquePtr.h>
 #endif
 
+#if PLATFORM(WPE) || PLATFORM(WIN)
+#include <stdio.h> // 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<u
     return cairo_surface_write_to_png_stream(image, writeFunction, output) == CAIRO_STATUS_SUCCESS;
 }
 
-Vector<uint8_t> encodeData(cairo_surface_t* image, const String& mimeType, std::optional<double>)
+static Vector<uint8_t> 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<uint8_t> output;
+    output.append(std::span { bufferPtr, bufferSize });
+    // Cannot use unique_ptr as bufferPtr changes during compression. GUniquePtr would work
+    // but it's under GLib and won't work on Windows.
+    free(bufferPtr);
+    return output;
+}
+
+Vector<uint8_t> encodeData(cairo_surface_t* image, const String& mimeType, std::optional<double> quality)
 {
+    if (mimeType == "image/jpeg"_s) {
+        int qualityPercent = 100;
+        if (quality)
+            qualityPercent = static_cast<int>(*quality * 100.0 + 0.5);
+        return encodeJpeg(image, qualityPercent);
+    }
+
     Vector<uint8_t> encodedImage;
     if (!image || !encodeImage(image, mimeType, &encodedImage))
         return { };
diff --git a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h
index 5b659c763b9754b025a63f89522954cc39915b9a..448b50a2b131361a75d3f816cdcbb6a102551280 100644
--- a/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h
+++ b/Source/WebCore/platform/graphics/cg/ImageBufferUtilitiesCG.h
@@ -38,7 +38,7 @@ WEBCORE_EXPORT uint8_t verifyImageBufferIsBigEnough(std::span<const uint8_t> buf
 
 RetainPtr<CFStringRef> utiFromImageBufferMIMEType(const String& mimeType);
 CFStringRef jpegUTI();
-Vector<uint8_t> encodeData(CGImageRef, const String& mimeType, std::optional<double> quality);
+WEBCORE_EXPORT Vector<uint8_t> encodeData(CGImageRef, const String& mimeType, std::optional<double> quality);
 Vector<uint8_t> encodeData(const PixelBuffer&, const String& mimeType, std::optional<double> quality);
 Vector<uint8_t> encodeData(std::span<const uint8_t>, const String& mimeType, std::optional<double> quality);
 
diff --git a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h b/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h
index 3d0ab7eceaf2a6321685bc362eb9b25600fd98fd..2d7e9a399bf2e9dc3f373d5fa3db99fa0908bd9d 100644
--- a/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h
+++ b/Source/WebCore/platform/graphics/filters/software/FEComponentTransferSoftwareApplier.h
@@ -23,6 +23,7 @@
 #pragma once
 
 #include "FilterEffectApplier.h"
+#include "PixelBuffer.h"
 #include <wtf/TZoneMalloc.h>
 
 namespace WebCore {
diff --git a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp
index eb9710f7d61121f2414c8aa6734dc27653e292bb..9c0c7b350a6140681242ce36a180d6866e3e0fc2 100644
--- a/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp
+++ b/Source/WebCore/platform/graphics/win/ComplexTextControllerUniscribe.cpp
@@ -169,6 +169,33 @@ static Vector<unsigned> stringIndicesFromClusters(const Vector<WORD>& clusters,
     return stringIndices;
 }
 
+static int compactScriptItemsIfNeeded(std::span<const UChar> cp, Vector<SCRIPT_ITEM>& items, int numItems, const Font* font)
+{
+    // https://bugs.webkit.org/show_bug.cgi?id=201214
+    // Uniscribe is overly aggressive in separating the runs. It'll split "3d_rotation" into "3", "d", "_" and "rotation" and we
+    // will ScriptShape them separately. As a result, a ligature for "3d_rotation" in the Material icon set
+    // (https://www.materialui.co/icon/3d-rotation) will not be used. A quick and dirty hack is to glue them back here, only making
+    // this apply to the readable characters, digits and _.
+
+    if (!numItems)
+        return numItems;
+
+    if (font->platformData().hasVariations())
+        return numItems;
+
+    bool allGoodCharacters = true;
+    for (unsigned i = 0; allGoodCharacters && i < cp.size(); ++i) {
+        const UChar c = cp[i];
+        allGoodCharacters = (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
+    }
+    if (!allGoodCharacters)
+        return numItems;
+
+    // Consume entire string into a single run. |items| is at least numItems + 1 long.
+    items[1] = items[numItems];
+    return 1;
+}
+
 void ComplexTextController::collectComplexTextRunsForCharacters(std::span<const UChar> cp, unsigned stringLocation, const Font* font)
 {
     if (!font) {
@@ -198,6 +225,8 @@ void ComplexTextController::collectComplexTextRunsForCharacters(std::span<const
     }
     items.resize(numItems + 1);
 
+    numItems = compactScriptItemsIfNeeded(cp, items, numItems, font);
+
     for (int i = 0; i < numItems; i++) {
         // Determine the string for this item.
         const UChar* str = cp.data() + items[i].iCharPos;
diff --git a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp
index 979ec06ecd698b60066dc6775bf1b647624baa56..1b3056aada9f352cc558f85fea0fd6c494b5201f 100644
--- a/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp
+++ b/Source/WebCore/platform/gtk/PlatformKeyboardEventGtk.cpp
@@ -37,8 +37,10 @@
 #include <gdk/gdk.h>
 #include <gdk/gdkkeysyms.h>
 #include <pal/text/TextEncoding.h>
+#include <wtf/HashMap.h>
 #include <wtf/HexNumber.h>
 #include <wtf/text/MakeString.h>
+#include <mutex>
 
 namespace WebCore {
 
@@ -1302,6 +1304,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForGdkKeyCode(unsigned keycode)
 
 }
 
+static const UncheckedKeyHashMap<int, unsigned>& gdkToWindowsKeyCodeMap()
+{
+    static UncheckedKeyHashMap<int, unsigned>* result;
+    static std::once_flag once;
+    std::call_once(
+        once,
+        [] {
+            const unsigned gdkKeyCodes[] = {
+                GDK_KEY_Cancel,
+                // FIXME: non-keypad keys should take precedence, so we skip GDK_KEY_KP_*
+                // GDK_KEY_KP_0,
+                // GDK_KEY_KP_1,
+                // GDK_KEY_KP_2,
+                // GDK_KEY_KP_3,
+                // GDK_KEY_KP_4,
+                // GDK_KEY_KP_5,
+                // GDK_KEY_KP_6,
+                // GDK_KEY_KP_7,
+                // GDK_KEY_KP_8,
+                // GDK_KEY_KP_9,
+                // GDK_KEY_KP_Multiply,
+                // GDK_KEY_KP_Add,
+                // GDK_KEY_KP_Subtract,
+                // GDK_KEY_KP_Decimal,
+                // GDK_KEY_KP_Divide,
+                // GDK_KEY_KP_Page_Up,
+                // GDK_KEY_KP_Page_Down,
+                // GDK_KEY_KP_End,
+                // GDK_KEY_KP_Home,
+                // GDK_KEY_KP_Left,
+                // GDK_KEY_KP_Up,
+                // GDK_KEY_KP_Right,
+                // GDK_KEY_KP_Down,
+                GDK_KEY_BackSpace,
+                // GDK_KEY_ISO_Left_Tab,
+                // GDK_KEY_3270_BackTab,
+                GDK_KEY_Tab,
+                GDK_KEY_Clear,
+                // GDK_KEY_ISO_Enter,
+                // GDK_KEY_KP_Enter,
+                GDK_KEY_Return,
+                GDK_KEY_Menu,
+                GDK_KEY_Pause,
+                GDK_KEY_AudioPause,
+                GDK_KEY_Caps_Lock,
+                GDK_KEY_Kana_Lock,
+                GDK_KEY_Kana_Shift,
+                GDK_KEY_Hangul,
+                GDK_KEY_Hangul_Hanja,
+                GDK_KEY_Kanji,
+                GDK_KEY_Escape,
+                GDK_KEY_space,
+                GDK_KEY_Page_Up,
+                GDK_KEY_Page_Down,
+                GDK_KEY_End,
+                GDK_KEY_Home,
+                GDK_KEY_Left,
+                GDK_KEY_Up,
+                GDK_KEY_Right,
+                GDK_KEY_Down,
+                GDK_KEY_Select,
+                GDK_KEY_Print,
+                GDK_KEY_Execute,
+                GDK_KEY_Insert,
+                GDK_KEY_KP_Insert,
+                GDK_KEY_Delete,
+                GDK_KEY_KP_Delete,
+                GDK_KEY_Help,
+                GDK_KEY_0,
+                GDK_KEY_parenright,
+                GDK_KEY_1,
+                GDK_KEY_exclam,
+                GDK_KEY_2,
+                GDK_KEY_at,
+                GDK_KEY_3,
+                GDK_KEY_numbersign,
+                GDK_KEY_4,
+                GDK_KEY_dollar,
+                GDK_KEY_5,
+                GDK_KEY_percent,
+                GDK_KEY_6,
+                GDK_KEY_asciicircum,
+                GDK_KEY_7,
+                GDK_KEY_ampersand,
+                GDK_KEY_8,
+                GDK_KEY_asterisk,
+                GDK_KEY_9,
+                GDK_KEY_parenleft,
+                GDK_KEY_a,
+                GDK_KEY_A,
+                GDK_KEY_b,
+                GDK_KEY_B,
+                GDK_KEY_c,
+                GDK_KEY_C,
+                GDK_KEY_d,
+                GDK_KEY_D,
+                GDK_KEY_e,
+                GDK_KEY_E,
+                GDK_KEY_f,
+                GDK_KEY_F,
+                GDK_KEY_g,
+                GDK_KEY_G,
+                GDK_KEY_h,
+                GDK_KEY_H,
+                GDK_KEY_i,
+                GDK_KEY_I,
+                GDK_KEY_j,
+                GDK_KEY_J,
+                GDK_KEY_k,
+                GDK_KEY_K,
+                GDK_KEY_l,
+                GDK_KEY_L,
+                GDK_KEY_m,
+                GDK_KEY_M,
+                GDK_KEY_n,
+                GDK_KEY_N,
+                GDK_KEY_o,
+                GDK_KEY_O,
+                GDK_KEY_p,
+                GDK_KEY_P,
+                GDK_KEY_q,
+                GDK_KEY_Q,
+                GDK_KEY_r,
+                GDK_KEY_R,
+                GDK_KEY_s,
+                GDK_KEY_S,
+                GDK_KEY_t,
+                GDK_KEY_T,
+                GDK_KEY_u,
+                GDK_KEY_U,
+                GDK_KEY_v,
+                GDK_KEY_V,
+                GDK_KEY_w,
+                GDK_KEY_W,
+                GDK_KEY_x,
+                GDK_KEY_X,
+                GDK_KEY_y,
+                GDK_KEY_Y,
+                GDK_KEY_z,
+                GDK_KEY_Z,
+                GDK_KEY_Meta_L,
+                GDK_KEY_Meta_R,
+                GDK_KEY_Sleep,
+                GDK_KEY_Num_Lock,
+                GDK_KEY_Scroll_Lock,
+                GDK_KEY_Shift_L,
+                GDK_KEY_Shift_R,
+                GDK_KEY_Control_L,
+                GDK_KEY_Control_R,
+                GDK_KEY_Alt_L,
+                GDK_KEY_Alt_R,
+                GDK_KEY_Back,
+                GDK_KEY_Forward,
+                GDK_KEY_Refresh,
+                GDK_KEY_Stop,
+                GDK_KEY_Search,
+                GDK_KEY_Favorites,
+                GDK_KEY_HomePage,
+                GDK_KEY_AudioMute,
+                GDK_KEY_AudioLowerVolume,
+                GDK_KEY_AudioRaiseVolume,
+                GDK_KEY_AudioNext,
+                GDK_KEY_AudioPrev,
+                GDK_KEY_AudioStop,
+                GDK_KEY_AudioMedia,
+                GDK_KEY_semicolon,
+                GDK_KEY_colon,
+                GDK_KEY_plus,
+                GDK_KEY_equal,
+                GDK_KEY_comma,
+                GDK_KEY_less,
+                GDK_KEY_minus,
+                GDK_KEY_underscore,
+                GDK_KEY_period,
+                GDK_KEY_greater,
+                GDK_KEY_slash,
+                GDK_KEY_question,
+                GDK_KEY_asciitilde,
+                GDK_KEY_quoteleft,
+                GDK_KEY_bracketleft,
+                GDK_KEY_braceleft,
+                GDK_KEY_backslash,
+                GDK_KEY_bar,
+                GDK_KEY_bracketright,
+                GDK_KEY_braceright,
+                GDK_KEY_quoteright,
+                GDK_KEY_quotedbl,
+                GDK_KEY_AudioRewind,
+                GDK_KEY_AudioForward,
+                GDK_KEY_AudioPlay,
+                GDK_KEY_F1,
+                GDK_KEY_F2,
+                GDK_KEY_F3,
+                GDK_KEY_F4,
+                GDK_KEY_F5,
+                GDK_KEY_F6,
+                GDK_KEY_F7,
+                GDK_KEY_F8,
+                GDK_KEY_F9,
+                GDK_KEY_F10,
+                GDK_KEY_F11,
+                GDK_KEY_F12,
+                GDK_KEY_F13,
+                GDK_KEY_F14,
+                GDK_KEY_F15,
+                GDK_KEY_F16,
+                GDK_KEY_F17,
+                GDK_KEY_F18,
+                GDK_KEY_F19,
+                GDK_KEY_F20,
+                GDK_KEY_F21,
+                GDK_KEY_F22,
+                GDK_KEY_F23,
+                GDK_KEY_F24,
+                GDK_KEY_VoidSymbol,
+                GDK_KEY_Red,
+                GDK_KEY_Green,
+                GDK_KEY_Yellow,
+                GDK_KEY_Blue,
+                GDK_KEY_PowerOff,
+                GDK_KEY_AudioRecord,
+                GDK_KEY_Display,
+                GDK_KEY_Subtitle,
+                GDK_KEY_Video
+            };
+            result = new UncheckedKeyHashMap<int, unsigned>();
+            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 9ea18000578dd47295b2ce4da7fa00b39b5cac81..41bdd2d741b469acb134220df7e0c10209bd9f62 100644
--- a/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp
+++ b/Source/WebCore/platform/gtk/PlatformScreenGtk.cpp
@@ -132,7 +132,7 @@ bool screenSupportsExtendedColor(Widget*)
 }
 
 #if ENABLE(TOUCH_EVENTS)
-bool screenHasTouchDevice()
+bool platformScreenHasTouchDevice()
 {
     auto* display = gdk_display_get_default();
     if (!display)
@@ -142,7 +142,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 ae439e30f1fb239d18e1164e8896dfb272c75673..4cf29eda13d1f2dc2f03750c0ef8985b17de7f50 100644
--- a/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp
+++ b/Source/WebCore/platform/libwpe/PasteboardLibWPE.cpp
@@ -32,6 +32,10 @@
 #include "PasteboardStrategy.h"
 #include "PlatformStrategies.h"
 
+#if ENABLE(DRAG_SUPPORT)
+#include "DragData.h"
+#endif
+
 namespace WebCore {
 
 std::unique_ptr<Pasteboard> Pasteboard::createForCopyAndPaste(std::unique_ptr<PasteboardContext>&& context)
@@ -52,9 +56,28 @@ bool Pasteboard::hasData()
     return !types.isEmpty();
 }
 
-Vector<String> Pasteboard::typesSafeForBindings(const String&)
+Vector<String> Pasteboard::typesSafeForBindings(const String& origin)
 {
-    notImplemented();
+    if (m_selectionData) {
+        ListHashSet<String> types;
+        if (auto& buffer = m_selectionData->customData()) {
+            auto customData = PasteboardCustomData::fromSharedBuffer(*buffer);
+            if (customData.origin() == origin) {
+                for (auto& type : customData.orderedTypes())
+                    types.add(type);
+            }
+        }
+
+        if (m_selectionData->hasText())
+            types.add("text/plain"_s);
+        if (m_selectionData->hasMarkup())
+            types.add("text/html"_s);
+        if (m_selectionData->hasURIList())
+            types.add("text/uri-list"_s);
+
+        return copyToVector(types);
+    }
+
     return { };
 }
 
@@ -67,23 +90,55 @@ Vector<String> Pasteboard::typesForLegacyUnsafeBindings()
 
 String Pasteboard::readOrigin()
 {
-    notImplemented(); // webkit.org/b/177633: [GTK] Move to new Pasteboard API
+    if (m_selectionData) {
+        if (auto& buffer = m_selectionData->customData())
+            return PasteboardCustomData::fromSharedBuffer(*buffer).origin();
+
+        return { };
+    }
+
     return { };
 }
 
 String Pasteboard::readString(const String& type)
 {
+    if (m_selectionData) {
+        if (type == "text/plain"_s)
+            return m_selectionData->text();;
+        if (type == "text/html"_s)
+            return m_selectionData->markup();
+        if (type == "Files"_s || type == "text/uri-list"_s)
+            return m_selectionData->uriList();
+        return { };
+    }
+
     return platformStrategies()->pasteboardStrategy()->readStringFromPasteboard(0, type, name(), context());
 }
 
-String Pasteboard::readStringInCustomData(const String&)
+String Pasteboard::readStringInCustomData(const String& type)
 {
+    if (m_selectionData) {
+        if (auto& buffer = m_selectionData->customData())
+            return PasteboardCustomData::fromSharedBuffer(*buffer).readStringInCustomData(type);
+
+        return { };
+    }
+
     notImplemented();
     return { };
 }
 
 void Pasteboard::writeString(const String& type, const String& text)
 {
+   if (m_selectionData) {
+        if (type == "Files"_s || type == "text/uri-list"_s)
+            m_selectionData->setURIList(text);
+        else if (type == "text/html"_s)
+            m_selectionData->setMarkup(text);
+        else if (type == "text/plain"_s)
+            m_selectionData->setText(text);
+        return;
+    }
     platformStrategies()->pasteboardStrategy()->writeToPasteboard(type, text);
 }
 
@@ -111,7 +166,12 @@ void Pasteboard::read(PasteboardFileReader&, std::optional<size_t>)
 
 void Pasteboard::write(const PasteboardURL& url)
 {
-    platformStrategies()->pasteboardStrategy()->writeToPasteboard("text/plain;charset=utf-8"_s, url.url.string());
+    if (m_selectionData) {
+        m_selectionData->clearAll();
+        m_selectionData->setURL(url.url, url.title);
+    } else {
+        platformStrategies()->pasteboardStrategy()->writeToPasteboard("text/plain;charset=utf-8"_s, url.url.string());
+    }
 }
 
 void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&)
@@ -119,8 +179,16 @@ void Pasteboard::writeTrustworthyWebURLsPboardType(const PasteboardURL&)
     notImplemented();
 }
 
-void Pasteboard::write(const PasteboardImage&)
+void Pasteboard::write(const PasteboardImage& pasteboardImage)
 {
+    if (m_selectionData) {
+        m_selectionData->clearAll();
+        if (!pasteboardImage.url.url.isEmpty()) {
+            m_selectionData->setURL(pasteboardImage.url.url, pasteboardImage.url.title);
+            m_selectionData->setMarkup(pasteboardImage.url.markup);
+        }
+        m_selectionData->setImage(pasteboardImage.image.get());
+    }
 }
 
 void Pasteboard::write(const PasteboardBuffer&)
@@ -129,7 +197,13 @@ void Pasteboard::write(const PasteboardBuffer&)
 
 void Pasteboard::write(const PasteboardWebContent& content)
 {
-    platformStrategies()->pasteboardStrategy()->writeToPasteboard(content);
+    if (m_selectionData) {
+        m_selectionData->clearAll();
+        m_selectionData->setText(content.text);
+        m_selectionData->setMarkup(content.markup);
+    } else {
+        platformStrategies()->pasteboardStrategy()->writeToPasteboard(content);
+    }
 }
 
 Pasteboard::FileContentState Pasteboard::fileContentState()
@@ -152,14 +226,54 @@ void Pasteboard::writePlainText(const String& text, SmartReplaceOption)
     writeString("text/plain;charset=utf-8"_s, text);
 }
 
-void Pasteboard::writeCustomData(const Vector<PasteboardCustomData>&)
+void Pasteboard::writeCustomData(const Vector<PasteboardCustomData>& data)
 {
+    if (m_selectionData) {
+        if (!data.isEmpty()) {
+            const auto& customData = data[0];
+            customData.forEachPlatformString([this] (auto& type, auto& string) {
+                writeString(type, string);
+            });
+            if (customData.hasSameOriginCustomData() || !customData.origin().isEmpty())
+                m_selectionData->setCustomData(customData.createSharedBuffer());
+        }
+        return;
+    }
 }
 
 void Pasteboard::write(const Color&)
 {
 }
 
+#if ENABLE(DRAG_SUPPORT)
+
+Pasteboard::Pasteboard(std::unique_ptr<PasteboardContext>&& context, SelectionData&& selectionData)
+    : m_context(WTFMove(context))
+    , m_selectionData(WTFMove(selectionData))
+{
+}
+
+Pasteboard::Pasteboard(std::unique_ptr<PasteboardContext>&& context, SelectionData& selectionData)
+    : m_context(WTFMove(context))
+    , m_selectionData(selectionData)
+{
+}
+
+std::unique_ptr<Pasteboard> Pasteboard::createForDragAndDrop(std::unique_ptr<PasteboardContext>&& context)
+{
+    return makeUnique<Pasteboard>(WTFMove(context), SelectionData());
+}
+
+std::unique_ptr<Pasteboard> Pasteboard::create(const DragData& dragData)
+{
+    RELEASE_ASSERT(dragData.platformData());
+    return makeUnique<Pasteboard>(dragData.createPasteboardContext(), *dragData.platformData());
+}
+void Pasteboard::setDragImage(DragImage, const IntPoint&)
+{
+}
+#endif
+
 } // namespace WebCore
 
 #endif // USE(LIBWPE)
diff --git a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp
index a8674916429908cabb86bd95dc5b3da217e1556b..6a464e2b0c1c45cd4e8effba678b8dde9dd870da 100644
--- a/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp
+++ b/Source/WebCore/platform/libwpe/PlatformKeyboardEventLibWPE.cpp
@@ -30,9 +30,11 @@
 
 #include "WindowsKeyboardCodes.h"
 #include <wpe/wpe.h>
+#include <wtf/HashMap.h>
 #include <wtf/HexNumber.h>
 #include <wtf/text/MakeString.h>
 #include <wtf/text/StringBuilder.h>
+#include <mutex>
 
 namespace WebCore {
 
@@ -1303,6 +1305,246 @@ int PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(unsigned keycode)
     return 0;
 }
 
+static const UncheckedKeyHashMap<int, unsigned>& WPEToWindowsKeyCodeMap()
+{
+    static UncheckedKeyHashMap<int, unsigned>* result;
+    static std::once_flag once;
+    std::call_once(
+        once,
+        [] {
+            const unsigned WPEKeyCodes[] = {
+                WPE_KEY_Cancel,
+                // FIXME: non-keypad keys should take precedence, so we skip WPE_KEY_KP_*
+                // WPE_KEY_KP_0,
+                // WPE_KEY_KP_1,
+                // WPE_KEY_KP_2,
+                // WPE_KEY_KP_3,
+                // WPE_KEY_KP_4,
+                // WPE_KEY_KP_5,
+                // WPE_KEY_KP_6,
+                // WPE_KEY_KP_7,
+                // WPE_KEY_KP_8,
+                // WPE_KEY_KP_9,
+                // WPE_KEY_KP_Multiply,
+                // WPE_KEY_KP_Add,
+                // WPE_KEY_KP_Subtract,
+                // WPE_KEY_KP_Decimal,
+                // WPE_KEY_KP_Divide,
+                // WPE_KEY_KP_Page_Up,
+                // WPE_KEY_KP_Page_Down,
+                // WPE_KEY_KP_End,
+                // WPE_KEY_KP_Home,
+                // WPE_KEY_KP_Left,
+                // WPE_KEY_KP_Up,
+                // WPE_KEY_KP_Right,
+                // WPE_KEY_KP_Down,
+                WPE_KEY_BackSpace,
+                // WPE_KEY_ISO_Left_Tab,
+                // WPE_KEY_3270_BackTab,
+                WPE_KEY_Tab,
+                WPE_KEY_Clear,
+                // WPE_KEY_ISO_Enter,
+                // WPE_KEY_KP_Enter,
+                WPE_KEY_Return,
+                WPE_KEY_Menu,
+                WPE_KEY_Pause,
+                WPE_KEY_AudioPause,
+                WPE_KEY_Caps_Lock,
+                WPE_KEY_Kana_Lock,
+                WPE_KEY_Kana_Shift,
+                WPE_KEY_Hangul,
+                WPE_KEY_Hangul_Hanja,
+                WPE_KEY_Kanji,
+                WPE_KEY_Escape,
+                WPE_KEY_space,
+                WPE_KEY_Page_Up,
+                WPE_KEY_Page_Down,
+                WPE_KEY_End,
+                WPE_KEY_Home,
+                WPE_KEY_Left,
+                WPE_KEY_Up,
+                WPE_KEY_Right,
+                WPE_KEY_Down,
+                WPE_KEY_Select,
+                WPE_KEY_Print,
+                WPE_KEY_Execute,
+                WPE_KEY_Insert,
+                WPE_KEY_KP_Insert,
+                WPE_KEY_Delete,
+                WPE_KEY_KP_Delete,
+                WPE_KEY_Help,
+                WPE_KEY_0,
+                WPE_KEY_parenright,
+                WPE_KEY_1,
+                WPE_KEY_exclam,
+                WPE_KEY_2,
+                WPE_KEY_at,
+                WPE_KEY_3,
+                WPE_KEY_numbersign,
+                WPE_KEY_4,
+                WPE_KEY_dollar,
+                WPE_KEY_5,
+                WPE_KEY_percent,
+                WPE_KEY_6,
+                WPE_KEY_asciicircum,
+                WPE_KEY_7,
+                WPE_KEY_ampersand,
+                WPE_KEY_8,
+                WPE_KEY_asterisk,
+                WPE_KEY_9,
+                WPE_KEY_parenleft,
+                WPE_KEY_a,
+                WPE_KEY_A,
+                WPE_KEY_b,
+                WPE_KEY_B,
+                WPE_KEY_c,
+                WPE_KEY_C,
+                WPE_KEY_d,
+                WPE_KEY_D,
+                WPE_KEY_e,
+                WPE_KEY_E,
+                WPE_KEY_f,
+                WPE_KEY_F,
+                WPE_KEY_g,
+                WPE_KEY_G,
+                WPE_KEY_h,
+                WPE_KEY_H,
+                WPE_KEY_i,
+                WPE_KEY_I,
+                WPE_KEY_j,
+                WPE_KEY_J,
+                WPE_KEY_k,
+                WPE_KEY_K,
+                WPE_KEY_l,
+                WPE_KEY_L,
+                WPE_KEY_m,
+                WPE_KEY_M,
+                WPE_KEY_n,
+                WPE_KEY_N,
+                WPE_KEY_o,
+                WPE_KEY_O,
+                WPE_KEY_p,
+                WPE_KEY_P,
+                WPE_KEY_q,
+                WPE_KEY_Q,
+                WPE_KEY_r,
+                WPE_KEY_R,
+                WPE_KEY_s,
+                WPE_KEY_S,
+                WPE_KEY_t,
+                WPE_KEY_T,
+                WPE_KEY_u,
+                WPE_KEY_U,
+                WPE_KEY_v,
+                WPE_KEY_V,
+                WPE_KEY_w,
+                WPE_KEY_W,
+                WPE_KEY_x,
+                WPE_KEY_X,
+                WPE_KEY_y,
+                WPE_KEY_Y,
+                WPE_KEY_z,
+                WPE_KEY_Z,
+                WPE_KEY_Meta_L,
+                WPE_KEY_Meta_R,
+                WPE_KEY_Sleep,
+                WPE_KEY_Num_Lock,
+                WPE_KEY_Scroll_Lock,
+                WPE_KEY_Shift_L,
+                WPE_KEY_Shift_R,
+                WPE_KEY_Control_L,
+                WPE_KEY_Control_R,
+                WPE_KEY_Alt_L,
+                WPE_KEY_Alt_R,
+                WPE_KEY_Back,
+                WPE_KEY_Forward,
+                WPE_KEY_Refresh,
+                WPE_KEY_Stop,
+                WPE_KEY_Search,
+                WPE_KEY_Favorites,
+                WPE_KEY_HomePage,
+                WPE_KEY_AudioMute,
+                WPE_KEY_AudioLowerVolume,
+                WPE_KEY_AudioRaiseVolume,
+                WPE_KEY_AudioNext,
+                WPE_KEY_AudioPrev,
+                WPE_KEY_AudioStop,
+                WPE_KEY_AudioMedia,
+                WPE_KEY_semicolon,
+                WPE_KEY_colon,
+                WPE_KEY_plus,
+                WPE_KEY_equal,
+                WPE_KEY_comma,
+                WPE_KEY_less,
+                WPE_KEY_minus,
+                WPE_KEY_underscore,
+                WPE_KEY_period,
+                WPE_KEY_greater,
+                WPE_KEY_slash,
+                WPE_KEY_question,
+                WPE_KEY_asciitilde,
+                WPE_KEY_quoteleft,
+                WPE_KEY_bracketleft,
+                WPE_KEY_braceleft,
+                WPE_KEY_backslash,
+                WPE_KEY_bar,
+                WPE_KEY_bracketright,
+                WPE_KEY_braceright,
+                WPE_KEY_quoteright,
+                WPE_KEY_quotedbl,
+                WPE_KEY_AudioRewind,
+                WPE_KEY_AudioForward,
+                WPE_KEY_AudioPlay,
+                WPE_KEY_F1,
+                WPE_KEY_F2,
+                WPE_KEY_F3,
+                WPE_KEY_F4,
+                WPE_KEY_F5,
+                WPE_KEY_F6,
+                WPE_KEY_F7,
+                WPE_KEY_F8,
+                WPE_KEY_F9,
+                WPE_KEY_F10,
+                WPE_KEY_F11,
+                WPE_KEY_F12,
+                WPE_KEY_F13,
+                WPE_KEY_F14,
+                WPE_KEY_F15,
+                WPE_KEY_F16,
+                WPE_KEY_F17,
+                WPE_KEY_F18,
+                WPE_KEY_F19,
+                WPE_KEY_F20,
+                WPE_KEY_F21,
+                WPE_KEY_F22,
+                WPE_KEY_F23,
+                WPE_KEY_F24,
+                WPE_KEY_VoidSymbol,
+                WPE_KEY_Red,
+                WPE_KEY_Green,
+                WPE_KEY_Yellow,
+                WPE_KEY_Blue,
+                WPE_KEY_PowerOff,
+                WPE_KEY_AudioRecord,
+                WPE_KEY_Display,
+                WPE_KEY_Subtitle,
+                WPE_KEY_Video
+            };
+            result = new UncheckedKeyHashMap<int, unsigned>();
+            for (unsigned WPEKeyCode : WPEKeyCodes) {
+                int winKeyCode = PlatformKeyboardEvent::windowsKeyCodeForWPEKeyCode(WPEKeyCode);
+                // If several gdk key codes map to the same win key code first one is used.
+                result->add(winKeyCode, WPEKeyCode);
+            }
+        });
+    return *result;
+}
+
+unsigned PlatformKeyboardEvent::WPEKeyCodeForWindowsKeyCode(int keycode)
+{
+    return WPEToWindowsKeyCodeMap().get(keycode);
+}
+
 String PlatformKeyboardEvent::singleCharacterString(unsigned val)
 {
     switch (val) {
diff --git a/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp b/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp
index 64afe805b4418d9e57cc7a2704498a97162b93ab..86c385359352853d2884226f478168f890b0c8f0 100644
--- a/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp
+++ b/Source/WebCore/platform/libwpe/PlatformPasteboardLibWPE.cpp
@@ -31,10 +31,18 @@
 #include "Pasteboard.h"
 #include <wpe/wpe.h>
 #include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/text/WTFString.h>
 
 namespace WebCore {
 
+static UncheckedKeyHashMap<String, String>& sharedPasteboard()
+{
+    static NeverDestroyed<UncheckedKeyHashMap<String, String>> pasteboard;
+    return pasteboard.get();
+}
+
 PlatformPasteboard::PlatformPasteboard(const String&)
     : m_pasteboard(wpe_pasteboard_get_singleton())
 {
@@ -54,72 +62,26 @@ void PlatformPasteboard::performAsDataOwner(DataOwnerType, Function<void()>&& ac
 
 void PlatformPasteboard::getTypes(Vector<String>& types) const
 {
-    struct wpe_pasteboard_string_vector pasteboardTypes = { nullptr, 0 };
-    wpe_pasteboard_get_types(m_pasteboard, &pasteboardTypes);
-    for (auto& typeString : unsafeMakeSpan(pasteboardTypes.strings, pasteboardTypes.length)) {
-        const auto length = std::min(static_cast<size_t>(typeString.length), std::numeric_limits<size_t>::max());
-        types.append(String({ typeString.data, length }));
-    }
-
-    wpe_pasteboard_string_vector_free(&pasteboardTypes);
+    for (const auto& type : sharedPasteboard().keys())
+        types.append(type);
 }
 
 String PlatformPasteboard::readString(size_t, const String& type) const
 {
-    struct wpe_pasteboard_string string = { nullptr, 0 };
-    wpe_pasteboard_get_string(m_pasteboard, type.utf8().data(), &string);
-    if (!string.length)
-        return String();
-
-    const auto length = std::min(static_cast<size_t>(string.length), std::numeric_limits<size_t>::max());
-    String returnValue({ string.data, length });
-
-    wpe_pasteboard_string_free(&string);
-    return returnValue;
+    return sharedPasteboard().get(type);
 }
 
 void PlatformPasteboard::write(const PasteboardWebContent& content)
 {
-    static constexpr auto plainText = "text/plain;charset=utf-8"_s;
-    static constexpr auto htmlText = "text/html;charset=utf-8"_s;
-
-    CString textString = content.text.utf8();
-    CString markupString = content.markup.utf8();
-
-    std::array<struct wpe_pasteboard_string_pair, 2> pairs = { {
-        { { nullptr, 0 }, { nullptr, 0 } },
-        { { nullptr, 0 }, { nullptr, 0 } },
-    } };
-    wpe_pasteboard_string_initialize(&pairs[0].type, plainText, strlen(plainText));
-    wpe_pasteboard_string_initialize(&pairs[0].string, textString.data(), textString.length());
-    wpe_pasteboard_string_initialize(&pairs[1].type, htmlText, strlen(htmlText));
-    wpe_pasteboard_string_initialize(&pairs[1].string, markupString.data(), markupString.length());
-    struct wpe_pasteboard_string_map map = { pairs.data(), pairs.size() };
-
-    wpe_pasteboard_write(m_pasteboard, &map);
-
-    wpe_pasteboard_string_free(&pairs[0].type);
-    wpe_pasteboard_string_free(&pairs[0].string);
-    wpe_pasteboard_string_free(&pairs[1].type);
-    wpe_pasteboard_string_free(&pairs[1].string);
+    String plainText = "text/plain;charset=utf-8"_s;
+    String htmlText = "text/html;charset=utf-8"_s;
+    sharedPasteboard().set(plainText, content.text);
+    sharedPasteboard().set(htmlText, content.markup);
 }
 
 void PlatformPasteboard::write(const String& type, const String& string)
 {
-    struct wpe_pasteboard_string_pair pairs[] = {
-        { { nullptr, 0 }, { nullptr, 0 } },
-    };
-
-    auto typeUTF8 = type.utf8();
-    auto stringUTF8 = string.utf8();
-    wpe_pasteboard_string_initialize(&pairs[0].type, typeUTF8.data(), typeUTF8.length());
-    wpe_pasteboard_string_initialize(&pairs[0].string, stringUTF8.data(), stringUTF8.length());
-    struct wpe_pasteboard_string_map map = { pairs, 1 };
-
-    wpe_pasteboard_write(m_pasteboard, &map);
-
-    wpe_pasteboard_string_free(&pairs[0].type);
-    wpe_pasteboard_string_free(&pairs[0].string);
+    sharedPasteboard().set(type, string);
 }
 
 Vector<String> PlatformPasteboard::typesSafeForDOMToReadAndWrite(const String&) const
diff --git a/Source/WebCore/platform/network/HTTPHeaderMap.cpp b/Source/WebCore/platform/network/HTTPHeaderMap.cpp
index d22cc965746c1b55ed9242af878a590a487ecae5..2c7649e3fa5bd13e456e1e1d90da37a813a75aca 100644
--- a/Source/WebCore/platform/network/HTTPHeaderMap.cpp
+++ b/Source/WebCore/platform/network/HTTPHeaderMap.cpp
@@ -234,8 +234,11 @@ void HTTPHeaderMap::add(HTTPHeaderName name, const String& value)
     auto index = m_commonHeaders.findIf([&](auto& header) {
         return header.key == name;
     });
+    // Align with Chromium and Firefox, but just for SetCookies where it is critical:
+    // https://bit.ly/2HCa0iq
+    String separator = name == HTTPHeaderName::SetCookie ? "playwright-set-cookie-separator"_s : ", "_s;
     if (index != notFound)
-        m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, ", "_s, value);
+        m_commonHeaders[index].value = makeString(m_commonHeaders[index].value, separator, value);
     else
         m_commonHeaders.append(CommonHeader { name, value });
 }
diff --git a/Source/WebCore/platform/network/NetworkStorageSession.h b/Source/WebCore/platform/network/NetworkStorageSession.h
index 00d37bb9aac7aa0db5a7cc7acdff5611a44e4aaa..6e23adbdb9035bb4698232b2086b4ac0fcff7dea 100644
--- a/Source/WebCore/platform/network/NetworkStorageSession.h
+++ b/Source/WebCore/platform/network/NetworkStorageSession.h
@@ -184,6 +184,7 @@ public:
 
     NetworkingContext* context() const;
 #endif
+    WEBCORE_EXPORT void setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL&, const String& setCookieValue);
 
     WEBCORE_EXPORT HTTPCookieAcceptPolicy cookieAcceptPolicy() const;
     WEBCORE_EXPORT void setCookie(const Cookie&);
diff --git a/Source/WebCore/platform/network/ResourceResponseBase.cpp b/Source/WebCore/platform/network/ResourceResponseBase.cpp
index 774748f1bb47fdefa53b820db5fc891077125de7..4f9220dace7d300d2326692383944f3a560d8cb8 100644
--- a/Source/WebCore/platform/network/ResourceResponseBase.cpp
+++ b/Source/WebCore/platform/network/ResourceResponseBase.cpp
@@ -78,6 +78,7 @@ ResourceResponseBase::ResourceResponseBase(std::optional<ResourceResponseData> d
     , m_httpStatusText(data ? data->httpStatusText : String { })
     , m_httpVersion(data ? data->httpVersion : String { })
     , m_httpHeaderFields(data ? data->httpHeaderFields : HTTPHeaderMap { })
+    , m_httpRequestHeaderFields(data ? data->httpRequestHeaderFields : HTTPHeaderMap { })
     , m_networkLoadMetrics(data && data->networkLoadMetrics ? Box<NetworkLoadMetrics>::create(*data->networkLoadMetrics) : Box<NetworkLoadMetrics> { })
     , m_certificateInfo(data ? data->certificateInfo : std::nullopt)
     , m_httpStatusCode(data ? data->httpStatusCode : 0)
@@ -901,6 +902,7 @@ std::optional<ResourceResponseData> ResourceResponseBase::getResponseData() cons
         String { m_httpStatusText },
         String { m_httpVersion },
         HTTPHeaderMap { m_httpHeaderFields },
+        HTTPHeaderMap { m_httpRequestHeaderFields },
         m_networkLoadMetrics ? std::optional(*m_networkLoadMetrics) : std::nullopt,
         m_source,
         m_type,
@@ -974,6 +976,11 @@ std::optional<WebCore::ResourceResponseData> Coder<WebCore::ResourceResponseData
     if (!httpHeaderFields)
         return std::nullopt;
 
+    std::optional<WebCore::HTTPHeaderMap> httpRequestHeaderFields;
+    decoder >> httpRequestHeaderFields;
+    if (!httpRequestHeaderFields)
+        return std::nullopt;
+
     std::optional<short> httpStatusCode;
     decoder >> httpStatusCode;
     if (!httpStatusCode)
@@ -1028,6 +1035,7 @@ std::optional<WebCore::ResourceResponseData> Coder<WebCore::ResourceResponseData
         WTFMove(*httpStatusText),
         WTFMove(*httpVersion),
         WTFMove(*httpHeaderFields),
+        WTFMove(*httpRequestHeaderFields),
         std::nullopt,
         *source,
         *type,
diff --git a/Source/WebCore/platform/network/ResourceResponseBase.h b/Source/WebCore/platform/network/ResourceResponseBase.h
index ec38706084d826ae14aefc6febba137d3e51f1a6..01a916a312e99e405d3098b3df78ee000f55f74a 100644
--- a/Source/WebCore/platform/network/ResourceResponseBase.h
+++ b/Source/WebCore/platform/network/ResourceResponseBase.h
@@ -254,6 +254,11 @@ protected:
     String m_httpStatusText;
     String m_httpVersion;
     HTTPHeaderMap m_httpHeaderFields;
+
+public:
+    HTTPHeaderMap m_httpRequestHeaderFields;
+
+protected:
     Box<NetworkLoadMetrics> m_networkLoadMetrics;
 
     mutable std::optional<CertificateInfo> m_certificateInfo;
@@ -294,7 +299,7 @@ struct ResourceResponseData {
     ResourceResponseData() = default;
     ResourceResponseData(ResourceResponseData&&) = default;
     ResourceResponseData& operator=(ResourceResponseData&&) = default;
-    ResourceResponseData(URL&& url, String&& mimeType, long long expectedContentLength, String&& textEncodingName, int httpStatusCode, String&& httpStatusText, String&& httpVersion, HTTPHeaderMap&& httpHeaderFields, std::optional<NetworkLoadMetrics>&& networkLoadMetrics, ResourceResponseBaseSource source, ResourceResponseBaseType type, ResourceResponseBaseTainting tainting, bool isRedirected, UsedLegacyTLS usedLegacyTLS, WasPrivateRelayed wasPrivateRelayed, bool isRangeRequested, std::optional<CertificateInfo> certificateInfo)
+    ResourceResponseData(URL&& url, String&& mimeType, long long expectedContentLength, String&& textEncodingName, int httpStatusCode, String&& httpStatusText, String&& httpVersion, HTTPHeaderMap&& httpHeaderFields, HTTPHeaderMap&& httpRequestHeaderFields, std::optional<NetworkLoadMetrics>&& networkLoadMetrics, ResourceResponseBaseSource source, ResourceResponseBaseType type, ResourceResponseBaseTainting tainting, bool isRedirected, UsedLegacyTLS usedLegacyTLS, WasPrivateRelayed wasPrivateRelayed, bool isRangeRequested, std::optional<CertificateInfo> certificateInfo)
         : url(WTFMove(url))
         , mimeType(WTFMove(mimeType))
         , expectedContentLength(expectedContentLength)
@@ -303,6 +308,7 @@ struct ResourceResponseData {
         , httpStatusText(WTFMove(httpStatusText))
         , httpVersion(WTFMove(httpVersion))
         , httpHeaderFields(WTFMove(httpHeaderFields))
+        , httpRequestHeaderFields(WTFMove(httpRequestHeaderFields))
         , networkLoadMetrics(WTFMove(networkLoadMetrics))
         , source(source)
         , type(type)
@@ -325,6 +331,7 @@ struct ResourceResponseData {
     String httpStatusText;
     String httpVersion;
     HTTPHeaderMap httpHeaderFields;
+    HTTPHeaderMap httpRequestHeaderFields;
     std::optional<NetworkLoadMetrics> networkLoadMetrics;
     ResourceResponseBase::Source source;
     ResourceResponseBase::Type type;
diff --git a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm
index b101c64297f845dd72c80a28893c6a3f4e4d8c05..72e289b9fbeb40f11c161b0c0b1b743e173cf849 100644
--- a/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm
+++ b/Source/WebCore/platform/network/cocoa/NetworkStorageSessionCocoa.mm
@@ -493,6 +493,22 @@ bool NetworkStorageSession::setCookieFromDOM(const URL& firstParty, const SameSi
     return false;
 }
 
+void NetworkStorageSession::setCookiesFromResponse(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& setCookieValue)
+{
+    Vector<String> cookieValues = setCookieValue.split('\n');
+    size_t count = cookieValues.size();
+    auto* cookies = [NSMutableArray arrayWithCapacity:count];
+    for (const auto& cookieValue : cookieValues) {
+        NSString* cookieString = (NSString *)cookieValue;
+        NSString* cookieKey = @"Set-Cookie";
+        NSDictionary* headers = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObject:cookieString] forKeys:[NSArray arrayWithObject:cookieKey]];
+        NSArray<NSHTTPCookie*>* parsedCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:(NSURL *)url];
+        [cookies addObject:parsedCookies[0]];
+    }
+    NSURL *cookieURL = url;
+    setHTTPCookiesForURL(cookieStorage().get(), cookies, cookieURL, firstParty, sameSiteInfo);
+}
+
 static NSHTTPCookieAcceptPolicy httpCookieAcceptPolicy(CFHTTPCookieStorageRef cookieStorage)
 {
     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
diff --git a/Source/WebCore/platform/network/curl/CookieJarDB.h b/Source/WebCore/platform/network/curl/CookieJarDB.h
index 37e129136c69b27d509acc01f10be42a8a1fe35a..9df0babc8f82372925fddf2211a7c8c908f3bb18 100644
--- a/Source/WebCore/platform/network/curl/CookieJarDB.h
+++ b/Source/WebCore/platform/network/curl/CookieJarDB.h
@@ -73,7 +73,7 @@ public:
     WEBCORE_EXPORT ~CookieJarDB();
 
 private:
-    CookieAcceptPolicy m_acceptPolicy { CookieAcceptPolicy::Always };
+    CookieAcceptPolicy m_acceptPolicy { CookieAcceptPolicy::OnlyFromMainDocumentDomain };
     String m_databasePath;
 
     bool m_detectedDatabaseCorruption { false };
diff --git a/Source/WebCore/platform/network/curl/CurlStream.cpp b/Source/WebCore/platform/network/curl/CurlStream.cpp
index d07f26d77447d05fa2b086d04e6aa105c3d6b4b1..52b09365fff63fa4099320d0eebc1d498e0c068e 100644
--- a/Source/WebCore/platform/network/curl/CurlStream.cpp
+++ b/Source/WebCore/platform/network/curl/CurlStream.cpp
@@ -37,7 +37,7 @@ namespace WebCore {
 
 WTF_MAKE_TZONE_ALLOCATED_IMPL(CurlStream);
 
-CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias)
+CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, bool ignoreCertificateErrors, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias)
     : m_scheduler(scheduler)
     , m_streamID(streamID)
 {
@@ -52,6 +52,9 @@ CurlStream::CurlStream(CurlStreamScheduler& scheduler, CurlStreamID streamID, UR
         m_curlHandle->disableServerTrustEvaluation();
 
     m_curlHandle->enableConnectionOnly();
+    if (ignoreCertificateErrors)
+        m_curlHandle->disableServerTrustEvaluation();
+
 
     auto errorCode = m_curlHandle->perform();
     if (errorCode != CURLE_OK) {
diff --git a/Source/WebCore/platform/network/curl/CurlStream.h b/Source/WebCore/platform/network/curl/CurlStream.h
index 96c3d2c216d522cf5c8b53b06a87eb849d159618..b595a1cfe961ad98364d8893014ab5c2fc1007f5 100644
--- a/Source/WebCore/platform/network/curl/CurlStream.h
+++ b/Source/WebCore/platform/network/curl/CurlStream.h
@@ -56,12 +56,12 @@ public:
         virtual void didFail(CurlStreamID, CURLcode, CertificateInfo&&) = 0;
     };
 
-    static std::unique_ptr<CurlStream> create(CurlStreamScheduler& scheduler, CurlStreamID streamID, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias)
+    static std::unique_ptr<CurlStream> create(CurlStreamScheduler& scheduler, CurlStreamID streamID, bool ignoreCertificateErrors, URL&& url, ServerTrustEvaluation serverTrustEvaluation, LocalhostAlias localhostAlias)
     {
-        return makeUnique<CurlStream>(scheduler, streamID, WTFMove(url), serverTrustEvaluation, localhostAlias);
+        return makeUnique<CurlStream>(scheduler, streamID, ignoreCertificateErrors, WTFMove(url), serverTrustEvaluation, localhostAlias);
     }
 
-    CurlStream(CurlStreamScheduler&, CurlStreamID, URL&&, ServerTrustEvaluation, LocalhostAlias);
+    CurlStream(CurlStreamScheduler&, CurlStreamID, bool ignoreCertificateErrors, URL&&, ServerTrustEvaluation, LocalhostAlias);
     virtual ~CurlStream();
 
     void send(UniqueArray<uint8_t>&&, size_t);
diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp b/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp
index 83c4ca7871e536077f2d0a1a8ba6e2b4adb584da..12a49c124283fbe50ac17ecaa0c1e6fee32741d6 100644
--- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp
+++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.cpp
@@ -43,7 +43,7 @@ CurlStreamScheduler::~CurlStreamScheduler()
     ASSERT(isMainThread());
 }
 
-CurlStreamID CurlStreamScheduler::createStream(const URL& url, CurlStream::Client& client, CurlStream::ServerTrustEvaluation serverTrustEvaluation, CurlStream::LocalhostAlias localhostAlias)
+CurlStreamID CurlStreamScheduler::createStream(const URL& url, bool ignoreCertificateErrors, CurlStream::Client& client, CurlStream::ServerTrustEvaluation serverTrustEvaluation, CurlStream::LocalhostAlias localhostAlias)
 {
     ASSERT(isMainThread());
 
@@ -54,8 +54,8 @@ CurlStreamID CurlStreamScheduler::createStream(const URL& url, CurlStream::Clien
     auto streamID = m_currentStreamID;
     m_clientList.add(streamID, &client);
 
-    callOnWorkerThread([this, streamID, url = url.isolatedCopy(), serverTrustEvaluation, localhostAlias]() mutable {
-        m_streamList.add(streamID, CurlStream::create(*this, streamID, WTFMove(url), serverTrustEvaluation, localhostAlias));
+    callOnWorkerThread([this, streamID, ignoreCertificateErrors, url = url.isolatedCopy(), serverTrustEvaluation, localhostAlias]() mutable {
+        m_streamList.add(streamID, CurlStream::create(*this, streamID, ignoreCertificateErrors, WTFMove(url), serverTrustEvaluation, localhostAlias));
     });
 
     return streamID;
diff --git a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h
index 2d7a77d759aaea9a541030af5e6015a8ed9c97a4..a0c947d325c984045dbbdf2580d19a32eea86ada 100644
--- a/Source/WebCore/platform/network/curl/CurlStreamScheduler.h
+++ b/Source/WebCore/platform/network/curl/CurlStreamScheduler.h
@@ -39,7 +39,7 @@ public:
     CurlStreamScheduler();
     virtual ~CurlStreamScheduler();
 
-    WEBCORE_EXPORT CurlStreamID createStream(const URL&, CurlStream::Client&, CurlStream::ServerTrustEvaluation, CurlStream::LocalhostAlias);
+    WEBCORE_EXPORT CurlStreamID createStream(const URL&, bool ignoreCertificateErrors, CurlStream::Client&, CurlStream::ServerTrustEvaluation, CurlStream::LocalhostAlias);
     WEBCORE_EXPORT void destroyStream(CurlStreamID);
     WEBCORE_EXPORT void send(CurlStreamID, UniqueArray<uint8_t>&&, size_t);
 
diff --git a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp
index 7567442a6bdccbe755b2cf5e3fa42265a065a9e1..4886cf0b5a6bc0b8a270d763ad481f5bc6f0d1c2 100644
--- a/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp
+++ b/Source/WebCore/platform/network/curl/NetworkStorageSessionCurl.cpp
@@ -135,6 +135,12 @@ void NetworkStorageSession::setCookieAcceptPolicy(CookieAcceptPolicy policy) con
     cookieDatabase().setAcceptPolicy(policy);
 }
 
+void  NetworkStorageSession::setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL& url, const String& setCookieValue)
+{
+    for (auto& cookieString : setCookieValue.split('\n'))
+        cookieDatabase().setCookie(firstParty, url, cookieString, CookieJarDB::Source::Network);
+}
+
 HTTPCookieAcceptPolicy NetworkStorageSession::cookieAcceptPolicy() const
 {
     switch (cookieDatabase().acceptPolicy()) {
diff --git a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
index 09ab1320beacc41ae92399f3320aaf805d9d81d1..e1caf6e7ebd61151439a9c86350e57122784af0b 100644
--- a/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
+++ b/Source/WebCore/platform/network/soup/NetworkStorageSessionSoup.cpp
@@ -424,6 +424,26 @@ void NetworkStorageSession::replaceCookies(const Vector<Cookie>& cookies)
     g_signal_emit(jar, signalId, 0);
 }
 
+void  NetworkStorageSession::setCookiesFromResponse(const URL& firstParty, const SameSiteInfo&, const URL& url, const String& setCookieValue)
+{
+    auto origin = urlToSoupURI(url);
+    if (!origin)
+        return;
+
+    auto firstPartyURI = urlToSoupURI(firstParty);
+    if (!firstPartyURI)
+        return;
+
+    for (auto& cookieString : setCookieValue.split('\n')) {
+        GUniquePtr<SoupCookie> cookie(soup_cookie_parse(cookieString.utf8().data(), origin.get()));
+
+        if (!cookie)
+            continue;
+
+        soup_cookie_jar_add_cookie_full(cookieStorage(), cookie.release(), origin.get(), firstPartyURI.get());
+    }
+}
+
 void NetworkStorageSession::deleteCookie(const Cookie& cookie, CompletionHandler<void()>&& completionHandler)
 {
     GUniquePtr<SoupCookie> targetCookie(cookie.toSoupCookie());
diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp
index fd2a8e09edb5e076d8c436c69c41660bcd4f312e..455e9c4881744a86fdeaf29ebe50b303f7535825 100644
--- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp
+++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.cpp
@@ -40,6 +40,7 @@
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/win/WCharStringExtras.h>
 #include <wtf/unicode/CharacterNames.h>
+#include "Pasteboard.h"
 
 namespace WebCore {
 
@@ -690,7 +691,10 @@ template<typename T> void getStringData(IDataObject* data, FORMATETC* format, Ve
     STGMEDIUM store;
     if (FAILED(data->GetData(format, &store)))
         return;
-    dataStrings.append(String({ static_cast<T*>(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<T*>(GlobalLock(store.hGlobal)), ::GlobalSize(store.hGlobal) / sizeof(T) });
+    dataStrings.append(String::fromUTF8(rawString.utf8().data()));
     GlobalUnlock(store.hGlobal);
     ReleaseStgMedium(&store);
 }
diff --git a/Source/WebCore/platform/win/ClipboardUtilitiesWin.h b/Source/WebCore/platform/win/ClipboardUtilitiesWin.h
index c3ffc7392c0b7fa099a7dd4e4be977cdee1c803c..9570dbb0f2c42ca38598a8898183c9b310f858ab 100644
--- a/Source/WebCore/platform/win/ClipboardUtilitiesWin.h
+++ b/Source/WebCore/platform/win/ClipboardUtilitiesWin.h
@@ -34,6 +34,7 @@ namespace WebCore {
 
 class Document;
 class DocumentFragment;
+class Pasteboard;
 
 HGLOBAL createGlobalData(const String&);
 HGLOBAL createGlobalData(const Vector<char>&);
diff --git a/Source/WebCore/platform/win/DragDataWin.cpp b/Source/WebCore/platform/win/DragDataWin.cpp
index 0379437d84807e4a8d3846afac5ec8a70e743e70..5b0461bf12535d4900ffaddc2a87826280505233 100644
--- a/Source/WebCore/platform/win/DragDataWin.cpp
+++ b/Source/WebCore/platform/win/DragDataWin.cpp
@@ -40,12 +40,13 @@
 
 namespace WebCore {
 
-DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<DragOperation> sourceOperationMask, OptionSet<DragApplicationFlags> flags, std::optional<PageIdentifier> pageID)
+DragData::DragData(const DragDataMap& data, const IntPoint& clientPosition, const IntPoint& globalPosition, OptionSet<DragOperation> sourceOperationMask, OptionSet<DragApplicationFlags> flags, OptionSet<DragDestinationAction> dragDestinationAction, std::optional<PageIdentifier> pageID)
     : m_clientPosition(clientPosition)
     , m_globalPosition(globalPosition)
     , m_platformDragData(0)
     , m_draggingSourceOperationMask(sourceOperationMask)
     , m_applicationFlags(flags)
+    , m_dragDestinationActionMask(dragDestinationAction)
     , m_pageID(pageID)
     , m_dragDataMap(data)
 {
@@ -63,7 +64,7 @@ bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
         || (filenamePolicy == ConvertFilenames && (m_dragDataMap.contains(filenameWFormat()->cfFormat) || m_dragDataMap.contains(filenameFormat()->cfFormat)));
 }
 
-const DragDataMap& DragData::dragDataMap()
+const DragDataMap& DragData::dragDataMap() const
 {
     if (!m_dragDataMap.isEmpty() || !m_platformDragData)
         return m_dragDataMap;
diff --git a/Source/WebCore/platform/win/KeyEventWin.cpp b/Source/WebCore/platform/win/KeyEventWin.cpp
index d450bf9d0fd1f0bf8f28db483ac9d3d60fa9d114..72a59403a0b5493aea4a8e28eb15eac24b652b09 100644
--- a/Source/WebCore/platform/win/KeyEventWin.cpp
+++ b/Source/WebCore/platform/win/KeyEventWin.cpp
@@ -243,10 +243,16 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(HWND, WPARAM code, LPARAM keyData,
 {
 }
 
-void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type, bool)
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardsCompatibility)
 {
-    // No KeyDown events on Windows to disambiguate.
-    ASSERT_NOT_REACHED();
+    m_type = type;
+    if (type == PlatformEvent::Type::RawKeyDown) {
+        m_text = String();
+        m_unmodifiedText = String();
+    } else {
+        m_keyIdentifier = String();
+        m_windowsVirtualKeyCode = 0;
+    }
 }
 
 OptionSet<PlatformEvent::Modifier> PlatformKeyboardEvent::currentStateOfModifierKeys()
diff --git a/Source/WebCore/platform/win/PasteboardWin.cpp b/Source/WebCore/platform/win/PasteboardWin.cpp
index ec0b9f28cd41d15acb6feaa2132f08afb8a92b6b..496f5ec6733e72c28a55a748983dd868a0ef863b 100644
--- a/Source/WebCore/platform/win/PasteboardWin.cpp
+++ b/Source/WebCore/platform/win/PasteboardWin.cpp
@@ -1138,7 +1138,21 @@ void Pasteboard::writeCustomData(const Vector<PasteboardCustomData>& 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) {
@@ -1177,4 +1191,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<IEnumFORMATETC> itr;
+
+    if (FAILED(dragObject->EnumFormatEtc(DATADIR_GET, &itr)) || !itr)
+        return dragDataMap;
+
+    FORMATETC dataFormat;
+    while (itr->Next(1, &dataFormat, 0) == S_OK) {
+        Vector<String> dataStrings;
+        getClipboardData(dragObject.get(), &dataFormat, dataStrings);
+        if (!dataStrings.isEmpty())
+            dragDataMap.set(dataFormat.cfFormat, dataStrings);
+    }
+    return dragDataMap;
+}
+
 } // namespace WebCore
diff --git a/Source/WebCore/platform/wpe/DragDataWPE.cpp b/Source/WebCore/platform/wpe/DragDataWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..fbd32d390129129fd5b213f7f9c3e96bdca9355b
--- /dev/null
+++ b/Source/WebCore/platform/wpe/DragDataWPE.cpp
@@ -0,0 +1,92 @@
+/*
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "DragData.h"
+#include "SelectionData.h"
+
+namespace WebCore {
+
+bool DragData::canSmartReplace() const
+{
+    return false;
+}
+
+bool DragData::containsColor() const
+{
+    return false;
+}
+
+bool DragData::containsFiles() const
+{
+    return m_platformDragData->hasFilenames();
+}
+
+unsigned DragData::numberOfFiles() const
+{
+    return m_platformDragData->filenames().size();
+}
+
+Vector<String> DragData::asFilenames() const
+{
+    return m_platformDragData->filenames();
+}
+
+bool DragData::containsPlainText() const
+{
+    return m_platformDragData->hasText();
+}
+
+String DragData::asPlainText() const
+{
+    return m_platformDragData->text();
+}
+
+Color DragData::asColor() const
+{
+    return Color();
+}
+
+bool DragData::containsCompatibleContent(DraggingPurpose) const
+{
+    return containsPlainText() || containsURL() || containsColor() || containsFiles();
+}
+
+bool DragData::containsURL(FilenameConversionPolicy filenamePolicy) const
+{
+    return !asURL(filenamePolicy).isEmpty();
+}
+
+String DragData::asURL(FilenameConversionPolicy filenamePolicy, String* title) const
+{
+    if (!m_platformDragData->hasURL())
+        return String();
+    if (filenamePolicy != ConvertFilenames) {
+        if (m_platformDragData->url().protocolIsFile())
+            return { };
+    }
+
+    if (title)
+        *title = m_platformDragData->urlLabel();
+    return m_platformDragData->url().string();
+}
+
+bool DragData::shouldMatchStyleOnDrop() const
+{
+    return false;
+}
+
+}
diff --git a/Source/WebCore/platform/wpe/DragImageWPE.cpp b/Source/WebCore/platform/wpe/DragImageWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2454253889d4c7d5129c2d7895c089f54bc2e3d
--- /dev/null
+++ b/Source/WebCore/platform/wpe/DragImageWPE.cpp
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (C) 2010,2017 Igalia S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "DragImage.h"
+#include "NotImplemented.h"
+
+#include "Image.h"
+
+namespace WebCore {
+
+IntSize dragImageSize(DragImageRef)
+{
+    notImplemented();
+    return { 0, 0 };
+}
+
+void deleteDragImage(DragImageRef)
+{
+    notImplemented();
+}
+
+DragImageRef scaleDragImage(DragImageRef, FloatSize)
+{
+    notImplemented();
+    return nullptr;
+}
+
+DragImageRef dissolveDragImageToFraction(DragImageRef image, float)
+{
+    notImplemented();
+    return image;
+}
+
+DragImageRef createDragImageFromImage(Image* image, ImageOrientation)
+{
+    return image->currentNativeImage()->platformImage();
+}
+
+
+DragImageRef createDragImageIconForCachedImageFilename(const String&)
+{
+    notImplemented();
+    return nullptr;
+}
+
+DragImageRef createDragImageForLink(Element&, URL&, const String&, TextIndicatorData&, float)
+{
+    notImplemented();
+    return nullptr;
+}
+
+DragImageRef createDragImageForColor(const Color&, const FloatRect&, float, Path&)
+{
+    return nullptr;
+}
+
+}
diff --git a/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp b/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp
index 77bdff686770e56f5445fa12216c6bff93bb5cfb..e16583ea6298864df9c8b82cb0686b2afb18ce95 100644
--- a/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp
+++ b/Source/WebCore/platform/wpe/PlatformScreenWPE.cpp
@@ -151,12 +151,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..947bfe6576780038ecb87ea9bda116adb19dfd71
--- /dev/null
+++ b/Source/WebCore/platform/wpe/SelectionData.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2009, Martin Robinson
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "config.h"
+#include "SelectionData.h"
+
+#include <wtf/glib/GUniquePtr.h>
+#include <wtf/text/CString.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+SelectionData::SelectionData(const String& text, const String& markup, const URL& url, const String& uriList, RefPtr<WebCore::Image>&& image, RefPtr<WebCore::SharedBuffer>&& buffer, bool canSmartReplace)
+{
+    if (!text.isEmpty())
+        setText(text);
+    if (!markup.isEmpty())
+        setMarkup(markup);
+    if (!url.isEmpty())
+        setURL(url, String());
+    if (!uriList.isEmpty())
+        setURIList(uriList);
+    if (image)
+        setImage(WTFMove(image));
+    if (buffer)
+        setCustomData(buffer.releaseNonNull());
+    setCanSmartReplace(canSmartReplace);
+}
+
+static void replaceNonBreakingSpaceWithSpace(String& str)
+{
+    static const UChar NonBreakingSpaceCharacter = 0xA0;
+    static const UChar SpaceCharacter = ' ';
+    str = makeStringByReplacingAll(str, NonBreakingSpaceCharacter, SpaceCharacter);
+}
+
+void SelectionData::setText(const String& newText)
+{
+    m_text = newText;
+    replaceNonBreakingSpaceWithSpace(m_text);
+}
+
+void SelectionData::setURIList(const String& uriListString)
+{
+    m_uriList = uriListString;
+
+    // This code is originally from: platform/chromium/ChromiumDataObject.cpp.
+    // FIXME: We should make this code cross-platform eventually.
+
+    // Line separator is \r\n per RFC 2483 - however, for compatibility
+    // reasons we also allow just \n here.
+
+    // Process the input and copy the first valid URL into the url member.
+    // In case no URLs can be found, subsequent calls to getData("URL")
+    // will get an empty string. This is in line with the HTML5 spec (see
+    // "The DragEvent and DataTransfer interfaces"). Also extract all filenames
+    // from the URI list.
+    bool setURL = hasURL();
+    for (auto& line : uriListString.split('\n')) {
+        line = line.trim(deprecatedIsSpaceOrNewline);
+        if (line.isEmpty())
+            continue;
+        if (line[0] == '#')
+            continue;
+
+        URL url = URL(URL(), line);
+        if (url.isValid()) {
+            if (!setURL) {
+                m_url = url;
+                setURL = true;
+            }
+
+            GUniqueOutPtr<GError> error;
+            GUniquePtr<gchar> 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("<a href=\""_s);
+    markup.append(url.string());
+    markup.append("\">"_s);
+    GUniquePtr<gchar> escaped(g_markup_escape_text(actualLabel.utf8().data(), -1));
+    markup.append(String::fromUTF8(escaped.get()));
+    markup.append("</a>"_s);
+    setMarkup(markup.toString());
+}
+
+const String& SelectionData::urlLabel() const
+{
+    if (hasText())
+        return text();
+
+    if (hasURL())
+        return url().string();
+
+    return emptyString();
+}
+
+void SelectionData::clearAllExceptFilenames()
+{
+    clearText();
+    clearMarkup();
+    clearURIList();
+    clearURL();
+    clearImage();
+    clearCustomData();
+
+    m_canSmartReplace = false;
+}
+
+void SelectionData::clearAll()
+{
+    clearAllExceptFilenames();
+    m_filenames.clear();
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/wpe/SelectionData.h b/Source/WebCore/platform/wpe/SelectionData.h
new file mode 100644
index 0000000000000000000000000000000000000000..a76b583a1e65cd6999fab4784c22dd9cb48d6aeb
--- /dev/null
+++ b/Source/WebCore/platform/wpe/SelectionData.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009, Martin Robinson
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#pragma once
+
+#include "Image.h"
+#include "SharedBuffer.h"
+#include <wtf/HashMap.h>
+#include <wtf/URL.h>
+#include <wtf/text/StringHash.h>
+
+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<String>& filenames() const { return m_filenames; }
+    bool hasURIList() const { return !m_uriList.isEmpty(); }
+    bool hasFilenames() const { return !m_filenames.isEmpty(); }
+    void clearURIList() { m_uriList = emptyString(); }
+
+    void setImage(RefPtr<Image>&& newImage) { m_image = WTFMove(newImage); }
+    const RefPtr<Image>& image() const { return m_image; }
+    bool hasImage() const { return m_image; }
+    void clearImage() { m_image = nullptr; }
+
+    void setCanSmartReplace(bool canSmartReplace) { m_canSmartReplace = canSmartReplace; }
+    bool canSmartReplace() const { return m_canSmartReplace; }
+
+    void setCustomData(Ref<SharedBuffer>&& buffer) { m_customData = WTFMove(buffer); }
+    const RefPtr<SharedBuffer>& customData() const { return m_customData; }
+    bool hasCustomData() const { return !!m_customData; }
+    void clearCustomData() { m_customData = nullptr; }
+
+    void clearAll();
+    void clearAllExceptFilenames();
+
+    SelectionData(const String& text, const String& markup, const URL&, const String& uriList, RefPtr<WebCore::Image>&&, RefPtr<WebCore::SharedBuffer>&&, bool);
+    SelectionData() = default;
+
+private:
+    String m_text;
+    String m_markup;
+    URL m_url;
+    String m_uriList;
+    Vector<String> m_filenames;
+    RefPtr<Image> m_image;
+    bool m_canSmartReplace { false };
+    RefPtr<SharedBuffer> m_customData;
+};
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp
index 02afb718cfae6a4314ab704fbe6a70d88a530312..ed32870de0571317a6527d89a14a6a51b7acfd33 100644
--- a/Source/WebCore/rendering/RenderTextControl.cpp
+++ b/Source/WebCore/rendering/RenderTextControl.cpp
@@ -225,13 +225,13 @@ void RenderTextControl::layoutExcludedChildren(bool relayoutChildren)
     }
 }
 
-#if PLATFORM(IOS_FAMILY)
 bool RenderTextControl::canScroll() const
 {
     auto innerText = innerTextElement();
     return innerText && innerText->renderer() && innerText->renderer()->hasNonVisibleOverflow();
 }
 
+#if PLATFORM(IOS_FAMILY)
 int RenderTextControl::innerLineHeight() const
 {
     auto innerText = innerTextElement();
diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h
index 8ff886aec15c960e06408f638892579a6c3f4879..a5f8889818e456504c82a99994dcf4b21774b99d 100644
--- a/Source/WebCore/rendering/RenderTextControl.h
+++ b/Source/WebCore/rendering/RenderTextControl.h
@@ -37,9 +37,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/workers/WorkerConsoleClient.cpp b/Source/WebCore/workers/WorkerConsoleClient.cpp
index 5b64d59511778572142eae5e48b16cfaa1040d49..7082cd677870f4c359130bc065bdee097c82feda 100644
--- a/Source/WebCore/workers/WorkerConsoleClient.cpp
+++ b/Source/WebCore/workers/WorkerConsoleClient.cpp
@@ -104,4 +104,6 @@ void WorkerConsoleClient::recordEnd(JSC::JSGlobalObject*, Ref<ScriptArguments>&&
 // FIXME: <https://webkit.org/b/243361> Web Inspector: support console screenshots in a Worker
 void WorkerConsoleClient::screenshot(JSC::JSGlobalObject*, Ref<ScriptArguments>&&) { }
 
+void WorkerConsoleClient::bindingCalled(JSC::JSGlobalObject*, const String&, const String&) { }
+
 } // namespace WebCore
diff --git a/Source/WebCore/workers/WorkerConsoleClient.h b/Source/WebCore/workers/WorkerConsoleClient.h
index db95c8273bd0deb3f903a45d02fc07bbbd8ab305..bf88228b4c838b90d11d430cc9429d5130631afa 100644
--- a/Source/WebCore/workers/WorkerConsoleClient.h
+++ b/Source/WebCore/workers/WorkerConsoleClient.h
@@ -58,6 +58,7 @@ private:
     void record(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override;
     void recordEnd(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override;
     void screenshot(JSC::JSGlobalObject*, Ref<Inspector::ScriptArguments>&&) override;
+    void bindingCalled(JSC::JSGlobalObject*, const String& name, const String& arg) override;
 
     WorkerOrWorkletGlobalScope& m_globalScope;
 };
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
index c677a1dda62afcad62a41f1b8b8ff886ce7412ee..1df6de27593cab0e5f96c9d906a45f55003e1a66 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.cpp
@@ -96,6 +96,8 @@
 
 #if PLATFORM(COCOA)
 #include <wtf/OSObjectPtr.h>
+#include "NetworkDataTaskCocoa.h"
+#include "NetworkSessionCocoa.h"
 #endif
 
 #if ENABLE(APPLE_PAY_REMOTE_UI)
@@ -1130,6 +1132,14 @@ void NetworkConnectionToWebProcess::clearPageSpecificData(PageIdentifier pageID)
         storageSession->clearPageSpecificDataForResourceLoadStatistics(pageID);
 }
 
+void NetworkConnectionToWebProcess::setCookieFromResponse(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, const String& setCookieValue)
+{
+    auto* networkStorageSession = storageSession();
+    if (!networkStorageSession)
+        return;
+    networkStorageSession->setCookiesFromResponse(firstParty, sameSiteInfo, url, setCookieValue);
+}
+
 void NetworkConnectionToWebProcess::removeStorageAccessForFrame(FrameIdentifier frameID, PageIdentifier pageID)
 {
     if (auto* storageSession = protectedNetworkProcess()->storageSession(m_sessionID))
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
index 590065cea0e5ed1167f6f8fc1a747c2d32a23c01..2807fb69297332011f38b5c3a27973ca53754c0a 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.h
@@ -374,6 +374,8 @@ private:
 
     void clearPageSpecificData(WebCore::PageIdentifier);
 
+    void setCookieFromResponse(const URL& firstParty, const WebCore::SameSiteInfo&, const URL& url, const String& setCookieValue);
+
     void removeStorageAccessForFrame(WebCore::FrameIdentifier, WebCore::PageIdentifier);
 
     void logUserInteraction(RegistrableDomain&&);
diff --git a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
index c493d8e359dfdd393cee8ab77d25fc08e942ba77..4934c6b5038953ec1f1662b03400f6d1f8fec9d7 100644
--- a/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
+++ b/Source/WebKit/NetworkProcess/NetworkConnectionToWebProcess.messages.in
@@ -79,6 +79,8 @@ messages -> NetworkConnectionToWebProcess WantsDispatchMessage {
 
     ClearPageSpecificData(WebCore::PageIdentifier pageID);
 
+    SetCookieFromResponse(URL firstParty, struct WebCore::SameSiteInfo sameSiteInfo, URL url, String setCookieValue);
+
     RemoveStorageAccessForFrame(WebCore::FrameIdentifier frameID, WebCore::PageIdentifier pageID);
     LogUserInteraction(WebCore::RegistrableDomain domain)
     ResourceLoadStatisticsUpdated(Vector<WebCore::ResourceLoadStatistics> statistics) -> ()
diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.cpp b/Source/WebKit/NetworkProcess/NetworkProcess.cpp
index 239ba1501c57b46b28f7e6442ae9a65935b7fcf0..819e8c69ddc28abbac2a82ced2c80ad41db9a1c3 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcess.cpp
+++ b/Source/WebKit/NetworkProcess/NetworkProcess.cpp
@@ -648,6 +648,12 @@ void NetworkProcess::registrableDomainsExemptFromWebsiteDataDeletion(PAL::Sessio
     completionHandler({ });
 }
 
+void NetworkProcess::setIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignore)
+{
+    if (auto* networkSession = this->networkSession(sessionID))
+        networkSession->setIgnoreCertificateErrors(ignore);
+}
+
 void NetworkProcess::dumpResourceLoadStatistics(PAL::SessionID sessionID, CompletionHandler<void(String)>&& completionHandler)
 {
     if (auto* session = networkSession(sessionID)) {
diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.h b/Source/WebKit/NetworkProcess/NetworkProcess.h
index a4ff8274229c85548135766cd1623d65813d9a12..6d500eeae356757850cfd55d62d6ec75ffe280d1 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcess.h
+++ b/Source/WebKit/NetworkProcess/NetworkProcess.h
@@ -84,6 +84,7 @@ class SessionID;
 
 namespace WebCore {
 class CertificateInfo;
+struct Cookie;
 class CurlProxySettings;
 class ProtectionSpace;
 class NetworkStorageSession;
@@ -227,6 +228,9 @@ public:
 
     void registrableDomainsWithLastAccessedTime(PAL::SessionID, CompletionHandler<void(std::optional<HashMap<RegistrableDomain, WallTime>>)>&&);
     void registrableDomainsExemptFromWebsiteDataDeletion(PAL::SessionID, CompletionHandler<void(HashSet<RegistrableDomain>)>&&);
+
+    void setIgnoreCertificateErrors(PAL::SessionID, bool);
+
     void clearPrevalentResource(PAL::SessionID, RegistrableDomain&&, CompletionHandler<void()>&&);
     void clearUserInteraction(PAL::SessionID, RegistrableDomain&&, CompletionHandler<void()>&&);
     void deleteAndRestrictWebsiteDataForRegistrableDomains(PAL::SessionID, OptionSet<WebsiteDataType>, RegistrableDomainsToDeleteOrRestrictWebsiteDataFor&&, CompletionHandler<void(HashSet<RegistrableDomain>&&)>&&);
diff --git a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
index 07286a774824c1ebab411668c173450aaa3d8db0..4a424aa025202517aa5392b969cfe50552628f14 100644
--- a/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
+++ b/Source/WebKit/NetworkProcess/NetworkProcess.messages.in
@@ -85,6 +85,8 @@ messages -> NetworkProcess : AuxiliaryProcess WantsAsyncDispatchMessage {
 
     SetInspectionForServiceWorkersAllowed(PAL::SessionID sessionID, bool inspectable)
 
+    SetIgnoreCertificateErrors(PAL::SessionID sessionID, bool ignoreTLSErrors)
+
     ClearPrevalentResource(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> ()
     ClearUserInteraction(PAL::SessionID sessionID, WebCore::RegistrableDomain resourceDomain) -> ()
     DumpResourceLoadStatistics(PAL::SessionID sessionID) -> (String dumpedStatistics)
diff --git a/Source/WebKit/NetworkProcess/NetworkSession.h b/Source/WebKit/NetworkProcess/NetworkSession.h
index e04e1ab157e39b042af9a9a02866ad871264a496..7ba4f9bba80d8c8af7bb1a6383b36bb436ce26c4 100644
--- a/Source/WebKit/NetworkProcess/NetworkSession.h
+++ b/Source/WebKit/NetworkProcess/NetworkSession.h
@@ -204,6 +204,9 @@ public:
 
     void lowMemoryHandler(WTF::Critical);
 
+    void setIgnoreCertificateErrors(bool ignore) { m_ignoreCertificateErrors = ignore; }
+    bool ignoreCertificateErrors() { return m_ignoreCertificateErrors; }
+
     void removeSoftUpdateLoader(ServiceWorkerSoftUpdateLoader* loader) { m_softUpdateLoaders.remove(loader); }
     void addNavigationPreloaderTask(ServiceWorkerFetchTask&);
     ServiceWorkerFetchTask* navigationPreloaderTaskFromFetchIdentifier(WebCore::FetchIdentifier);
@@ -321,6 +324,7 @@ protected:
     bool m_privateClickMeasurementDebugModeEnabled { false };
     std::optional<WebCore::PrivateClickMeasurement> m_ephemeralMeasurement;
     bool m_isRunningEphemeralMeasurementTest { false };
+    bool m_ignoreCertificateErrors { false };
 
     HashSet<Ref<NetworkResourceLoader>> m_keptAliveLoads;
 
diff --git a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
index 9525ea0ff6d7a3ae90ceb319a13600f682524c32..4461f24b5087cae6203b4c0f12db4edc0e2c2380 100644
--- a/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
+++ b/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
@@ -772,6 +772,8 @@ - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didRece
 
     if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
         sessionCocoa->setClientAuditToken(challenge);
+        if (sessionCocoa->ignoreCertificateErrors())
+            return completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
 
         NSURLSessionTaskTransactionMetrics *metrics = task._incompleteTaskMetrics.transactionMetrics.lastObject;
         auto tlsVersion = (tls_protocol_version_t)metrics.negotiatedTLSProtocolVersion.unsignedShortValue;
@@ -1121,6 +1123,13 @@ - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)data
 
         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, privateRelayed, [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 1e1c7897c858ddd5a1c69a4d5942102f5649ef14..1d2a4835905018a39bc33488e9bc1450cb728179 100644
--- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp
+++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.cpp
@@ -80,10 +80,18 @@ NetworkDataTaskCurl::NetworkDataTaskCurl(NetworkSession& session, NetworkDataTas
         blockCookies();
     restrictRequestReferrerToOriginIfNeeded(request);
 
-    m_curlRequest = createCurlRequest(WTFMove(request));
-    if (!m_initialCredential.isEmpty()) {
-        m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password());
-        m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic);
+    if (request.url().protocolIsData()) {
+        DataURLDecoder::decode(request.url(), { }, DataURLDecoder::ShouldValidatePadding::Yes, [this, protectedThis = Ref { *this }](auto decodeResult) mutable {
+            didReadDataURL(WTFMove(decodeResult));
+        });
+    } else {
+        m_curlRequest = createCurlRequest(WTFMove(request));
+        if (!m_initialCredential.isEmpty()) {
+            m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password());
+            m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic);
+        }
+        if (m_session->ignoreCertificateErrors())
+            m_curlRequest->disableServerTrustEvaluation();
     }
 }
 
@@ -166,6 +174,7 @@ void NetworkDataTaskCurl::curlDidReceiveResponse(CurlRequest& request, CurlRespo
 
     updateNetworkLoadMetrics(receivedResponse.networkLoadMetrics);
     m_response.setDeprecatedNetworkLoadMetrics(Box<NetworkLoadMetrics>::create(WTFMove(receivedResponse.networkLoadMetrics)));
+    m_response.m_httpRequestHeaderFields = request.resourceRequest().httpHeaderFields();
 
     handleCookieHeaders(request.resourceRequest(), receivedResponse);
 
@@ -294,6 +303,36 @@ bool NetworkDataTaskCurl::shouldRedirectAsGET(const ResourceRequest& request, bo
     return false;
 }
 
+void NetworkDataTaskCurl::didReadDataURL(std::optional<DataURLDecoder::Result>&& result)
+{
+    if (state() == State::Canceling || state() == State::Completed)
+        return;
+
+    m_dataURLResult = WTFMove(result);
+    m_response = ResourceResponse::dataURLResponse(firstRequest().url(), m_dataURLResult.value());
+    invokeDidReceiveResponse();
+}
+
+void NetworkDataTaskCurl::downloadDataURL(Download& download)
+{
+    if (!m_dataURLResult) {
+        deleteDownloadFile();
+        download.didFail(internalError(firstRequest().url()), std::span<const uint8_t>());
+        return;
+    }
+
+    if (-1 == FileSystem::writeToFile(m_downloadDestinationFile, std::span<const uint8_t>(m_dataURLResult.value().data.data(), m_dataURLResult.value().data.size()))) {
+        deleteDownloadFile();
+        download.didFail(ResourceError(CURLE_WRITE_ERROR, m_response.url()), std::span<const uint8_t>());
+        return;
+    }
+
+    download.didReceiveData(m_dataURLResult.value().data.size(), 0, 0);
+    FileSystem::closeFile(m_downloadDestinationFile);
+    m_downloadDestinationFile = FileSystem::invalidPlatformFileHandle;
+    download.didFinish();
+}
+
 void NetworkDataTaskCurl::invokeDidReceiveResponse()
 {
     didReceiveResponse(ResourceResponse(m_response), NegotiatedLegacyTLS::No, PrivateRelayed::No, std::nullopt, [this, protectedThis = Ref { *this }](PolicyAction policyAction) {
@@ -323,6 +362,8 @@ void NetworkDataTaskCurl::invokeDidReceiveResponse()
             download->didCreateDestination(m_pendingDownloadLocation);
             if (m_curlRequest)
                 m_curlRequest->completeDidReceiveResponse();
+            else if (firstRequest().url().protocolIsData())
+                downloadDataURL(download);
             break;
         }
         default:
@@ -411,6 +452,8 @@ void NetworkDataTaskCurl::willPerformHTTPRedirection()
             m_curlRequest->setUserPass(m_initialCredential.user(), m_initialCredential.password());
             m_curlRequest->setAuthenticationScheme(ProtectionSpace::AuthenticationScheme::HTTPBasic);
         }
+        if (m_session->ignoreCertificateErrors())
+            m_curlRequest->disableServerTrustEvaluation();
 
         if (m_state != State::Suspended) {
             m_state = State::Suspended;
diff --git a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h
index 0f7c70e405d00416c9e5e58f9c56423a4cf3947c..b730722c5bdb3949bedc1a578089bb3ea2d4af67 100644
--- a/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h
+++ b/Source/WebKit/NetworkProcess/curl/NetworkDataTaskCurl.h
@@ -28,6 +28,7 @@
 #include "NetworkDataTask.h"
 #include "NetworkLoadParameters.h"
 #include <WebCore/CurlRequestClient.h>
+#include <WebCore/DataURLDecoder.h>
 #include <WebCore/FrameIdentifier.h>
 #include <WebCore/PageIdentifier.h>
 #include <WebCore/ProtectionSpace.h>
@@ -43,6 +44,8 @@ class SharedBuffer;
 
 namespace WebKit {
 
+class Download;
+
 class NetworkDataTaskCurl final : public NetworkDataTask, public WebCore::CurlRequestClient {
 public:
     static Ref<NetworkDataTask> create(NetworkSession& session, NetworkDataTaskClient& client, const NetworkLoadParameters& parameters)
@@ -76,6 +79,9 @@ private:
     void curlDidComplete(WebCore::CurlRequest&, WebCore::NetworkLoadMetrics&&) override;
     void curlDidFailWithError(WebCore::CurlRequest&, WebCore::ResourceError&&, WebCore::CertificateInfo&&) override;
 
+    void didReadDataURL(std::optional<WebCore::DataURLDecoder::Result>&&);
+    void downloadDataURL(Download&);
+
     void invokeDidReceiveResponse();
 
     bool shouldStartHTTPRedirection();
@@ -114,6 +120,9 @@ private:
     unsigned m_authFailureCount { 0 };
 
     bool m_allowOverwriteDownload { false };
+
+    std::optional<WebCore::DataURLDecoder::Result> m_dataURLResult;
+
     FileSystem::PlatformFileHandle m_downloadDestinationFile { FileSystem::invalidPlatformFileHandle };
 
     bool m_blockingCookies { false };
diff --git a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp
index 49685c872d0fb042a401612201a7448af6f1ac8b..e98efc1c2e7e5a85980c8d39afcb600a1f6c5d23 100644
--- a/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp
+++ b/Source/WebKit/NetworkProcess/curl/NetworkSessionCurl.cpp
@@ -68,7 +68,7 @@ void NetworkSessionCurl::clearAlternativeServices(WallTime)
 
 std::unique_ptr<WebSocketTask> NetworkSessionCurl::createWebSocketTask(WebPageProxyIdentifier webPageProxyID, std::optional<FrameIdentifier>, std::optional<PageIdentifier>, NetworkSocketChannel& channel, const WebCore::ResourceRequest& request, const String& protocol, const WebCore::ClientOrigin& clientOrigin, bool, bool, OptionSet<WebCore::AdvancedPrivacyProtections>, ShouldRelaxThirdPartyCookieBlocking, StoredCredentialsPolicy)
 {
-    return makeUnique<WebSocketTask>(channel, webPageProxyID, request, protocol, clientOrigin);
+    return makeUnique<WebSocketTask>(channel, webPageProxyID, request, protocol, ignoreCertificateErrors(), clientOrigin);
 }
 
 void NetworkSessionCurl::didReceiveChallenge(WebSocketTask& webSocketTask, WebCore::AuthenticationChallenge&& challenge, CompletionHandler<void(WebKit::AuthenticationChallengeDisposition, const WebCore::Credential&)>&& challengeCompletionHandler)
diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp
index 57da1a448cc75e4a24f0a2b3e7159452da8da2df..f64b446e074cb58c36be5f68ccb07e4584a38a1f 100644
--- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp
+++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.cpp
@@ -39,11 +39,12 @@
 namespace WebKit {
 WTF_MAKE_TZONE_ALLOCATED_IMPL(WebSocketTask);
 
-WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifier webProxyPageID, const WebCore::ResourceRequest& request, const String& protocol, const WebCore::ClientOrigin& clientOrigin)
+WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifier webProxyPageID, const WebCore::ResourceRequest& request, const String& protocol, bool ignoreCertificateErrors, const WebCore::ClientOrigin& clientOrigin)
     : m_channel(channel)
     , m_webProxyPageID(webProxyPageID)
     , m_request(request.isolatedCopy())
     , m_protocol(protocol)
+    , m_ignoreCertificateErrors(ignoreCertificateErrors)
     , m_scheduler(WebCore::CurlContext::singleton().streamScheduler())
 {
     // We use topOrigin in case of service worker websocket connections, for which pageID does not link to a real page.
@@ -55,7 +56,7 @@ WebSocketTask::WebSocketTask(NetworkSocketChannel& channel, WebPageProxyIdentifi
     if (networkSession() && networkSession()->networkProcess().localhostAliasesForTesting().contains<StringViewHashTranslator>(m_request.url().host()))
         localhostAlias = WebCore::CurlStream::LocalhostAlias::Enable;
 
-    m_streamID = m_scheduler.createStream(request.url(), *this, WebCore::CurlStream::ServerTrustEvaluation::Enable, localhostAlias);
+    m_streamID = m_scheduler.createStream(request.url(), ignoreCertificateErrors, *this, WebCore::CurlStream::ServerTrustEvaluation::Enable, localhostAlias);
     channel.didSendHandshakeRequest(WebCore::ResourceRequest(m_request));
 }
 
@@ -265,7 +266,7 @@ void WebSocketTask::tryServerTrustEvaluation(WebCore::AuthenticationChallenge&&
             if (networkSession() && networkSession()->networkProcess().localhostAliasesForTesting().contains<StringViewHashTranslator>(m_request.url().host()))
                 localhostAlias = WebCore::CurlStream::LocalhostAlias::Enable;
 
-            m_streamID = m_scheduler.createStream(m_request.url(), *this, WebCore::CurlStream::ServerTrustEvaluation::Disable, localhostAlias);
+            m_streamID = m_scheduler.createStream(m_request.url(), m_ignoreCertificateErrors, *this, WebCore::CurlStream::ServerTrustEvaluation::Disable, localhostAlias);
         } else
             didFail(WTFMove(errorReason));
     });
diff --git a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h
index 70c88bf553159e26e63c6dc735ae2bb4358df698..967b2c849206784efe3b0d9a2364cd3e7600b1f9 100644
--- a/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h
+++ b/Source/WebKit/NetworkProcess/curl/WebSocketTaskCurl.h
@@ -55,7 +55,7 @@ class WebSocketTask : public CanMakeWeakPtr<WebSocketTask>, public CanMakeChecke
     WTF_MAKE_TZONE_ALLOCATED(WebSocketTask);
     WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(WebSocketTask);
 public:
-    WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, const String& protocol, const WebCore::ClientOrigin&);
+    WebSocketTask(NetworkSocketChannel&, WebPageProxyIdentifier, const WebCore::ResourceRequest&, const String& protocol,  bool ignoreCertificateErrors, const WebCore::ClientOrigin&);
     virtual ~WebSocketTask();
 
     void sendString(std::span<const uint8_t>, CompletionHandler<void()>&&);
@@ -110,6 +110,7 @@ private:
     WebPageProxyIdentifier m_webProxyPageID;
     WebCore::ResourceRequest m_request;
     String m_protocol;
+    bool m_ignoreCertificateErrors { false };
     WebCore::SecurityOriginData m_topOrigin;
 
     WebCore::CurlStreamScheduler& m_scheduler;
diff --git a/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in b/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in
index a6d86f1388e8cae7c3939d1ecffb2c46eb5054c5..9e11224335211908fe8bf14edc4c22e9e4934582 100644
--- a/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in
+++ b/Source/WebKit/NetworkProcess/mac/com.apple.WebKit.NetworkProcess.sb.in
@@ -451,9 +451,11 @@
 
 ;; FIXME: This should be removed when <rdar://problem/10479685> is fixed.
 ;; Restrict AppSandboxed processes from creating /Library/Keychains, but allow access to the contents of /Library/Keychains:
-(allow file-read-data file-read-metadata
-    (subpath "/Library/Keychains")
-    (home-subpath "/Library/Keychains"))
+;; Playwright begin
+;; (allow file-read-data file-read-metadata
+;;     (subpath "/Library/Keychains")
+;;     (home-subpath "/Library/Keychains"))
+;; Playwright end
 
 ;; Except deny access to new-style iOS Keychain folders which are UUIDs.
 (deny file-read* file-write*
diff --git a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
index d781f70f2c31ff5631773684893a40d738bd9856..6270cfd7707a190f123b9750a31162fbc64c3086 100644
--- a/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
+++ b/Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp
@@ -461,6 +461,8 @@ void NetworkDataTaskSoup::didSendRequest(GRefPtr<GInputStream>&& inputStream)
     m_networkLoadMetrics.responseStart = MonotonicTime::now();
 #endif
 
+    auto& additionalMetrics = additionalNetworkLoadMetricsForWebInspector();
+    m_response.m_httpRequestHeaderFields = additionalMetrics.requestHeaders;
     dispatchDidReceiveResponse();
 }
 
@@ -563,6 +565,8 @@ bool NetworkDataTaskSoup::acceptCertificate(GTlsCertificate* certificate, GTlsCe
 {
     ASSERT(m_soupMessage);
     URL url = soupURIToURL(soup_message_get_uri(m_soupMessage.get()));
+    if (m_session->ignoreCertificateErrors())
+        return true;
     auto error = static_cast<NetworkSessionSoup&>(*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 599c405513ee38c74da12c01dafc23c6ece86aa0..5af7dc9306d211a5cff1736013716b08933e2278 100644
--- a/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp
+++ b/Source/WebKit/NetworkProcess/soup/NetworkSessionSoup.cpp
@@ -100,6 +100,11 @@ void NetworkSessionSoup::clearCredentials(WallTime)
 #endif
 }
 
+static gboolean webSocketAcceptCertificateCallbackIgnoreTLSErrors(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session)
+{
+    return TRUE;
+}
+
 #if USE(SOUP2)
 static gboolean webSocketAcceptCertificateCallback(GTlsConnection* connection, GTlsCertificate* certificate, GTlsCertificateFlags errors, NetworkSessionSoup* session)
 {
@@ -130,12 +135,16 @@ std::unique_ptr<WebSocketTask> NetworkSessionSoup::createWebSocketTask(WebPagePr
 #if USE(SOUP2)
         g_signal_connect(soupMessage.get(), "network-event", G_CALLBACK(webSocketMessageNetworkEventCallback), this);
 #else
-        g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors,  NetworkSessionSoup* session) -> gboolean {
-            if (DeprecatedGlobalSettings::allowsAnySSLCertificate())
-                return TRUE;
-
-            return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors);
-        }), this);
+        if (ignoreCertificateErrors()) {
+            g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(webSocketAcceptCertificateCallbackIgnoreTLSErrors), this);
+        } else {
+            g_signal_connect(soupMessage.get(), "accept-certificate", G_CALLBACK(+[](SoupMessage* message, GTlsCertificate* certificate, GTlsCertificateFlags errors,  NetworkSessionSoup* session) -> gboolean {
+                if (DeprecatedGlobalSettings::allowsAnySSLCertificate())
+                    return TRUE;
+
+                return !session->soupNetworkSession().checkTLSErrors(soup_message_get_uri(message), certificate, errors);
+            }), this);
+        }
 #endif
     }
 
diff --git a/Source/WebKit/PlatformGTK.cmake b/Source/WebKit/PlatformGTK.cmake
index 232378e3be5e4e1b4bdd9f97a722f518f8fdec33..fed6a3de75b889fa90e18cb95300ceecb3e80d40 100644
--- a/Source/WebKit/PlatformGTK.cmake
+++ b/Source/WebKit/PlatformGTK.cmake
@@ -327,6 +327,9 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES
     ${GSTREAMER_PBUTILS_INCLUDE_DIRS}
     ${GTK_INCLUDE_DIRS}
     ${LIBSOUP_INCLUDE_DIRS}
+# Playwright begin
+    ${LIBVPX_INCLUDE_DIRS}
+# Playwright end
 )
 
 list(APPEND WebKit_INTERFACE_INCLUDE_DIRECTORIES
@@ -363,6 +366,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 ()
 
@@ -414,6 +420,12 @@ else ()
     set(WebKitGTK_ENUM_HEADER_TEMPLATE ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitEnumTypesGtk3.h.in)
 endif ()
 
+# Playwright begin
+list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm"
+)
+# Playwright end
+
 # To generate WebKitEnumTypes.h we want to use all installed headers, except WebKitEnumTypes.h itself.
 set(WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_INSTALLED_HEADERS})
 list(REMOVE_ITEM WebKitGTK_ENUM_GENERATION_HEADERS ${WebKitGTK_DERIVED_SOURCES_DIR}/webkit/WebKitEnumTypes.h)
diff --git a/Source/WebKit/PlatformWPE.cmake b/Source/WebKit/PlatformWPE.cmake
index 3c5bdcf25c6f9c0c86d0c4550d5dc7486f99d703..259fce0cf15b4263148f6f6da59161001875b465 100644
--- a/Source/WebKit/PlatformWPE.cmake
+++ b/Source/WebKit/PlatformWPE.cmake
@@ -117,6 +117,8 @@ list(APPEND WebKit_SERIALIZATION_IN_FILES
     Shared/glib/UserMessage.serialization.in
 
     Shared/soup/WebCoreArgumentCodersSoup.serialization.in
+
+    Shared/libwpe/ArgumentCodersWPE.serialization.in
 )
 
 list(APPEND WebKit_DERIVED_SOURCES
@@ -221,6 +223,7 @@ set(WPE_API_HEADER_TEMPLATES
     ${WEBKIT_DIR}/UIProcess/API/glib/WebKitWindowProperties.h.in
     ${WEBKIT_DIR}/UIProcess/API/glib/WebKitWebsitePolicies.h.in
     ${WEBKIT_DIR}/UIProcess/API/glib/webkit.h.in
+    ${WEBKIT_DIR}/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in
 )
 
 if (ENABLE_2022_GLIB_API)
@@ -430,7 +433,16 @@ list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES
     ${GIO_UNIX_INCLUDE_DIRS}
     ${GLIB_INCLUDE_DIRS}
     ${LIBSOUP_INCLUDE_DIRS}
+# Playwright begin
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include"
+# Playwright end
+)
+
+# Playwright begin
+list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm"
 )
+# Playwright end
 
 list(APPEND WebKit_LIBRARIES
     WPE::libwpe
diff --git a/Source/WebKit/PlatformWin.cmake b/Source/WebKit/PlatformWin.cmake
index d68c315379e227e41722991651c1c1285194bad6..401aa471b17032bf3fb3f3de8bc14f14fd304719 100644
--- a/Source/WebKit/PlatformWin.cmake
+++ b/Source/WebKit/PlatformWin.cmake
@@ -55,8 +55,13 @@ list(APPEND WebKit_SOURCES
     UIProcess/WebsiteData/win/WebsiteDataStoreWin.cpp
 
     UIProcess/win/AutomationClientWin.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
@@ -72,6 +77,7 @@ list(APPEND WebKit_SOURCES
     WebProcess/MediaCache/WebMediaKeyStorageManager.cpp
 
     WebProcess/WebCoreSupport/win/WebPopupMenuWin.cpp
+    WebProcess/WebCoreSupport/win/WebDragClientWin.cpp
 
     WebProcess/WebPage/AcceleratedSurface.cpp
 
@@ -117,8 +123,81 @@ list(APPEND WebKit_PUBLIC_FRAMEWORK_HEADERS
 
 list(APPEND WebKit_PRIVATE_LIBRARIES
     comctl32
+    ${LIBVPX_CUSTOM_LIBRARY}
+)
+
+# Playwright begin
+list(APPEND WebKit_SYSTEM_INCLUDE_DIRECTORIES
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include"
+    "${LIBVPX_CUSTOM_INCLUDE_DIR}"
+)
+
+list(APPEND WebKit_PRIVATE_INCLUDE_DIRECTORIES
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm"
 )
 
+set(vpxutils_SOURCES
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxer.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvmuxerutil.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm/mkvmuxer/mkvwriter.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_common.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_gcc.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_msa.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_neon64.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_neon.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/compare_win.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_argb.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_from_argb.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_from.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_jpeg.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_to_argb.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/convert_to_i420.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/cpu_id.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/mjpeg_decoder.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/mjpeg_validate.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/planar_functions.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_any.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_argb.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_common.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_gcc.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_msa.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_neon64.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_neon.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/rotate_win.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_any.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_common.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_gcc.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_msa.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_neon64.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_neon.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/row_win.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_any.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_argb.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_common.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_gcc.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_msa.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_neon64.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_neon.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_rvv.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_uv.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/scale_win.cc"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/source/video_common.cc"
+)
+
+add_library(vpxutils STATIC ${vpxutils_SOURCES})
+
+target_include_directories(vpxutils PRIVATE
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libyuv/include"
+    "${THIRDPARTY_DIR}/libwebrtc/Source/third_party/libwebm"
+)
+
+target_link_libraries(WebKit PRIVATE vpxutils)
+# Playwright end
+
 list(APPEND WebProcess_SOURCES
     WebProcess/EntryPoint/win/WebProcessMain.cpp
 
diff --git a/Source/WebKit/Shared/AuxiliaryProcess.h b/Source/WebKit/Shared/AuxiliaryProcess.h
index 4510beb0b7403138abef4c9b5e892271fe8beaab..dae8f31ef187d7b086dd84d7e356839dc2811154 100644
--- a/Source/WebKit/Shared/AuxiliaryProcess.h
+++ b/Source/WebKit/Shared/AuxiliaryProcess.h
@@ -212,6 +212,11 @@ struct AuxiliaryProcessInitializationParameters {
     IPC::Connection::Identifier connectionIdentifier;
     HashMap<String, String> extraInitializationData;
     WTF::AuxiliaryProcessType processType;
+// Playwright begin
+#if !PLATFORM(COCOA)
+    bool shouldEnableSharedArrayBuffer { false };
+#endif
+// Playwright end
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/Shared/NativeWebKeyboardEvent.h b/Source/WebKit/Shared/NativeWebKeyboardEvent.h
index c72c9733800b6f836c4d3ccb0b50d40c3ee83067..e2955ddebe388d886ca43d733dce0eb58256ce8b 100644
--- a/Source/WebKit/Shared/NativeWebKeyboardEvent.h
+++ b/Source/WebKit/Shared/NativeWebKeyboardEvent.h
@@ -33,6 +33,7 @@
 #if USE(APPKIT)
 #include <wtf/RetainPtr.h>
 OBJC_CLASS NSView;
+OBJC_CLASS NSEvent;
 #endif
 
 #if PLATFORM(GTK)
@@ -70,23 +71,39 @@ public:
 #if USE(APPKIT)
     // FIXME: Share iOS's HandledByInputMethod enum here instead of passing a boolean.
     NativeWebKeyboardEvent(NSEvent *, bool handledByInputMethod, bool replacesSoftSpace, const Vector<WebCore::KeypressCommand>&);
+    NativeWebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, WallTime timestamp, Vector<WebCore::KeypressCommand>&& commands)
+        : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands))
+    {
+    }
 #elif PLATFORM(GTK)
     NativeWebKeyboardEvent(const NativeWebKeyboardEvent&);
     NativeWebKeyboardEvent(GdkEvent*, const String&, bool isAutoRepeat, Vector<String>&& commands);
     NativeWebKeyboardEvent(const String&, std::optional<Vector<WebCore::CompositionUnderline>>&&, std::optional<EditingRange>&&);
     NativeWebKeyboardEvent(WebEventType, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector<String>&& commands, bool isAutoRepeat, bool isKeypad, OptionSet<WebEventModifier>);
+    NativeWebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, WallTime timestamp, Vector<String>&& commands)
+        : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp, WTFMove(commands))
+    {
+    }
 #elif PLATFORM(IOS_FAMILY)
     enum class HandledByInputMethod : bool { No, Yes };
     NativeWebKeyboardEvent(::WebEvent *, HandledByInputMethod);
 #elif USE(LIBWPE)
     enum class HandledByInputMethod : bool { No, Yes };
     NativeWebKeyboardEvent(struct wpe_input_keyboard_event*, const String&, bool isAutoRepeat, HandledByInputMethod, std::optional<Vector<WebCore::CompositionUnderline>>&&, std::optional<EditingRange>&&);
+    NativeWebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, WallTime timestamp)
+        : WebKeyboardEvent(type, text, unmodifiedText, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, isAutoRepeat, isKeypad, isSystemKey, modifiers, timestamp)
+    {
+    }
 #if PLATFORM(WPE) && ENABLE(WPE_PLATFORM)
     NativeWebKeyboardEvent(WPEEvent*, const String&, bool isAutoRepeat);
     NativeWebKeyboardEvent(const String&, std::optional<Vector<WebCore::CompositionUnderline>>&&, std::optional<EditingRange>&&);
 #endif
 #elif PLATFORM(WIN)
     NativeWebKeyboardEvent(HWND, UINT message, WPARAM, LPARAM, Vector<MSG>&& pendingCharEvents);
+    NativeWebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> 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 e33858caab024b20217304209d7bf428e3335653..4026f6244889e5a0ee85edb72696d0be20ba531d 100644
--- a/Source/WebKit/Shared/NativeWebMouseEvent.h
+++ b/Source/WebKit/Shared/NativeWebMouseEvent.h
@@ -31,6 +31,7 @@
 #if USE(APPKIT)
 #include <wtf/RetainPtr.h>
 OBJC_CLASS NSView;
+OBJC_CLASS NSEvent;
 #endif
 
 #if PLATFORM(GTK)
@@ -86,6 +87,11 @@ public:
     NativeWebMouseEvent(HWND, UINT message, WPARAM, LPARAM, bool, float deviceScaleFactor);
 #endif
 
+#if PLATFORM(GTK) || USE(LIBWPE) || PLATFORM(WIN)
+    NativeWebMouseEvent(WebEventType type, WebMouseEventButton button, unsigned short buttons, const WebCore::IntPoint& position, const WebCore::IntPoint& globalPosition, float deltaX, float deltaY, float deltaZ, int clickCount, OptionSet<WebEventModifier> modifiers, WallTime timestamp)
+        : WebMouseEvent({type, modifiers, timestamp}, button, buttons, position, globalPosition, deltaX, deltaY, deltaZ, clickCount) { }
+#endif
+
 #if USE(APPKIT)
     NSEvent* nativeEvent() const { return m_nativeEvent.get(); }
 #elif PLATFORM(GTK)
diff --git a/Source/WebKit/Shared/NativeWebWheelEvent.h b/Source/WebKit/Shared/NativeWebWheelEvent.h
index f8e96218fd2671d1c0aca5e549efe0d8b94ef0f9..6cebd61bceb39c08e916fe991e4c3fc6f34b4704 100644
--- a/Source/WebKit/Shared/NativeWebWheelEvent.h
+++ b/Source/WebKit/Shared/NativeWebWheelEvent.h
@@ -74,7 +74,8 @@ public:
 #elif PLATFORM(WIN)
     NativeWebWheelEvent(HWND, UINT message, WPARAM, LPARAM, float deviceScaleFactor);
 #endif
-
+    NativeWebWheelEvent(const WebWheelEvent & webWheelEvent)
+        : WebWheelEvent(webWheelEvent) { }
 #if USE(APPKIT)
     NSEvent* nativeEvent() const { return m_nativeEvent.get(); }
 #elif PLATFORM(GTK)
diff --git a/Source/WebKit/Shared/Pasteboard.serialization.in b/Source/WebKit/Shared/Pasteboard.serialization.in
index ea1eb9f00feaaecf73bdddc37c904e88f43bfa85..8a631e5293a11abd650958baad4e967840a9a526 100644
--- a/Source/WebKit/Shared/Pasteboard.serialization.in
+++ b/Source/WebKit/Shared/Pasteboard.serialization.in
@@ -73,7 +73,7 @@ header: <WebCore/Pasteboard.h>
 #if PLATFORM(MAC)
     String userVisibleForm
 #endif
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
     String markup
 #endif
 };
diff --git a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
index 309c0b92bc4fbd53ba15c0f334f753a4ba5d4416..d6c03e6ff85c8107d8ba58b69572a85019dd91d9 100644
--- a/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
+++ b/Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
@@ -2769,6 +2769,9 @@ class WebCore::AuthenticationChallenge {
 class WebCore::DragData {
 #if PLATFORM(COCOA)
     String pasteboardName();
+#endif
+#if PLATFORM(WIN)
+    WebCore::DragDataMap dragDataMap();
 #endif
     WebCore::IntPoint clientPosition();
     WebCore::IntPoint globalPosition();
@@ -3567,6 +3570,7 @@ enum class WebCore::WasPrivateRelayed : bool;
     String httpStatusText;
     String httpVersion;
     WebCore::HTTPHeaderMap httpHeaderFields;
+    WebCore::HTTPHeaderMap httpRequestHeaderFields;
     std::optional<WebCore::NetworkLoadMetrics> networkLoadMetrics;
     WebCore::ResourceResponseBase::Source source;
     WebCore::ResourceResponseBase::Type type;
diff --git a/Source/WebKit/Shared/WebKeyboardEvent.cpp b/Source/WebKit/Shared/WebKeyboardEvent.cpp
index 8040819bba9dcde87311aaafe7d8177d0e07281d..24972c0a357324d27910ae6ff1979d1c6b8bc758 100644
--- a/Source/WebKit/Shared/WebKeyboardEvent.cpp
+++ b/Source/WebKit/Shared/WebKeyboardEvent.cpp
@@ -51,6 +51,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S
     ASSERT(isKeyboardEventType(type()));
 }
 
+WebKeyboardEvent::WebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, WallTime timestamp, Vector<WebCore::KeypressCommand>&& commands)
+    : WebEvent(type, modifiers, timestamp)
+    , m_text(text)
+    , m_unmodifiedText(text)
+    , m_key(key)
+    , m_code(code)
+    , m_keyIdentifier(keyIdentifier)
+    , m_windowsVirtualKeyCode(windowsVirtualKeyCode)
+    , m_nativeVirtualKeyCode(nativeVirtualKeyCode)
+    , m_macCharCode(0)
+    , m_commands(WTFMove(commands))
+    , m_isAutoRepeat(isAutoRepeat)
+    , m_isKeypad(isKeypad)
+    , m_isSystemKey(isSystemKey)
+{
+    ASSERT(isKeyboardEventType(type));
+}
+
 #elif PLATFORM(GTK)
 
 WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional<Vector<WebCore::CompositionUnderline>>&& preeditUnderlines, std::optional<EditingRange>&& preeditSelectionRange, Vector<String>&& commands, bool isAutoRepeat, bool isKeypad)
@@ -74,6 +92,24 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S
     ASSERT(isKeyboardEventType(type()));
 }
 
+WebKeyboardEvent::WebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, WallTime timestamp, Vector<String>&& commands)
+    : WebEvent(type, modifiers, timestamp)
+    , m_text(text)
+    , m_unmodifiedText(text)
+    , m_key(key)
+    , m_code(code)
+    , m_keyIdentifier(keyIdentifier)
+    , m_windowsVirtualKeyCode(windowsVirtualKeyCode)
+    , m_nativeVirtualKeyCode(nativeVirtualKeyCode)
+    , m_macCharCode(0)
+    , m_commands(WTFMove(commands))
+    , m_isAutoRepeat(isAutoRepeat)
+    , m_isKeypad(isKeypad)
+    , m_isSystemKey(isSystemKey)
+{
+    ASSERT(isKeyboardEventType(type));
+}
+
 #elif PLATFORM(IOS_FAMILY)
 
 WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey)
@@ -137,6 +173,27 @@ WebKeyboardEvent::WebKeyboardEvent(WebEvent&& event, const String& text, const S
 
 #endif
 
+#if PLATFORM(WIN) || USE(LIBWPE)
+
+WebKeyboardEvent::WebKeyboardEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, WallTime timestamp)
+    : WebEvent(type, modifiers, timestamp)
+    , m_text(text)
+    , m_unmodifiedText(text)
+    , m_key(key)
+    , m_code(code)
+    , m_keyIdentifier(keyIdentifier)
+    , m_windowsVirtualKeyCode(windowsVirtualKeyCode)
+    , m_nativeVirtualKeyCode(nativeVirtualKeyCode)
+    , m_macCharCode(0)
+    , m_isAutoRepeat(isAutoRepeat)
+    , m_isKeypad(isKeypad)
+    , m_isSystemKey(isSystemKey)
+{
+    ASSERT(isKeyboardEventType(type));
+}
+
+#endif
+
 WebKeyboardEvent::~WebKeyboardEvent()
 {
 }
diff --git a/Source/WebKit/Shared/WebKeyboardEvent.h b/Source/WebKit/Shared/WebKeyboardEvent.h
index 8e4e2d6d5ebb08fba210fe0a328d45290348dd11..32a43192ec1e918c33b1b046b71d2ec571dc92ff 100644
--- a/Source/WebKit/Shared/WebKeyboardEvent.h
+++ b/Source/WebKit/Shared/WebKeyboardEvent.h
@@ -42,14 +42,18 @@ public:
 
 #if USE(APPKIT)
     WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, const Vector<WebCore::KeypressCommand>&, bool isAutoRepeat, bool isKeypad, bool isSystemKey);
+    WebKeyboardEvent(WebEventType, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier>, WallTime timestamp, Vector<WebCore::KeypressCommand>&& commands);
 #elif PLATFORM(GTK)
     WebKeyboardEvent(WebEvent&&, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional<Vector<WebCore::CompositionUnderline>>&&, std::optional<EditingRange>&&, Vector<String>&& commands, bool isAutoRepeat, bool isKeypad);
+    WebKeyboardEvent(WebEventType, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier>, WallTime timestamp, Vector<String>&& commands);
 #elif PLATFORM(IOS_FAMILY)
     WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool handledByInputMethod, bool isAutoRepeat, bool isKeypad, bool isSystemKey);
 #elif USE(LIBWPE)
     WebKeyboardEvent(WebEvent&&, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool handledByInputMethod, std::optional<Vector<WebCore::CompositionUnderline>>&&, std::optional<EditingRange>&&, bool isAutoRepeat, bool isKeypad);
+    WebKeyboardEvent(WebEventType, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier>, WallTime timestamp);
 #else
     WebKeyboardEvent(WebEvent&&, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, int macCharCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey);
+    WebKeyboardEvent(WebEventType, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier>, WallTime timestamp);
 #endif
 
     const String& text() const { return m_text; }
diff --git a/Source/WebKit/Shared/WebMouseEvent.h b/Source/WebKit/Shared/WebMouseEvent.h
index fd4722dd38df74f259d8add02025549022a0a205..e1c33f6d766707170935b3e77e81098cc8e3786d 100644
--- a/Source/WebKit/Shared/WebMouseEvent.h
+++ b/Source/WebKit/Shared/WebMouseEvent.h
@@ -70,6 +70,7 @@ public:
 
     WebMouseEventButton button() const { return m_button; }
     unsigned short buttons() const { return m_buttons; }
+    void playwrightSetButtons(unsigned short buttons) { m_buttons = buttons; }
     const WebCore::IntPoint& position() const { return m_position; } // Relative to the view.
     void setPosition(const WebCore::IntPoint& position) { m_position = position; }
     const WebCore::IntPoint& globalPosition() const { return m_globalPosition; }
diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h
index 4fe4a84a939e46607a2871fcbdd96b1357573915..4eb0e10f4c079cf3bc7e94f6c02afd09ffe5015c 100644
--- a/Source/WebKit/Shared/WebPageCreationParameters.h
+++ b/Source/WebKit/Shared/WebPageCreationParameters.h
@@ -303,6 +303,8 @@ struct WebPageCreationParameters {
     
     bool httpsUpgradeEnabled { true };
 
+    bool shouldPauseInInspectorWhenShown { false };
+
 #if PLATFORM(IOS) || PLATFORM(VISION)
     bool allowsDeprecatedSynchronousXMLHttpRequestDuringUnload { false };
 #endif
diff --git a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in
index b819a2ee2af4b6d3e6eeabecf6ef770eaf988bbe..e43123a99d7c2fff6ea2875001631f2b52aa70c0 100644
--- a/Source/WebKit/Shared/WebPageCreationParameters.serialization.in
+++ b/Source/WebKit/Shared/WebPageCreationParameters.serialization.in
@@ -227,6 +227,8 @@ enum class WebCore::UserInterfaceLayoutDirection : bool;
 
     bool httpsUpgradeEnabled;
 
+    bool shouldPauseInInspectorWhenShown;
+
 #if PLATFORM(IOS) || PLATFORM(VISION)
     bool allowsDeprecatedSynchronousXMLHttpRequestDuringUnload;
 #endif
diff --git a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp
index 40d482a1860598391363027e63b010b3ce32b014..e654ae5e7c54b788badd463b1f2b653160d0370e 100644
--- a/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp
+++ b/Source/WebKit/Shared/glib/ProcessExecutablePathGLib.cpp
@@ -32,7 +32,7 @@
 
 namespace WebKit {
 
-#if ENABLE(DEVELOPER_MODE)
+#if TRUE
 static String getExecutablePath()
 {
     CString executablePath = FileSystem::currentExecutablePath();
@@ -44,7 +44,7 @@ static String getExecutablePath()
 
 static String findWebKitProcess(const char* processName)
 {
-#if ENABLE(DEVELOPER_MODE)
+#if TRUE
     static const char* execDirectory = g_getenv("WEBKIT_EXEC_PATH");
     if (execDirectory) {
         String processPath = FileSystem::pathByAppendingComponent(FileSystem::stringFromFileSystemRepresentation(execDirectory), StringView::fromLatin1(processName));
diff --git a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp
index 8d33ceb065fb3e90372b0c696779189d07838da0..6e3194c3e96e46bfa09f8d706324e6515df1e7f4 100644
--- a/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp
+++ b/Source/WebKit/Shared/gtk/NativeWebKeyboardEventGtk.cpp
@@ -51,12 +51,12 @@ NativeWebKeyboardEvent::NativeWebKeyboardEvent(const String& text, std::optional
 }
 
 NativeWebKeyboardEvent::NativeWebKeyboardEvent(WebEventType type, const String& text, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, Vector<String>&& commands, bool isAutoRepeat, bool isKeypad, OptionSet<WebEventModifier> modifiers)
-    : WebKeyboardEvent(WebEvent(type, modifiers, WallTime::now()), text, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, false, std::nullopt, std::nullopt, WTFMove(commands), isAutoRepeat, isKeypad)
+    : WebKeyboardEvent(WebEvent(type, modifiers, WallTime::now()), text, key, code, keyIdentifier, windowsVirtualKeyCode, nativeVirtualKeyCode, false, std::nullopt, std::nullopt, WTFMove(commands), false, isKeypad)
 {
 }
 
 NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& event)
-    : WebKeyboardEvent(WebEvent(event.type(), event.modifiers(), event.timestamp()), event.text(), event.key(), event.code(), event.keyIdentifier(), event.windowsVirtualKeyCode(), event.nativeVirtualKeyCode(), event.handledByInputMethod(), std::optional<Vector<WebCore::CompositionUnderline>>(event.preeditUnderlines()), std::optional<EditingRange>(event.preeditSelectionRange()), Vector<String>(event.commands()), event.isAutoRepeat(), event.isKeypad())
+    : WebKeyboardEvent(event)
     , m_nativeEvent(event.nativeEvent() ? constructNativeEvent(event.nativeEvent()) : nullptr)
 {
 }
diff --git a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp
index 9a1c3f09c756ea368ac2d68e183a13e2eb47ead7..01c738376230f83376d80d6d225543a3914943dd 100644
--- a/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp
+++ b/Source/WebKit/Shared/gtk/NativeWebMouseEventGtk.cpp
@@ -61,7 +61,7 @@ NativeWebMouseEvent::NativeWebMouseEvent(WebEventType type, WebMouseEventButton
 }
 
 NativeWebMouseEvent::NativeWebMouseEvent(const NativeWebMouseEvent& event)
-    : WebMouseEvent(WebEvent(event.type(), event.modifiers(), event.timestamp()), event.button(), event.buttons(), event.position(), event.globalPosition(), event.deltaX(), event.deltaY(), event.deltaZ(), event.clickCount(), 0, WebMouseEventSyntheticClickType::NoTap, event.isTouchEvent(), event.pointerId(), event.pointerType())
+    : WebMouseEvent(event)
     , m_nativeEvent(event.nativeEvent() ? constructNativeEvent(const_cast<GdkEvent*>(event.nativeEvent())) : nullptr)
 {
 }
diff --git a/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.serialization.in b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.serialization.in
new file mode 100644
index 0000000000000000000000000000000000000000..f4f09d171ebf9774b3f8744751d220d35941fcb5
--- /dev/null
+++ b/Source/WebKit/Shared/libwpe/ArgumentCodersWPE.serialization.in
@@ -0,0 +1,32 @@
+# Copyright (C) 2024 Igalia, S.L. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1.  Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+# 2.  Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in the
+#     documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+header: <WebCore/SelectionData.h>
+class WebCore::SelectionData {
+    String text()
+    String markup()
+    URL url()
+    String uriList()
+    RefPtr<WebCore::Image> image()
+    RefPtr<WebCore::SharedBuffer> customData()
+    bool canSmartReplace()
+}
diff --git a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp
index b00e6ecd0deb54eed0c2f05ba54c75a37383a90e..df085b96df4c8f5c1cb8cc25db20d019ad20f67e 100644
--- a/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp
+++ b/Source/WebKit/Shared/unix/AuxiliaryProcessMain.cpp
@@ -40,6 +40,15 @@
 
 namespace WebKit {
 
+static bool hasArgument(const char* argument, int argc, char** argv)
+{
+    for (int i = 0; i < argc; ++i) {
+        if (!strcmp(argument, argv[i]))
+            return true;
+    }
+    return false;
+}
+
 AuxiliaryProcessMainCommon::AuxiliaryProcessMainCommon()
 {
 #if ENABLE(BREAKPAD)
@@ -94,6 +103,10 @@ WTF_ALLOW_UNSAFE_BUFFER_USAGE_END
     }
 #endif
 
+// Playwright begin
+    if (hasArgument("--enable-shared-array-buffer", argc, argv))
+        m_parameters.shouldEnableSharedArrayBuffer = true;
+// Playwright end
     return true;
 }
 
diff --git a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp
index 9edb5fbcd103cd8d1b224dfd60ac88aabe9626d2..9ed392ae3809f8bda92a2765ffadc643f23fe856 100644
--- a/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp
+++ b/Source/WebKit/Shared/win/AuxiliaryProcessMainWin.cpp
@@ -41,6 +41,10 @@ bool AuxiliaryProcessMainCommon::parseCommandLine(int argc, char** argv)
             m_parameters.connectionIdentifier = IPC::Connection::Identifier { reinterpret_cast<HANDLE>(parseIntegerAllowingTrailingJunk<uint64_t>(StringView::fromLatin1(argv[++i])).value_or(0)) };
         else if (!strcmp(argv[i], "-processIdentifier") && i + 1 < argc)
             m_parameters.processIdentifier = ObjectIdentifier<WebCore::ProcessIdentifierType>(parseIntegerAllowingTrailingJunk<uint64_t>(StringView::fromLatin1(argv[++i])).value_or(0));
+// Playwright begin
+        else if (!strcmp(argv[i], "-enable-shared-array-buffer"))
+            m_parameters.shouldEnableSharedArrayBuffer = true;
+// Playwright end
         else if (!strcmp(argv[i], "-configure-jsc-for-testing"))
             JSC::Config::configureForTesting();
         else if (!strcmp(argv[i], "-disable-jit"))
diff --git a/Source/WebKit/Shared/win/WebEventFactory.cpp b/Source/WebKit/Shared/win/WebEventFactory.cpp
index a1044685ff596361f14f418a1d1f0b133dee385a..2916a6f8e0c370b860ea45106c34d8dd82547f93 100644
--- a/Source/WebKit/Shared/win/WebEventFactory.cpp
+++ b/Source/WebKit/Shared/win/WebEventFactory.cpp
@@ -484,7 +484,7 @@ WebKeyboardEvent WebEventFactory::createWebKeyboardEvent(HWND hwnd, UINT message
 #if ENABLE(TOUCH_EVENTS)
 WebTouchEvent WebEventFactory::createWebTouchEvent()
 {
-    return WebTouchEvent();
+    return WebTouchEvent({ WebEventType::TouchMove, OptionSet<WebEventModifier> { }, WallTime::now()}, { }, { }, { });
 }
 #endif // ENABLE(TOUCH_EVENTS)
 
diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt
index 3fd56653a93792ebde4b607e1f7157d5aa95b933..06108563862ca29350a62ba3ddf5186bd702706a 100644
--- a/Source/WebKit/Sources.txt
+++ b/Source/WebKit/Sources.txt
@@ -384,6 +384,7 @@ Shared/XR/XRDeviceProxy.cpp
 UIProcess/AuxiliaryProcessProxy.cpp
 UIProcess/BackgroundProcessResponsivenessTimer.cpp
 UIProcess/BrowsingContextGroup.cpp
+UIProcess/BrowserInspectorPipe.cpp
 UIProcess/DeviceIdHashSaltStorage.cpp
 UIProcess/DisplayLink.cpp
 UIProcess/DisplayLinkProcessProxyClient.cpp
@@ -393,16 +394,20 @@ UIProcess/FrameLoadState.cpp
 UIProcess/FrameProcess.cpp
 UIProcess/GeolocationPermissionRequestManagerProxy.cpp
 UIProcess/GeolocationPermissionRequestProxy.cpp
+UIProcess/InspectorDialogAgent.cpp
+UIProcess/InspectorPlaywrightAgent.cpp
 UIProcess/LegacyGlobalSettings.cpp
 UIProcess/MediaKeySystemPermissionRequestManagerProxy.cpp
 UIProcess/MediaKeySystemPermissionRequestProxy.cpp
 UIProcess/ModelElementController.cpp
 UIProcess/OverrideLanguages.cpp
 UIProcess/PageLoadState.cpp
+UIProcess/PlaywrightFullScreenManagerProxyClient.cpp
 UIProcess/ProcessAssertion.cpp
 UIProcess/ProcessThrottler.cpp
 UIProcess/ProvisionalFrameProxy.cpp
 UIProcess/ProvisionalPageProxy.cpp
+UIProcess/RemoteInspectorPipe.cpp
 UIProcess/RemotePageDrawingAreaProxy.cpp
 UIProcess/RemotePageProxy.cpp
 UIProcess/ResponsivenessTimer.cpp
@@ -444,6 +449,8 @@ UIProcess/WebOpenPanelResultListenerProxy.cpp
 UIProcess/WebPageDiagnosticLoggingClient.cpp
 UIProcess/WebPageGroup.cpp
 UIProcess/WebPageInjectedBundleClient.cpp
+UIProcess/WebPageInspectorEmulationAgent.cpp
+UIProcess/WebPageInspectorInputAgent.cpp
 UIProcess/WebPageProxy.cpp
 UIProcess/WebPageProxyMessageReceiverRegistration.cpp
 UIProcess/WebPageProxyTesting.cpp
@@ -588,7 +595,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 691526c0539d33e3bf69a84d26eb24b1f5d8202a..1e195cc3f2fa96059f3293ce3aca9ad5d1a55258 100644
--- a/Source/WebKit/SourcesCocoa.txt
+++ b/Source/WebKit/SourcesCocoa.txt
@@ -269,6 +269,7 @@ UIProcess/API/Cocoa/_WKArchiveExclusionRule.mm
 UIProcess/API/Cocoa/_WKAttachment.mm
 UIProcess/API/Cocoa/_WKAutomationSession.mm
 UIProcess/API/Cocoa/_WKAutomationSessionConfiguration.mm
+UIProcess/API/Cocoa/_WKBrowserInspector.mm
 UIProcess/API/Cocoa/_WKContentRuleListAction.mm
 UIProcess/API/Cocoa/_WKContextMenuElementInfo.mm
 UIProcess/API/Cocoa/_WKCustomHeaderFields.mm @no-unify
@@ -463,6 +464,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 d72fbeaf135545416a2997d557fd0bead76dc486..a68862ac8f44c4a54d39483af518b99071a85c0f 100644
--- a/Source/WebKit/SourcesGTK.txt
+++ b/Source/WebKit/SourcesGTK.txt
@@ -122,6 +122,7 @@ UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify
 UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify
 UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify
 UIProcess/API/glib/WebKitClipboardPermissionRequest.cpp @no-unify
+UIProcess/API/glib/WebKitBrowserInspector.cpp @no-unify
 UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify
 UIProcess/API/glib/WebKitCookieManager.cpp @no-unify
 UIProcess/API/glib/WebKitCredential.cpp @no-unify
@@ -251,6 +252,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp
 UIProcess/glib/DisplayVBlankMonitorDRM.cpp
 UIProcess/glib/DisplayVBlankMonitorTimer.cpp
 UIProcess/glib/FenceMonitor.cpp
+UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp
 UIProcess/glib/ScreenManager.cpp
 UIProcess/glib/SystemSettingsManagerProxy.cpp
 UIProcess/glib/WebPageProxyGLib.cpp
@@ -269,6 +271,7 @@ UIProcess/gtk/DisplayX11.cpp @no-unify
 UIProcess/gtk/DisplayWayland.cpp @no-unify
 UIProcess/gtk/WebDateTimePickerGtk.cpp
 UIProcess/gtk/HardwareAccelerationManager.cpp
+UIProcess/gtk/InspectorTargetProxyGtk.cpp
 UIProcess/gtk/KeyBindingTranslator.cpp
 UIProcess/gtk/PointerLockManager.cpp @no-unify
 UIProcess/gtk/PointerLockManagerWayland.cpp @no-unify
@@ -282,6 +285,8 @@ UIProcess/gtk/ViewGestureControllerGtk.cpp
 UIProcess/gtk/WebColorPickerGtk.cpp
 UIProcess/gtk/WebContextMenuProxyGtk.cpp
 UIProcess/gtk/WebDataListSuggestionsDropdownGtk.cpp
+UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp
+UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp
 UIProcess/gtk/WebPageProxyGtk.cpp @no-unify
 UIProcess/gtk/WebPasteboardProxyGtk.cpp
 UIProcess/gtk/WebPopupMenuProxyGtk.cpp
diff --git a/Source/WebKit/SourcesWPE.txt b/Source/WebKit/SourcesWPE.txt
index f655188213595d7e990faa208258486a8e721bb1..88f81226b302ea9b190b3d72576992746531a882 100644
--- a/Source/WebKit/SourcesWPE.txt
+++ b/Source/WebKit/SourcesWPE.txt
@@ -124,6 +124,7 @@ UIProcess/API/glib/WebKitAuthenticationRequest.cpp @no-unify
 UIProcess/API/glib/WebKitAutomationSession.cpp @no-unify
 UIProcess/API/glib/WebKitBackForwardList.cpp @no-unify
 UIProcess/API/glib/WebKitBackForwardListItem.cpp @no-unify
+UIProcess/API/glib/WebKitBrowserInspector.cpp @no-unify
 UIProcess/API/glib/WebKitContextMenuClient.cpp @no-unify
 UIProcess/API/glib/WebKitCookieManager.cpp @no-unify
 UIProcess/API/glib/WebKitCredential.cpp @no-unify
@@ -157,6 +158,7 @@ UIProcess/API/glib/WebKitOptionMenu.cpp @no-unify
 UIProcess/API/glib/WebKitOptionMenuItem.cpp @no-unify
 UIProcess/API/glib/WebKitPermissionRequest.cpp @no-unify
 UIProcess/API/glib/WebKitPermissionStateQuery.cpp @no-unify
+UIProcess/API/glib/WebKitPointerLockPermissionRequest.cpp @no-unify
 UIProcess/API/glib/WebKitPolicyDecision.cpp @no-unify
 UIProcess/API/glib/WebKitPrivate.cpp @no-unify
 UIProcess/API/glib/WebKitProtocolHandler.cpp @no-unify
@@ -193,6 +195,7 @@ UIProcess/API/soup/HTTPCookieStoreSoup.cpp
 UIProcess/API/wpe/InputMethodFilterWPE.cpp @no-unify
 UIProcess/API/wpe/PageClientImpl.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/WebKitInputMethodContextImplWPE.cpp @no-unify
 UIProcess/API/wpe/WebKitPopupMenu.cpp @no-unify
@@ -221,6 +224,7 @@ UIProcess/glib/DisplayVBlankMonitor.cpp
 UIProcess/glib/DisplayVBlankMonitorDRM.cpp
 UIProcess/glib/DisplayVBlankMonitorTimer.cpp
 UIProcess/glib/FenceMonitor.cpp
+UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp
 UIProcess/glib/ScreenManager.cpp
 UIProcess/glib/SystemSettingsManagerProxy.cpp
 UIProcess/glib/WebPageProxyGLib.cpp
@@ -254,8 +258,13 @@ UIProcess/linux/MemoryPressureMonitor.cpp
 UIProcess/soup/WebProcessPoolSoup.cpp
 
 UIProcess/wpe/AcceleratedBackingStoreDMABuf.cpp
+UIProcess/wpe/InspectorTargetProxyWPE.cpp
 UIProcess/wpe/ScreenManagerWPE.cpp
 UIProcess/wpe/SystemSettingsManagerProxyWPE.cpp
+UIProcess/wpe/WebColorPickerWPE.cpp
+UIProcess/wpe/WebDateTimePickerWPE.cpp
+UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp
+UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp
 UIProcess/wpe/WebPageProxyWPE.cpp
 UIProcess/wpe/WebPreferencesWPE.cpp
 
@@ -282,6 +291,8 @@ WebProcess/WebCoreSupport/glib/WebEditorClientGLib.cpp
 
 WebProcess/WebCoreSupport/soup/WebFrameNetworkingContext.cpp
 
+WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp
+
 WebProcess/WebCoreSupport/wpe/WebEditorClientWPE.cpp
 
 WebProcess/WebPage/AcceleratedSurface.cpp
diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp
index c1a03ab72d496d65b1036a7227ad0e23d896f89f..a17ffd445f3070e579aa11fac24dca881585903b 100644
--- a/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp
+++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.cpp
@@ -255,6 +255,11 @@ WebPageProxy* PageConfiguration::relatedPage() const
     return m_data.relatedPage.get();
 }
 
+WebKit::WebPageProxy* PageConfiguration::openerPageForInspector() const
+{
+    return m_data.openerPageForInspector.get();
+}
+
 WebPageProxy* PageConfiguration::pageToCloneSessionStorageFrom() const
 {
     return m_data.pageToCloneSessionStorageFrom.get();
diff --git a/Source/WebKit/UIProcess/API/APIPageConfiguration.h b/Source/WebKit/UIProcess/API/APIPageConfiguration.h
index 8e7d7abc63f5740a0ad05c811470bd476219c93f..0c16acfa885b2d648c58ebf14f2babd5547d6571 100644
--- a/Source/WebKit/UIProcess/API/APIPageConfiguration.h
+++ b/Source/WebKit/UIProcess/API/APIPageConfiguration.h
@@ -155,6 +155,10 @@ public:
     WebKit::WebPageProxy* relatedPage() const;
     void setRelatedPage(WeakPtr<WebKit::WebPageProxy>&& relatedPage) { m_data.relatedPage = WTFMove(relatedPage); }
 
+    // This is similar to relatedPage(), but it is also set for noopener links.
+    WebKit::WebPageProxy* openerPageForInspector() const;
+    void setOpenerPageForInspector(WeakPtr<WebKit::WebPageProxy>&& openerPageForInspector) { m_data.openerPageForInspector = WTFMove(openerPageForInspector); }
+
     WebKit::WebPageProxy* pageToCloneSessionStorageFrom() const;
     void setPageToCloneSessionStorageFrom(WeakPtr<WebKit::WebPageProxy>&&);
 
@@ -510,6 +514,7 @@ private:
 #endif
         RefPtr<WebKit::WebPageGroup> pageGroup;
         WeakPtr<WebKit::WebPageProxy> relatedPage;
+        WeakPtr<WebKit::WebPageProxy> openerPageForInspector;
         std::optional<OpenerInfo> openerInfo;
         WebCore::Site openedSite;
         WTF::String openedMainFrameName;
diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp
index a08bd7c99393d04b0b377e404196bc2fda008038..9943de5d16474cf9a506f7c2b0daf555abdfc9cf 100644
--- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp
+++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp
@@ -52,6 +52,10 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy()
     copy->m_ignoreSynchronousMessagingTimeoutsForTesting = this->m_ignoreSynchronousMessagingTimeoutsForTesting;
     copy->m_attrStyleEnabled = this->m_attrStyleEnabled;
     copy->m_shouldThrowExceptionForGlobalConstantRedeclaration = this->m_shouldThrowExceptionForGlobalConstantRedeclaration;
+#if PLATFORM(MAC)
+    copy->m_forceOverlayScrollbars = this->m_forceOverlayScrollbars;
+#endif
+    copy->m_overrideLanguages = this->m_overrideLanguages; /* playwright revert fb205fb */
     copy->m_alwaysRunsAtBackgroundPriority = this->m_alwaysRunsAtBackgroundPriority;
     copy->m_shouldTakeUIBackgroundAssertion = this->m_shouldTakeUIBackgroundAssertion;
     copy->m_shouldCaptureDisplayInUIProcess = this->m_shouldCaptureDisplayInUIProcess;
diff --git a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h
index 1dd06677f5b6712abce52103c0209ef46a25ed77..869c2a1eec2797cd7fabee4ed7949cefb47ca361 100644
--- a/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h
+++ b/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h
@@ -96,6 +96,16 @@ public:
     bool shouldThrowExceptionForGlobalConstantRedeclaration() const { return m_shouldThrowExceptionForGlobalConstantRedeclaration; }
     void setShouldThrowExceptionForGlobalConstantRedeclaration(bool shouldThrow) { m_shouldThrowExceptionForGlobalConstantRedeclaration = shouldThrow; }
     
+#if PLATFORM(MAC)
+    bool forceOverlayScrollbars() const { return m_forceOverlayScrollbars; }
+    void setForceOverlayScrollbars(bool forceOverlayScrollbars) { m_forceOverlayScrollbars = forceOverlayScrollbars; }
+#endif
+
+    /* playwright revert fb205fb */
+    const Vector<WTF::String>& overrideLanguages() const { return m_overrideLanguages; }
+    void setOverrideLanguages(Vector<WTF::String>&& languages) { m_overrideLanguages = WTFMove(languages); }
+    /* end playwright revert fb205fb */
+
     bool alwaysRunsAtBackgroundPriority() const { return m_alwaysRunsAtBackgroundPriority; }
     void setAlwaysRunsAtBackgroundPriority(bool alwaysRunsAtBackgroundPriority) { m_alwaysRunsAtBackgroundPriority = alwaysRunsAtBackgroundPriority; }
 
@@ -178,6 +188,10 @@ private:
     bool m_ignoreSynchronousMessagingTimeoutsForTesting { false };
     bool m_attrStyleEnabled { false };
     bool m_shouldThrowExceptionForGlobalConstantRedeclaration { true };
+#if PLATFORM(MAC)
+    bool m_forceOverlayScrollbars { false };
+#endif
+    Vector<WTF::String> m_overrideLanguages; /* playwright revert fb205fb */
     bool m_alwaysRunsAtBackgroundPriority { false };
     bool m_shouldTakeUIBackgroundAssertion { true };
     bool m_shouldCaptureDisplayInUIProcess { DEFAULT_CAPTURE_DISPLAY_IN_UI_PROCESS };
diff --git a/Source/WebKit/UIProcess/API/APIUIClient.h b/Source/WebKit/UIProcess/API/APIUIClient.h
index f7d8880ba2c010245a69e779f5a3d11f6af6b4e0..4ed7b422d72c8814aec0f1d9cbcf466dc464fe17 100644
--- a/Source/WebKit/UIProcess/API/APIUIClient.h
+++ b/Source/WebKit/UIProcess/API/APIUIClient.h
@@ -116,6 +116,7 @@ public:
     virtual void runJavaScriptAlert(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function<void()>&& completionHandler) { completionHandler(); }
     virtual void runJavaScriptConfirm(WebKit::WebPageProxy&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function<void(bool)>&& completionHandler) { completionHandler(false); }
     virtual void runJavaScriptPrompt(WebKit::WebPageProxy&, const WTF::String&, const WTF::String&, WebKit::WebFrameProxy*, WebKit::FrameInfoData&&, Function<void(const WTF::String&)>&& 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<WebKit::WebEventModifier>, Object*) { }
diff --git a/Source/WebKit/UIProcess/API/C/WKInspector.cpp b/Source/WebKit/UIProcess/API/C/WKInspector.cpp
index 8ecba5bacfa39f9f5309a127e2c0aed527373a04..0873b91211c89b9cddab9ed74120c0b77e4c6aec 100644
--- a/Source/WebKit/UIProcess/API/C/WKInspector.cpp
+++ b/Source/WebKit/UIProcess/API/C/WKInspector.cpp
@@ -28,6 +28,11 @@
 
 #if !PLATFORM(IOS_FAMILY)
 
+#if PLATFORM(WIN)
+#include "BrowserInspectorPipe.h"
+#include "InspectorPlaywrightAgentClientWin.h"
+#endif
+
 #include "WKAPICast.h"
 #include "WebFrameProxy.h"
 #include "WebInspectorUIProxy.h"
@@ -131,4 +136,11 @@ void WKInspectorToggleElementSelection(WKInspectorRef inspectorRef)
     toImpl(inspectorRef)->toggleElementSelection();
 }
 
+void WKInspectorInitializeRemoteInspectorPipe(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit)
+{
+#if PLATFORM(WIN)
+    initializeBrowserInspectorPipe(makeUnique<InspectorPlaywrightAgentClientWin>(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 048cd54f4b349d48d023f5532e4606f96340bfc2..562ad6fc0cfc3a7082ef19ab2bf592718bb16fa6 100644
--- a/Source/WebKit/UIProcess/API/C/WKPage.cpp
+++ b/Source/WebKit/UIProcess/API/C/WKPage.cpp
@@ -1800,6 +1800,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)
@@ -1829,6 +1836,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 1484f064ec89ee8c25c35df9f0a4462896699415..0622f4d5fc9144b9059395d9d0730a4ae00b7497 100644
--- a/Source/WebKit/UIProcess/API/C/WKPageUIClient.h
+++ b/Source/WebKit/UIProcess/API/C/WKPageUIClient.h
@@ -98,6 +98,7 @@ typedef void (*WKPageRunBeforeUnloadConfirmPanelCallback)(WKPageRef page, WKStri
 typedef void (*WKPageRunJavaScriptAlertCallback)(WKPageRef page, WKStringRef alertText, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptAlertResultListenerRef listener, const void *clientInfo);
 typedef void (*WKPageRunJavaScriptConfirmCallback)(WKPageRef page, WKStringRef message, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptConfirmResultListenerRef listener, const void *clientInfo);
 typedef void (*WKPageRunJavaScriptPromptCallback)(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, WKSecurityOriginRef securityOrigin, WKPageRunJavaScriptPromptResultListenerRef listener, const void *clientInfo);
+typedef void (*WKPageHandleJavaScriptDialogCallback)(WKPageRef page, bool accept, WKStringRef value, const void *clientInfo);
 typedef void (*WKPageRequestStorageAccessConfirmCallback)(WKPageRef page, WKFrameRef frame, WKStringRef requestingDomain, WKStringRef currentDomain, WKPageRequestStorageAccessConfirmResultListenerRef listener, const void *clientInfo);
 typedef void (*WKPageTakeFocusCallback)(WKPageRef page, WKFocusDirection direction, const void *clientInfo);
 typedef void (*WKPageFocusCallback)(WKPageRef page, const void *clientInfo);
@@ -1364,6 +1365,7 @@ typedef struct WKPageUIClientV14 {
 
     // Version 14.
     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+    WKPageHandleJavaScriptDialogCallback                                handleJavaScriptDialog;
 } WKPageUIClientV14;
 
 typedef struct WKPageUIClientV15 {
@@ -1471,6 +1473,7 @@ typedef struct WKPageUIClientV15 {
 
     // Version 14.
     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+    WKPageHandleJavaScriptDialogCallback                                handleJavaScriptDialog;
 
     // Version 15.
     WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
@@ -1582,6 +1585,7 @@ typedef struct WKPageUIClientV16 {
 
     // Version 14.
     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+    WKPageHandleJavaScriptDialogCallback                                handleJavaScriptDialog;
 
     // Version 15.
     WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
@@ -1696,6 +1700,7 @@ typedef struct WKPageUIClientV17 {
 
     // Version 14.
     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+    WKPageHandleJavaScriptDialogCallback                                handleJavaScriptDialog;
 
     // Version 15.
     WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
@@ -1810,6 +1815,7 @@ typedef struct WKPageUIClientV18 {
 
     // Version 14.
     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+    WKPageHandleJavaScriptDialogCallback                                handleJavaScriptDialog;
 
     // Version 15.
     WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
@@ -1926,6 +1932,7 @@ typedef struct WKPageUIClientV19 {
 
     // Version 14.
     WKPageRunWebAuthenticationPanelCallback                             runWebAuthenticationPanel;
+    WKPageHandleJavaScriptDialogCallback                                handleJavaScriptDialog;
 
     // Version 15.
     WKPageDecidePolicyForSpeechRecognitionPermissionRequestCallback     decidePolicyForSpeechRecognitionPermissionRequest;
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm
index 6625fbd43fe223d7be556283e43abd70bb664d5b..9bbd46a892af196c32636d622d959aef1b6d14b3 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferences.mm
@@ -697,6 +697,16 @@ - (void)_setMediaCaptureRequiresSecureConnection:(BOOL)requiresSecureConnection
     _preferences->setMediaCaptureRequiresSecureConnection(requiresSecureConnection);
 }
 
+- (BOOL)_alternateWebMPlayerEnabled
+{
+    return _preferences->alternateWebMPlayerEnabled();
+}
+
+- (void)_setAlternateWebMPlayerEnabled:(BOOL)enabled
+{
+    _preferences->setAlternateWebMPlayerEnabled(enabled);
+}
+
 - (double)_inactiveMediaCaptureStreamRepromptIntervalInMinutes
 {
     return _preferences->inactiveMediaCaptureStreamRepromptIntervalInMinutes();
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h
index 07f25e73846777573709a8091fab19fe576e4282..e194073bc1a0dac8f2e2bf25f430c8624f2cb932 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKPreferencesPrivate.h
@@ -119,6 +119,7 @@ typedef NS_ENUM(NSInteger, _WKPitchCorrectionAlgorithm) {
 @property (nonatomic, setter=_setMockCaptureDevicesEnabled:) BOOL _mockCaptureDevicesEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0));
 @property (nonatomic, setter=_setMockCaptureDevicesPromptEnabled:) BOOL _mockCaptureDevicesPromptEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
 @property (nonatomic, setter=_setMediaCaptureRequiresSecureConnection:) BOOL _mediaCaptureRequiresSecureConnection WK_API_AVAILABLE(macos(10.13), ios(11.0));
+@property (nonatomic, setter=_setAlternateWebMPlayerEnabled:) BOOL _alternateWebMPlayerEnabled WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 @property (nonatomic, setter=_setEnumeratingAllNetworkInterfacesEnabled:) BOOL _enumeratingAllNetworkInterfacesEnabled WK_API_AVAILABLE(macos(10.13), ios(11.0));
 @property (nonatomic, setter=_setICECandidateFilteringEnabled:) BOOL _iceCandidateFilteringEnabled WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
 @property (nonatomic, setter=_setInactiveMediaCaptureStreamRepromptIntervalInMinutes:) double _inactiveMediaCaptureStreamRepromptIntervalInMinutes WK_API_AVAILABLE(macos(10.13.4), ios(11.3));
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h
index 11fd07547370723575352866358867b5dddb8a61..8d59d73717325a92e3eb892384daf35d8eb3fb17 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h
@@ -149,6 +149,12 @@ WK_SWIFT_UI_ACTOR
  */
 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(WK_SWIFT_UI_ACTOR void (^)(NSString * _Nullable result))completionHandler;
 
+/*! @abstract Handle a JavaScript dialog.
+ @param webView The web view invoking the delegate method.
+ @param accept Whether to accept the dialog.
+ @param value Value to use for prompt dialog.
+ */
+- (void)webView:(WKWebView *)webView handleJavaScriptDialog:(BOOL)accept value:(nullable NSString *)value;
 
 /*! @abstract A delegate to request permission for microphone audio and camera video access.
  @param webView The web view invoking the delegate method.
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h
index eff4cf557033561ab20762d93a58c2d71f5505f0..9418e2c51e50190dee2b5d7c854eacea8c5a4b76 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.h
@@ -126,6 +126,8 @@ WK_CLASS_AVAILABLE(macos(10.11), ios(9.0))
 #endif
 #endif
 
+- (uint64_t)sessionID;
+
 @end
 
 NS_ASSUME_NONNULL_END
diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm
index 233c902323f43300cbe7a4a0a02f6afdb8c9dc1c..5484a2101a984612c1bde529250ad75c3ebcdfd2 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm
@@ -55,6 +55,7 @@
 #import "_WKWebPushActionInternal.h"
 #import "_WKWebsiteDataStoreConfigurationInternal.h"
 #import "_WKWebsiteDataStoreDelegate.h"
+#import <pal/SessionID.h>
 #import <WebCore/Credential.h>
 #import <WebCore/RegistrableDomain.h>
 #import <WebCore/ResourceResponse.h>
@@ -493,6 +494,11 @@ - (void)removeDataOfTypes:(NSSet *)dataTypes modifiedSince:(NSDate *)date comple
     });
 }
 
+- (uint64_t) sessionID
+{
+    return _websiteDataStore->sessionID().toUInt64();
+}
+
 static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecords)
 {
     Vector<WebKit::WebsiteDataRecord> 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 <WebKit/WKFoundation.h>
+#import <WebKit/WKProcessPool.h>
+#import <WebKit/WKWebsiteDataStore.h>
+#import <Foundation/Foundation.h>
+
+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 <NSObject>
+- (WKWebView *)createNewPage:(uint64_t)sessionID;
+- (_WKBrowserContext *)createBrowserContext:(NSString *)proxyServer WithBypassList:(NSString *)proxyBypassList;
+- (void)deleteBrowserContext:(uint64_t)sessionID;
+- (void)quit;
+@end
+
+WK_CLASS_AVAILABLE(macos(10.14.0))
+@interface _WKBrowserInspector : NSObject
++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate headless:(BOOL)headless;
+@end
+
+
+NS_ASSUME_NONNULL_END
+
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm
new file mode 100644
index 0000000000000000000000000000000000000000..69eb9c6aa30beb8ea21a0ef647e463043a868ab8
--- /dev/null
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKBrowserInspector.mm
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "_WKBrowserInspector.h"
+
+#include "BrowserInspectorPipe.h"
+#include "InspectorPlaywrightAgentClientMac.h"
+#include "PageClientImplMac.h"
+#include "WebKit2Initialize.h"
+
+#import "WKWebView.h"
+
+using namespace WebKit;
+
+@implementation _WKBrowserInspector
+
++ (void)initializeRemoteInspectorPipe:(id<_WKBrowserInspectorDelegate>)delegate headless:(BOOL)headless
+{
+#if ENABLE(REMOTE_INSPECTOR)
+    InitializeWebKit2();
+    PageClientImpl::setHeadless(headless);
+    initializeBrowserInspectorPipe(makeUnique<InspectorPlaywrightAgentClientMac>(delegate, headless));
+#endif
+}
+
+@end
+
+@implementation _WKBrowserContext
+- (void)dealloc
+{
+    [_dataStore release];
+    [_processPool release];
+    _dataStore = nil;
+    _processPool = nil;
+    [super dealloc];
+}
+@end
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h
index 6b3a806a282b8de4af64b0db7d04215a4321c924..f437ed7c7c6c1492f110141861aa7feeb8096246 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h
@@ -67,6 +67,7 @@ WK_CLASS_AVAILABLE(macos(10.10), ios(8.0))
 @property (nonatomic) pid_t presentingApplicationPID WK_API_AVAILABLE(macos(10.13), ios(11.0));
 @property (nonatomic) audit_token_t presentingApplicationProcessToken WK_API_AVAILABLE(macos(10.13), ios(11.3));
 @property (nonatomic) BOOL processSwapsOnNavigation WK_API_AVAILABLE(macos(10.14), ios(12.0));
+@property (nonatomic) BOOL forceOverlayScrollbars WK_API_AVAILABLE(macos(10.14));
 @property (nonatomic) BOOL alwaysKeepAndReuseSwappedProcesses WK_API_AVAILABLE(macos(10.14), ios(12.0));
 @property (nonatomic) BOOL processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol WK_API_AVAILABLE(macos(12.0), ios(15.0));
 @property (nonatomic) BOOL prewarmsProcessesAutomatically WK_API_AVAILABLE(macos(10.14.4), ios(12.2));
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm
index 56d52f9a7c6a893b598daacbfa6d491a7ed22460..83fee0d877594f20eade4b963c1fff08171838e7 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm
@@ -241,6 +241,16 @@ - (BOOL)processSwapsOnNavigation
     return _processPoolConfiguration->processSwapsOnNavigation();
 }
 
+- (void)setForceOverlayScrollbars:(BOOL)force
+{
+    _processPoolConfiguration->setForceOverlayScrollbars(force);
+}
+
+- (BOOL)forceOverlayScrollbars
+{
+    return _processPoolConfiguration->forceOverlayScrollbars();
+}
+
 - (void)setPrewarmsProcessesAutomatically:(BOOL)prewarms
 {
     _processPoolConfiguration->setIsAutomaticProcessWarmingEnabled(prewarms);
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h
index 4974e14214e2bb3e982325b885bab33e54f83998..cacdf8c71fab248d38d2faf03f7affdcfed1ef62 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKUserStyleSheet.h
@@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
 @class _WKUserContentWorld;
 @class WKContentWorld;
 @class WKWebView;
+@class WKContentWorld;
 
 typedef NS_ENUM(NSInteger, _WKUserStyleLevel) {
     _WKUserStyleUserLevel,
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm
index 0a6086b000eb61013e49ce0c1cc5a26ec275bdc2..261bb8828df3e282fd6c4a2fa8ec8684342465a2 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushDaemonConnection.mm
@@ -32,6 +32,7 @@
 #import "WKSecurityOriginInternal.h"
 #import "WebPushDaemonConnectionConfiguration.h"
 #import "_WKNotificationDataInternal.h"
+#import "_WKWebPushMessageInternal.h"
 #import "_WKWebPushSubscriptionDataInternal.h"
 #import <WebCore/ExceptionData.h>
 #import <WebCore/PushPermissionState.h>
diff --git a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm
index 0a78daba00961bf10564a0b53067960b71d8b61d..696408b77c82e205a134edf2ee17ff971af226f3 100644
--- a/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm
+++ b/Source/WebKit/UIProcess/API/Cocoa/_WKWebPushSubscriptionData.mm
@@ -28,6 +28,9 @@
 #import <WebCore/WebCoreObjCExtras.h>
 #import <wtf/cocoa/SpanCocoa.h>
 
+#import <WebCore/WebCoreObjCExtras.h>
+#import <wtf/cocoa/SpanCocoa.h>
+
 @implementation _WKWebPushSubscriptionData
 
 - (void)dealloc
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..575245fc1f279a75f7e74c26652cf772a2fc95b7
--- /dev/null
+++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspector.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebKitBrowserInspector.h"
+
+#include "BrowserInspectorPipe.h"
+#include "InspectorPlaywrightAgentClientGLib.h"
+#include "WebKitBrowserInspectorPrivate.h"
+#include "WebKitWebViewPrivate.h"
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/glib/WTFGType.h>
+
+/**
+ * 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<WebKitBrowserInspector> 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<WebKit::InspectorPlaywrightAgentClientGlib>(String::fromUTF8(defaultProxyURI), ignoreHosts));
+}
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h
new file mode 100644
index 0000000000000000000000000000000000000000..e0b1da48465c850f541532ed961d1b778bea6028
--- /dev/null
+++ b/Source/WebKit/UIProcess/API/glib/WebKitBrowserInspectorPrivate.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebKitBrowserInspector.h"
+#include "WebPageProxy.h"
+
+WebKit::WebPageProxy* webkitBrowserInspectorCreateNewPageInContext(WebKitWebContext*);
+void webkitBrowserInspectorQuitApplication();
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp
index 9b6d8db85df969e609de036fac67374226ecd48e..2b293d5f24e562f06859432580f2cdfe40f8b9a6 100644
--- a/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp
+++ b/Source/WebKit/UIProcess/API/glib/WebKitUIClient.cpp
@@ -101,6 +101,10 @@ private:
         page.makeViewBlankIfUnpaintedSinceLastLoadCommit();
         webkitWebViewRunJavaScriptPrompt(m_webView, message.utf8(), defaultValue.utf8(), WTFMove(completionHandler));
     }
+    void handleJavaScriptDialog(WebPageProxy&, bool accept, const String& value) final
+    {
+        webkitWebViewHandleJavaScriptDialog(m_webView, accept, value);
+    }
 
     bool canRunBeforeUnloadConfirmPanel() const final { return true; }
 
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp
index 49d382e0d469ca081754255feb71a70fca6acb13..2a5532502d0c34f1ad5e5d393ec12f52ad68ff7c 100644
--- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp
+++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp
@@ -422,10 +422,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<char> bundleFilename(g_build_filename(injectedBundleDirectory(), INJECTED_BUNDLE_FILENAME, nullptr));
 
     WebKitWebContext* webContext = WEBKIT_WEB_CONTEXT(object);
@@ -484,6 +493,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;
@@ -945,6 +956,11 @@ WebKitNetworkSession* webkit_web_context_get_network_session_for_automation(WebK
     return nullptr;
 #endif
 }
+
+void webkit_web_context_set_network_session_for_automation(WebKitWebContext* context, WebKitNetworkSession* session)
+{
+    context->priv->automationNetworkSession = session;
+}
 #endif
 /**
  * webkit_web_context_set_cache_model:
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in
index 15fe3e8e5652147ba54af266eda66b3962c074b9..d463fa78af375badb239c890da50ba1125e19de8 100644
--- a/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in
+++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in
@@ -161,6 +161,10 @@ webkit_web_context_set_automation_allowed           (WebKitWebContext
 #if ENABLE(2022_GLIB_API)
 WEBKIT_API WebKitNetworkSession *
 webkit_web_context_get_network_session_for_automation(WebKitWebContext             *context);
+
+WEBKIT_API void
+webkit_web_context_set_network_session_for_automation(WebKitWebContext             *context,
+                                                      WebKitNetworkSession          *session);
 #endif
 
 WEBKIT_API void
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h
index c1945fbe717a42afc1f51d64a80c7de3fa9009ba..ab63fe19b00ecbd64c9421e6eecad3e25cbb2361 100644
--- a/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h
+++ b/Source/WebKit/UIProcess/API/glib/WebKitWebContextPrivate.h
@@ -43,3 +43,4 @@ void webkitWebContextInitializeNotificationPermissions(WebKitWebContext*);
 #if ENABLE(REMOTE_INSPECTOR)
 void webkitWebContextWillCloseAutomationSession(WebKitWebContext*);
 #endif
+int webkitWebContextExistingCount();
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp
index 8fcb4462e8f0f25dc07498e3e62e36ca21e04d9c..9470855f7b233049b1b3b10ee1a47690f502a8eb 100644
--- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp
+++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp
@@ -35,6 +35,7 @@
 #include "WebContextMenuItem.h"
 #include "WebContextMenuItemData.h"
 #include "WebFrameProxy.h"
+#include "WebPageInspectorController.h"
 #include "WebKitAuthenticationRequestPrivate.h"
 #include "WebKitBackForwardListPrivate.h"
 #include "WebKitContextMenuClient.h"
@@ -148,6 +149,7 @@ enum {
     CLOSE,
 
     SCRIPT_DIALOG,
+    SCRIPT_DIALOG_HANDLED,
 
     DECIDE_POLICY,
     PERMISSION_REQUEST,
@@ -516,6 +518,16 @@ GRefPtr<WebKitOptionMenu> WebKitWebViewClient::showOptionMenu(WebKitPopupMenu& p
 
 void WebKitWebViewClient::frameDisplayed(WKWPE::View&)
 {
+
+#if USE(SKIA)
+    sk_sp<SkImage> surface(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get()));
+    if (surface)
+        getPage(m_webView).inspectorController().didPaint(WTFMove(surface));
+#elif USE(CAIRO)
+    if (RefPtr<cairo_surface_t> surface = adoptRef(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get())))
+        getPage(m_webView).inspectorController().didPaint(surface.get());
+#endif
+
     {
         SetForScope inFrameDisplayedGuard(m_webView->priv->inFrameDisplayed, true);
         for (const auto& callback : m_webView->priv->frameDisplayedCallbacks) {
@@ -532,6 +544,18 @@ void WebKitWebViewClient::frameDisplayed(WKWPE::View&)
     }
 }
 
+#if USE(SKIA)
+sk_sp<SkImage> WebKitWebViewClient::takeViewScreenshot()
+{
+    return sk_sp<SkImage>(webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get()));
+}
+#elif USE(CAIRO)
+cairo_surface_t* WebKitWebViewClient::takeViewScreenshot()
+{
+    return webkitWebViewBackendTakeScreenshot(m_webView->priv->backend.get());
+}
+#endif
+
 void WebKitWebViewClient::willStartLoad(WKWPE::View&)
 {
     webkitWebViewWillStartLoad(m_webView);
@@ -618,7 +642,7 @@ static gboolean webkitWebViewDecidePolicy(WebKitWebView*, WebKitPolicyDecision*
 
 static gboolean webkitWebViewPermissionRequest(WebKitWebView*, WebKitPermissionRequest* request)
 {
-#if ENABLE(POINTER_LOCK)
+#if ENABLE(POINTER_LOCK) && PLATFORM(GTK)
     if (WEBKIT_IS_POINTER_LOCK_PERMISSION_REQUEST(request)) {
         webkit_permission_request_allow(request);
         return TRUE;
@@ -941,6 +965,10 @@ static void webkitWebViewConstructed(GObject* object)
         priv->websitePolicies = adoptGRef(webkit_website_policies_new());
 
     Ref configuration = priv->relatedView && priv->relatedView->priv->configurationForNextRelatedView ? priv->relatedView->priv->configurationForNextRelatedView.releaseNonNull() : webkitWebViewCreatePageConfiguration(webView);
+
+    // Playwright: REGRESSION(278896@main): Need to preserve configuration's preferences.
+    configuration->setPreferences(webkitSettingsGetPreferences(priv->settings.get()));
+
     webkitWebViewCreatePage(webView, WTFMove(configuration));
     webkitWebContextWebViewCreated(priv->context.get(), webView);
 
@@ -1980,6 +2008,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
@@ -2765,6 +2802,23 @@ void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView* webView, const
     webkit_script_dialog_unref(webView->priv->currentScriptDialog);
 }
 
+void webkitWebViewHandleJavaScriptDialog(WebKitWebView* webView, bool accept, const String& value) {
+    auto* dialog = webView->priv->currentScriptDialog;
+#if PLATFORM(WPE)
+    dialog->isUserHandled = false;
+#endif
+    webkit_script_dialog_ref(dialog);
+    if (!value.isNull())
+        webkitWebViewSetCurrentScriptDialogUserInput(webView, value);
+    if (accept)
+        webkitWebViewAcceptCurrentScriptDialog(webView);
+    else
+        webkitWebViewDismissCurrentScriptDialog(webView);
+    gboolean returnValue;
+    g_signal_emit(webView, signals[SCRIPT_DIALOG_HANDLED], 0, dialog, &returnValue);
+    webkit_script_dialog_unref(dialog);
+}
+
 bool webkitWebViewIsShowingScriptDialog(WebKitWebView* webView)
 {
     if (!webView->priv->currentScriptDialog)
diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h
index bf5b4c2bcca722e4d008f12194344c29c0db8824..ee6ee6b476ac28dee3a5983d03ba89ad0c9eb9ff 100644
--- a/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h
+++ b/Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h
@@ -64,6 +64,7 @@ void webkitWebViewRunJavaScriptAlert(WebKitWebView*, const CString& message, Fun
 void webkitWebViewRunJavaScriptConfirm(WebKitWebView*, const CString& message, Function<void(bool)>&& completionHandler);
 void webkitWebViewRunJavaScriptPrompt(WebKitWebView*, const CString& message, const CString& defaultText, Function<void(const String&)>&& completionHandler);
 void webkitWebViewRunJavaScriptBeforeUnloadConfirm(WebKitWebView*, const CString& message, Function<void(bool)>&& completionHandler);
+void webkitWebViewHandleJavaScriptDialog(WebKitWebView*, bool accept, const String& value);
 bool webkitWebViewIsShowingScriptDialog(WebKitWebView*);
 bool webkitWebViewIsScriptDialogRunning(WebKitWebView*, WebKitScriptDialog*);
 String webkitWebViewGetCurrentScriptDialogMessage(WebKitWebView*);
diff --git a/Source/WebKit/UIProcess/API/glib/webkit.h.in b/Source/WebKit/UIProcess/API/glib/webkit.h.in
index 805f9f638c1630b5e9310494ae2970262de001cc..add3e80896c2e82bdd12cee15c8014bf88391ee0 100644
--- a/Source/WebKit/UIProcess/API/glib/webkit.h.in
+++ b/Source/WebKit/UIProcess/API/glib/webkit.h.in
@@ -45,6 +45,7 @@
 #include <@API_INCLUDE_PREFIX@/WebKitAutomationSession.h>
 #include <@API_INCLUDE_PREFIX@/WebKitBackForwardList.h>
 #include <@API_INCLUDE_PREFIX@/WebKitBackForwardListItem.h>
+#include <@API_INCLUDE_PREFIX@/WebKitBrowserInspector.h>
 #if PLATFORM(GTK)
 #include <@API_INCLUDE_PREFIX@/WebKitClipboardPermissionRequest.h>
 #include <@API_INCLUDE_PREFIX@/WebKitColorChooserRequest.h>
diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp
index ebd7d55886465375c70fb3265f6655fe43c62966..b5d2169c2b76474f12038727a66cf69e5ed23ebd 100644
--- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp
+++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp
@@ -268,6 +268,8 @@ void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool
 {
     if (wasEventHandled || event.type() != WebEventType::KeyDown || !event.nativeEvent())
         return;
+    if (!event.nativeEvent())
+        return;
 
     // Always consider arrow keys as handled, otherwise the GtkWindow key bindings will move the focus.
     guint keyval;
@@ -366,9 +368,9 @@ void PageClientImpl::selectionDidChange()
         webkitWebViewSelectionDidChange(WEBKIT_WEB_VIEW(m_viewWidget));
 }
 
-RefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot(std::optional<WebCore::IntRect>&& clipRect)
+RefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot(std::optional<WebCore::IntRect>&& clipRect, bool nominalResolution)
 {
-    return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget), WTFMove(clipRect));
+    return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget), WTFMove(clipRect), nominalResolution);
 }
 
 void PageClientImpl::didChangeContentSize(const IntSize& size)
diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h
index 536e66027bdcfec08e28503d3dd715e3c51a2c9f..2cfba18152fd87c10e1bb7630515a677799f1bbc 100644
--- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h
+++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h
@@ -109,7 +109,7 @@ private:
 #endif
     Ref<WebCore::ValidationBubble> createValidationBubble(const String& message, const WebCore::ValidationBubble::Settings&) final;
     void selectionDidChange() override;
-    RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&) override;
+    RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&, bool nominalResolution = false) override;
 #if ENABLE(DRAG_SUPPORT)
     void startDrag(WebCore::SelectionData&&, OptionSet<WebCore::DragOperation>, RefPtr<WebCore::ShareableBitmap>&& dragImage, WebCore::IntPoint&& dragImageHotspot) override;
     void didPerformDragControllerAction() override;
diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h
new file mode 100644
index 0000000000000000000000000000000000000000..45221096280941d747ef3f46749b1466b2d70090
--- /dev/null
+++ b/Source/WebKit/UIProcess/API/gtk/WebKitBrowserInspector.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(BUILDING_WEBKIT)
+#error "Only <webkit2/webkit2.h> can be included directly."
+#endif
+
+#ifndef WebKitBrowserInspector_h
+#define WebKitBrowserInspector_h
+
+#include <glib-object.h>
+#include <webkit/WebKitDefines.h>
+#include <webkit/WebKitWebView.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_BROWSER_INSPECTOR            (webkit_browser_inspector_get_type())
+#define WEBKIT_BROWSER_INSPECTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspector))
+#define WEBKIT_IS_BROWSER_INSPECTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_BROWSER_INSPECTOR))
+#define WEBKIT_BROWSER_INSPECTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass),  WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass))
+#define WEBKIT_IS_BROWSER_INSPECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  WEBKIT_TYPE_BROWSER_INSPECTOR))
+#define WEBKIT_BROWSER_INSPECTOR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  WEBKIT_TYPE_BROWSER_INSPECTOR, WebKitBrowserInspectorClass))
+
+typedef struct _WebKitBrowserInspector        WebKitBrowserInspector;
+typedef struct _WebKitBrowserInspectorClass   WebKitBrowserInspectorClass;
+typedef struct _WebKitBrowserInspectorPrivate WebKitBrowserInspectorPrivate;
+
+struct _WebKitBrowserInspector {
+    GObject parent;
+
+    WebKitBrowserInspectorPrivate *priv;
+};
+
+struct _WebKitBrowserInspectorClass {
+    GObjectClass parent_class;
+
+    WebKitWebView *(* create_new_page)           (WebKitBrowserInspector    *browser_inspector,
+                                                  WebKitWebContext          *context);
+    WebKitWebView *(* quit_application)          (WebKitBrowserInspector    *browser_inspector);
+
+    void (*_webkit_reserved0) (void);
+    void (*_webkit_reserved1) (void);
+    void (*_webkit_reserved2) (void);
+    void (*_webkit_reserved3) (void);
+};
+
+WEBKIT_API GType
+webkit_browser_inspector_get_type                     (void);
+
+WEBKIT_API WebKitBrowserInspector *
+webkit_browser_inspector_get_default                  (void);
+
+WEBKIT_API void
+webkit_browser_inspector_initialize_pipe              (const char* defaultProxyURI,
+                                                       const char* const* ignoreHosts);
+
+G_END_DECLS
+
+#endif
diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in b/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in
index 496079da90993ac37689b060b69ecd4a67c2b6a8..af30181ca922f16c0f6e245c70e5ce7d8999341f 100644
--- a/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in
+++ b/Source/WebKit/UIProcess/API/gtk/WebKitPointerLockPermissionRequest.h.in
@@ -23,7 +23,7 @@
 #define WebKitPointerLockPermissionRequest_h
 
 #include <glib-object.h>
-#include <webkit/WebKitDefines.h>
+#include <@API_INCLUDE_PREFIX@/WebKitDefines.h>
 
 G_BEGIN_DECLS
 
diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
index 4d4f62a1a5dfc153773c3fe7c37c4fd9c0cfa4b5..647fdfbf93889c966806d5f4285a1fc0724923cc 100644
--- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
+++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp
@@ -2902,6 +2902,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);
@@ -2958,12 +2963,12 @@ void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase)
         webkitWebViewBase->priv->acceleratedBackingStore->update({ });
 }
 
-RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase* webkitWebViewBase, std::optional<IntRect>&& clipRect)
+RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase* webkitWebViewBase, std::optional<IntRect>&& clipRect, bool nominalResolution)
 {
     WebPageProxy* page = webkitWebViewBase->priv->pageProxy.get();
 
     IntSize size = clipRect ? clipRect->size() : page->viewSize();
-    float deviceScale = page->deviceScaleFactor();
+    float deviceScale = nominalResolution ? 1 : page->deviceScaleFactor();
     size.scale(deviceScale);
 
 #if !USE(GTK4)
diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
index cfd4310b3c775e662b4d643d4f2edda56e101b58..65dc3319a8031b478b0faca89276f9dfed28c55f 100644
--- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
+++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h
@@ -27,6 +27,7 @@
 
 #pragma once
 
+#include "AcceleratedBackingStore.h"
 #include "APIPageConfiguration.h"
 #include "InputMethodState.h"
 #include "RendererBufferFormat.h"
@@ -104,7 +105,7 @@ void webkitWebViewBaseStartDrag(WebKitWebViewBase*, WebCore::SelectionData&&, Op
 void webkitWebViewBaseDidPerformDragControllerAction(WebKitWebViewBase*);
 #endif
 
-RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase*, std::optional<WebCore::IntRect>&&);
+RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase*, std::optional<WebCore::IntRect>&&, bool nominalResolution);
 void webkitWebViewBaseSetEnableBackForwardNavigationGesture(WebKitWebViewBase*, bool enabled);
 WebKit::ViewGestureController* webkitWebViewBaseViewGestureController(WebKitWebViewBase*);
 
@@ -145,3 +146,5 @@ void webkitWebViewBaseSetPlugID(WebKitWebViewBase*, const String&);
 #endif
 
 WebKit::RendererBufferFormat webkitWebViewBaseGetRendererBufferFormat(WebKitWebViewBase*);
+
+WebKit::AcceleratedBackingStore* webkitWebViewBaseGetAcceleratedBackingStore(WebKitWebViewBase*);
diff --git a/Source/WebKit/UIProcess/API/wpe/APIViewClient.h b/Source/WebKit/UIProcess/API/wpe/APIViewClient.h
index 7636ad733e7be66a74f8fede966b0acb905a5842..cf54287353d1e529c6765e3caf8d283abe1e3472 100644
--- a/Source/WebKit/UIProcess/API/wpe/APIViewClient.h
+++ b/Source/WebKit/UIProcess/API/wpe/APIViewClient.h
@@ -26,6 +26,12 @@
 #pragma once
 
 #include "UserMessage.h"
+#if USE(CAIRO)
+#include <cairo.h>
+#endif
+#if USE(SKIA)
+#include <skia/core/SkImage.h>
+#endif
 #include <wtf/CompletionHandler.h>
 #include <wtf/TZoneMallocInlines.h>
 
@@ -50,6 +56,13 @@ public:
     virtual bool isGLibBasedAPI() { return false; }
 
     virtual void frameDisplayed(WKWPE::View&) { }
+// Playwright begin
+#if USE(CAIRO)
+    virtual cairo_surface_t* takeViewScreenshot() { return nullptr; }
+#elif USE(SKIA)
+    virtual sk_sp<SkImage> takeViewScreenshot() { return nullptr; }
+#endif
+// Playwright end
     virtual void willStartLoad(WKWPE::View&) { }
     virtual void didChangePageID(WKWPE::View&) { }
     virtual void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler<void(WebKit::UserMessage&&)>&& completionHandler) { completionHandler(WebKit::UserMessage()); }
diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp
index 97b321f1d8bb33175f963af0f6ffe741b50e28e6..d03085cbaad14e3ed88817bf5f26facbe9a24538 100644
--- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp
+++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.cpp
@@ -34,9 +34,13 @@
 #include "TouchGestureController.h"
 #include "WPEWebViewLegacy.h"
 #include "WPEWebViewPlatform.h"
+#include "WebColorPickerWPE.h"
+#include "WebDateTimePickerWPE.h"
 #include "WebContextMenuProxy.h"
 #include "WebContextMenuProxyWPE.h"
+#include "WebKitDataListSuggestionsDropdown.h"
 #include "WebKitPopupMenu.h"
+#include "WebColorPicker.h"
 #include <WebCore/ActivityState.h>
 #include <WebCore/Cursor.h>
 #include <WebCore/DOMPasteAccess.h>
@@ -52,6 +56,12 @@
 #include <wpe/wpe-platform.h>
 #endif
 
+#if USE(SKIA)
+#include <skia/core/SkBitmap.h>
+#include <skia/core/SkCanvas.h>
+#include <skia/core/SkImage.h>
+#endif
+
 namespace WebKit {
 
 WTF_MAKE_TZONE_ALLOCATED_IMPL(PageClientImpl);
@@ -487,6 +497,64 @@ void PageClientImpl::selectionDidChange()
     m_view.selectionDidChange();
 }
 
+#if USE(SKIA)
+sk_sp<SkImage> PageClientImpl::takeViewSnapshot(std::optional<WebCore::IntRect>&& clipRect, bool nominalResolution)
+{
+    sk_sp<SkImage> fullScreenshot = m_view.client().takeViewScreenshot();
+    float deviceScale = m_view.page().deviceScaleFactor();
+    if (!clipRect && (!nominalResolution || deviceScale == 1))
+        return fullScreenshot;
+
+    WebCore::IntSize size = clipRect ? clipRect->size() : m_view.page().viewSize();
+    if (!nominalResolution) {
+        size.scale(deviceScale);
+        if (clipRect)
+            clipRect->scale(deviceScale);
+    }
+
+    SkBitmap bitmap;
+    bitmap.allocPixels(SkImageInfo::Make(size.width(), size.height(), kN32_SkColorType, kPremul_SkAlphaType));
+    SkCanvas canvas(bitmap);
+    if (clipRect) {
+        canvas.translate(-clipRect->x(), -clipRect->y());
+        SkRect rect = SkRect::MakeXYWH(clipRect->x(), clipRect->y(), clipRect->width(), clipRect->height());
+        canvas.clipRect(rect);
+    }
+    if (nominalResolution)
+        canvas.scale(1/deviceScale, 1/deviceScale);
+    canvas.drawImage(fullScreenshot, 0, 0);
+    return bitmap.asImage();
+}
+#elif USE(CAIRO)
+RefPtr<cairo_surface_t> PageClientImpl::takeViewSnapshot(std::optional<WebCore::IntRect>&& clipRect, bool nominalResolution)
+{
+    RefPtr<cairo_surface_t> fullScreenshot = adoptRef(m_view.client().takeViewScreenshot());
+    float deviceScale = m_view.page().deviceScaleFactor();
+    if (!clipRect && (!nominalResolution || deviceScale == 1))
+        return fullScreenshot;
+
+    WebCore::IntSize size = clipRect ? clipRect->size() : m_view.page().viewSize();
+    if (!nominalResolution) {
+        size.scale(deviceScale);
+        if (clipRect)
+            clipRect->scale(deviceScale);
+    }
+    RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_RGB24, size.width(), size.height()));
+    RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
+    if (clipRect) {
+        cairo_translate(cr.get(), -clipRect->x(), -clipRect->y());
+        cairo_rectangle(cr.get(), clipRect->x(), clipRect->y(), clipRect->width(), clipRect->height());
+        cairo_clip(cr.get());
+    }
+    if (nominalResolution)
+        cairo_scale(cr.get(), 1/deviceScale, 1/deviceScale);
+    cairo_set_source_surface(cr.get(), fullScreenshot.get(), 0, 0);
+    cairo_paint(cr.get());
+    return surface;
+}
+#endif
+
+
 WebKitWebResourceLoadManager* PageClientImpl::webResourceLoadManager()
 {
     return m_view.webResourceLoadManager();
@@ -497,4 +565,23 @@ void PageClientImpl::callAfterNextPresentationUpdate(CompletionHandler<void()>&&
     m_view.callAfterNextPresentationUpdate(WTFMove(callback));
 }
 
+#if ENABLE(DATALIST_ELEMENT)
+RefPtr<WebKit::WebDataListSuggestionsDropdown> PageClientImpl::createDataListSuggestionsDropdown(WebKit::WebPageProxy& page)
+{
+    return WebKitDataListSuggestionsDropdown::create(page);
+}
+#endif
+
+RefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy* page, const WebCore::Color& color, const WebCore::IntRect& rect, ColorControlSupportsAlpha, Vector<WebCore::Color>&&)
+{
+    return WebColorPickerWPE::create(*page, color, rect);
+}
+
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+RefPtr<WebDateTimePicker> PageClientImpl::createDateTimePicker(WebPageProxy& page)
+{
+    return WebDateTimePickerWPE::create(page);
+}
+#endif
+
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h
index 353515ae3a699d85314a924ba6fc4e9610ade23b..8a541023be8549e2c1fced51af6ed03dcd67fc6f 100644
--- a/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h
+++ b/Source/WebKit/UIProcess/API/wpe/PageClientImpl.h
@@ -170,9 +170,24 @@ private:
     void didChangeWebPageID() const override;
 
     void selectionDidChange() override;
-
+#if USE(SKIA)
+    sk_sp<SkImage> takeViewSnapshot(std::optional<WebCore::IntRect>&&, bool nominalResolution) override;
+#elif USE(CAIRO)
+    RefPtr<cairo_surface_t> takeViewSnapshot(std::optional<WebCore::IntRect>&&, bool nominalResolution) override;
+#endif
     WebKitWebResourceLoadManager* webResourceLoadManager() override;
 
+#if ENABLE(DATALIST_ELEMENT)
+    RefPtr<WebKit::WebDataListSuggestionsDropdown> createDataListSuggestionsDropdown(WebKit::WebPageProxy& page) override;
+#endif
+
+#if ENABLE(INPUT_TYPE_COLOR)
+    RefPtr<WebColorPicker> createColorPicker(WebPageProxy*, const WebCore::Color& initialColor, const WebCore::IntRect&, ColorControlSupportsAlpha, Vector<WebCore::Color>&&) override;
+#endif
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+    RefPtr<WebDateTimePicker> createDateTimePicker(WebPageProxy&) 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..273c5105cdf1638955cea01128c9bbab3e64436c
--- /dev/null
+++ b/Source/WebKit/UIProcess/API/wpe/WebKitBrowserInspector.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if !defined(__WEBKIT_H_INSIDE__) && !defined(BUILDING_WEBKIT)
+#error "Only <wpe/webkit.h> can be included directly."
+#endif
+
+#ifndef WebKitBrowserInspector_h
+#define WebKitBrowserInspector_h
+
+#include <glib-object.h>
+#include <wpe/WebKitDefines.h>
+#include <wpe/WebKitWebView.h>
+
+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<WebKitDataListSuggestionsDropdown> 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 763bda5b29304f7ed7133c0a8158e6c8b94c5ea1..8ed962e8c1af62b9b73a68348d0d88765429861d 100644
--- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp
+++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.cpp
@@ -54,6 +54,7 @@ struct _WebKitWebViewBackend {
     struct wpe_view_backend* backend;
     GDestroyNotify notifyCallback;
     gpointer notifyCallbackData;
+    take_screenshot_callback screenshotCallback;
     int referenceCount { 1 };
 };
 
@@ -116,6 +117,19 @@ struct wpe_view_backend* webkit_web_view_backend_get_wpe_backend(WebKitWebViewBa
     return viewBackend->backend;
 }
 
+void webkit_web_view_backend_set_screenshot_callback(WebKitWebViewBackend *view_backend, take_screenshot_callback callback)
+{
+    view_backend->screenshotCallback = callback;
+}
+
+PlatformImage webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend* view_backend)
+{
+    if (!view_backend->screenshotCallback)
+        return nullptr;
+
+    return view_backend->screenshotCallback(view_backend->notifyCallbackData);
+}
+
 namespace WTF {
 
 template <> WebKitWebViewBackend* refGPtr(WebKitWebViewBackend* ptr)
diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h
index 16dcc1f69c38cd8ad630bc49d6d69feaa3aa811e..efa3814a8e896e02b955dea0be70bdc5828e3d82 100644
--- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h
+++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackend.h
@@ -28,6 +28,15 @@
 #include <wpe/WebKitDefines.h>
 #include <wpe/wpe.h>
 
+#if defined(USE_CAIRO) && USE_CAIRO
+#include <cairo.h>
+using PlatformImage = cairo_surface_t*;
+#endif
+#if defined(USE_SKIA) && USE_SKIA
+#include <skia/core/SkImage.h>
+using PlatformImage = SkImage*;
+#endif
+
 G_BEGIN_DECLS
 
 #define WEBKIT_TYPE_WEB_VIEW_BACKEND (webkit_web_view_backend_get_type())
@@ -44,6 +53,12 @@ webkit_web_view_backend_new             (struct wpe_view_backend *backend,
 WEBKIT_API struct wpe_view_backend *
 webkit_web_view_backend_get_wpe_backend (WebKitWebViewBackend    *view_backend);
 
+typedef PlatformImage (*take_screenshot_callback)(gpointer              user_data);
+
+WEBKIT_API void
+webkit_web_view_backend_set_screenshot_callback   (WebKitWebViewBackend      *view_backend,
+                                                   take_screenshot_callback  callback);
+
 G_END_DECLS
 
 #endif /* WebKitWebViewBackend_h */
diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h
index e4b92ace1531090ae38a7aec3d3d4febf19aee84..b66b573f9148c39c5ce2738add6cd01a9a352be8 100644
--- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h
+++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewBackendPrivate.h
@@ -31,3 +31,5 @@ template <> void derefGPtr(WebKitWebViewBackend* ptr);
 }
 
 void webkitWebViewBackendUnref(WebKitWebViewBackend*);
+
+PlatformImage webkitWebViewBackendTakeScreenshot(WebKitWebViewBackend*);
diff --git a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h
index 2f1182cb91a00353eace0b71612df096391c2450..d71d7fc724b046fab41285bb8f390cb6af6520ca 100644
--- a/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h
+++ b/Source/WebKit/UIProcess/API/wpe/WebKitWebViewClient.h
@@ -51,6 +51,13 @@ private:
     bool isGLibBasedAPI() override { return true; }
 
     void frameDisplayed(WKWPE::View&) override;
+// Playwright begin
+#if USE(CAIRO)
+    cairo_surface_t* takeViewScreenshot() override;
+#elif USE(SKIA)
+    sk_sp<SkImage> takeViewScreenshot() override;
+#endif
+// Playwright end
     void willStartLoad(WKWPE::View&) override;
     void didChangePageID(WKWPE::View&) override;
     void didReceiveUserMessage(WKWPE::View&, WebKit::UserMessage&&, CompletionHandler<void(WebKit::UserMessage&&)>&&) override;
diff --git a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h
index 1eb1f76b903199f5af64d48cb5ce5b54c2c67571..3d25a50fd22352a7fc2d2e638eb559313c36966b 100644
--- a/Source/WebKit/UIProcess/Automation/WebAutomationSession.h
+++ b/Source/WebKit/UIProcess/Automation/WebAutomationSession.h
@@ -256,6 +256,8 @@ public:
 
     void didDestroyFrame(WebCore::FrameIdentifier);
 
+    static std::optional<String> platformGetBase64EncodedPNGData(const ViewSnapshot&);
+
 private:
     RefPtr<WebPageProxy> webPageProxyForHandle(const String&);
     String handleForWebPageProxy(const WebPageProxy&);
@@ -300,7 +302,6 @@ private:
 
     // Get base64-encoded PNG data from a bitmap.
     static std::optional<String> platformGetBase64EncodedPNGData(WebCore::ShareableBitmap::Handle&&);
-    static std::optional<String> platformGetBase64EncodedPNGData(const ViewSnapshot&);
 
     // Save base64-encoded file contents to a local file path and return the path.
     // This reuses the basename of the remote file path so that the filename exposed to DOM API remains the same.
diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp
index 67b26803f31aed0690ffd4e0aa26a842edce5eea..61bb0a44b067847d3cb45ad397c9c3572e107a89 100644
--- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.cpp
@@ -167,7 +167,11 @@ void AuxiliaryProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& lau
         launchOptions.processCmdPrefix = String::fromUTF8(processCmdPrefix);
 #endif // ENABLE(DEVELOPER_MODE) && (PLATFORM(GTK) || PLATFORM(WPE))
 
+/* playwright revert 50f8fee */
+#if 0
     populateOverrideLanguagesLaunchOptions(launchOptions);
+#endif
+/* end playwright revert 50f8fee */
 
     platformGetLaunchOptions(launchOptions);
 }
diff --git a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h
index a8ee41c1155989a57a5c0bd09c5144e8103c7c7c..172d567478e36d275a23ae3db82281f4a7af5c26 100644
--- a/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h
+++ b/Source/WebKit/UIProcess/AuxiliaryProcessProxy.h
@@ -296,13 +296,16 @@ protected:
 
     InitializationActivityAndGrant initializationActivityAndGrant();
 
+    /* playwright revert 50f8fee - make protected to allow use from WebProcessProxy */
+    Vector<String> platformOverrideLanguages() const;
+    /* end playwright revert 50f8fee */
+
 private:
     virtual void connectionWillOpen(IPC::Connection&);
     virtual void processWillShutDown(IPC::Connection&) = 0;
     void outgoingMessageQueueIsGrowingLarge();
 
     void populateOverrideLanguagesLaunchOptions(ProcessLauncher::LaunchOptions&) const;
-    Vector<String> platformOverrideLanguages() const;
     void platformStartConnectionTerminationWatchdog();
 
     // Connection::Client
diff --git a/Source/WebKit/UIProcess/BackingStore.h b/Source/WebKit/UIProcess/BackingStore.h
index f72e17dc0973d4523c4b29a14754ec6d6036e06f..153f7b8495404513e20db757c0269f9e3c4d0e2d 100644
--- a/Source/WebKit/UIProcess/BackingStore.h
+++ b/Source/WebKit/UIProcess/BackingStore.h
@@ -69,6 +69,7 @@ public:
     float deviceScaleFactor() const { return m_deviceScaleFactor; }
 
     void paint(PlatformPaintContextPtr, const WebCore::IntRect&);
+    RefPtr<cairo_surface_t> surface() const { return m_surface; }
     void incorporateUpdate(UpdateInfo&&);
 
 private:
diff --git a/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cfb57a48ce387b79613b757e2eb4de2c378aac30
--- /dev/null
+++ b/Source/WebKit/UIProcess/BrowserInspectorPipe.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BrowserInspectorPipe.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorPlaywrightAgent.h"
+#include "InspectorPlaywrightAgentClient.h"
+#include "RemoteInspectorPipe.h"
+#include "WebKit2Initialize.h"
+#include <wtf/NeverDestroyed.h>
+
+namespace WebKit {
+
+void initializeBrowserInspectorPipe(std::unique_ptr<InspectorPlaywrightAgentClient> client)
+{
+    // Initialize main loop before creating inspecor agent and pipe queues.
+    WebKit::InitializeWebKit2();
+
+    class BrowserInspectorPipe {
+    public:
+        BrowserInspectorPipe(std::unique_ptr<InspectorPlaywrightAgentClient> client)
+            : m_playwrightAgent(std::move(client))
+            , m_remoteInspectorPipe(m_playwrightAgent)
+        {
+        }
+
+        InspectorPlaywrightAgent m_playwrightAgent;
+        RemoteInspectorPipe m_remoteInspectorPipe;
+    };
+
+    static NeverDestroyed<BrowserInspectorPipe> 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<InspectorPlaywrightAgentClient> client);
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h
index 1eb07a8bfadb2c4477698940b9429eefacc7d059..30e8b82bb1d8ca88ec5af80580c0ca751d10485f 100644
--- a/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h
+++ b/Source/WebKit/UIProcess/Cocoa/SOAuthorization/WKSOAuthorizationDelegate.h
@@ -25,6 +25,7 @@
 
 #if HAVE(APP_SSO)
 
+#import "SOAuthorizationSession.h"
 #import <pal/cocoa/AppSSOSoftLink.h>
 
 namespace WebKit {
diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h
index 47da0ee168267f6a4a27602ea0c3cffdeb0a8a44..70eef746a34ebc037e56b4a81675e1184a37d178 100644
--- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.h
+++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.h
@@ -102,6 +102,7 @@ private:
         void runJavaScriptAlert(WebPageProxy&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function<void()>&& completionHandler) final;
         void runJavaScriptConfirm(WebPageProxy&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function<void(bool)>&& completionHandler) final;
         void runJavaScriptPrompt(WebPageProxy&, const WTF::String&, const WTF::String&, WebFrameProxy*, FrameInfoData&&, Function<void(const WTF::String&)>&&) final;
+        void handleJavaScriptDialog(WebKit::WebPageProxy&, bool accept, const WTF::String&) final;
         void presentStorageAccessConfirmDialog(const WTF::String& requestingDomain, const WTF::String& currentDomain, CompletionHandler<void(bool)>&&);
         void requestStorageAccessConfirm(WebPageProxy&, WebFrameProxy*, const WebCore::RegistrableDomain& requestingDomain, const WebCore::RegistrableDomain& currentDomain, std::optional<WebCore::OrganizationStorageAccessPromptQuirk>&&, CompletionHandler<void(bool)>&&) final;
         void decidePolicyForGeolocationPermissionRequest(WebPageProxy&, WebFrameProxy&, const FrameInfoData&, Function<void(bool)>&) final;
@@ -220,6 +221,7 @@ private:
         bool webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler : 1;
         bool webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1;
         bool webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler : 1;
+        bool webViewHandleJavaScriptDialogValue : 1;
         bool webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler : 1;
         bool webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler : 1;
         bool webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler : 1;
diff --git a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
index 1994f291d7e492daaefecfe93b4aa24f3d89fdef..03410eb4546e23a9f5f6ac6a3dd809207cff31e4 100644
--- a/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
+++ b/Source/WebKit/UIProcess/Cocoa/UIDelegate.mm
@@ -134,6 +134,7 @@ void UIDelegate::setDelegate(id <WKUIDelegate> delegate)
     m_delegateMethods.webViewRunJavaScriptAlertPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:)];
     m_delegateMethods.webViewRunJavaScriptConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
     m_delegateMethods.webViewRunJavaScriptTextInputPanelWithPromptDefaultTextInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:)];
+    m_delegateMethods.webViewHandleJavaScriptDialogValue = [delegate respondsToSelector:@selector(webView:handleJavaScriptDialog:value:)];
     m_delegateMethods.webViewRequestStorageAccessPanelUnderFirstPartyCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:completionHandler:)];
     m_delegateMethods.webViewRequestStorageAccessPanelForDomainUnderCurrentDomainForQuirkDomainsCompletionHandler = [delegate respondsToSelector:@selector(_webView:requestStorageAccessPanelForDomain:underCurrentDomain:forQuirkDomains:completionHandler:)];
     m_delegateMethods.webViewRunBeforeUnloadConfirmPanelWithMessageInitiatedByFrameCompletionHandler = [delegate respondsToSelector:@selector(_webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:completionHandler:)];
@@ -465,6 +466,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, std::optional<WebCore::OrganizationStorageAccessPromptQuirk>&& organizationStorageAccessPromptQuirk, CompletionHandler<void(bool)>&& completionHandler)
 {
     RefPtr uiDelegate = m_uiDelegate.get();
diff --git a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm
index 9c83bff69be2da80e51e91ce08cfbfcbcd7b3dd5..b70a8450fc3b69e2d27aff88474502cdc0bdc8f8 100644
--- a/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm
+++ b/Source/WebKit/UIProcess/Cocoa/WebPageProxyCocoa.mm
@@ -42,7 +42,9 @@
 #import "NativeWebKeyboardEvent.h"
 #import "NativeWebMouseEvent.h"
 #import "NavigationState.h"
+#import "NetworkProcessMessages.h"
 #import "PageClient.h"
+#import "PasteboardTypes.h"
 #import "PlatformXRSystem.h"
 #import "PlaybackSessionManagerProxy.h"
 #import "QuickLookThumbnailLoader.h"
@@ -317,11 +319,86 @@ bool WebPageProxy::scrollingUpdatesDisabledForTesting()
 
 void WebPageProxy::startDrag(const DragItem& dragItem, ShareableBitmap::Handle&& dragImageHandle)
 {
+    if (m_interceptDrags) {
+        NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName: m_overrideDragPasteboardName];
+
+        m_dragSelectionData = String([pasteboard name]);
+        if (auto replyID = grantAccessToCurrentPasteboardData(String([pasteboard name]), [] () { }))
+            websiteDataStore().protectedNetworkProcess()->connection().waitForAsyncReplyAndDispatchImmediately<Messages::NetworkProcess::AllowFilesAccessFromWebProcess>(*replyID, 100_ms);
+        m_dragSourceOperationMask = WebCore::anyDragOperation();
+
+        if (auto& info = dragItem.promisedAttachmentInfo) {
+            auto attachment = attachmentForIdentifier(info.attachmentIdentifier);
+            if (!attachment) {
+                dragCancelled();
+                return;
+            }
+            NSString *utiType = attachment->utiType();
+            if (!utiType.length) {
+                dragCancelled();
+                return;
+            }
+
+            for (size_t index = 0; index < info.additionalTypesAndData.size(); ++index) {
+                auto nsData = info.additionalTypesAndData[index].second->createNSData();
+                [pasteboard setData:nsData.get() forType:info.additionalTypesAndData[index].first];
+            }
+        } else {
+            [pasteboard setString:@"" forType:PasteboardTypes::WebDummyPboardType];
+        }
+        didStartDrag();
+        return;
+    }
+
     if (RefPtr pageClient = this->pageClient())
         pageClient->startDrag(dragItem, WTFMove(dragImageHandle));
 }
 
-#endif
+void WebPageProxy::releaseInspectorDragPasteboard() {
+    if (!!m_dragSelectionData)
+        m_dragSelectionData = std::nullopt;
+    if (!m_overrideDragPasteboardName.isEmpty()) {
+        NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
+        [pasteboard releaseGlobally];
+        m_overrideDragPasteboardName = ""_s;
+    }
+}
+
+
+void WebPageProxy::setInterceptDrags(bool shouldIntercept) {
+    m_interceptDrags = shouldIntercept;
+    if (m_interceptDrags) {
+        if (m_overrideDragPasteboardName.isEmpty()) {
+            NSPasteboard *pasteboard = [NSPasteboard pasteboardWithUniqueName];
+            m_overrideDragPasteboardName = String([pasteboard name]);
+        }
+        legacyMainFrameProcess().send(Messages::WebPage::SetDragPasteboardName(m_overrideDragPasteboardName), webPageIDInMainFrameProcess());
+    } else {
+        legacyMainFrameProcess().send(Messages::WebPage::SetDragPasteboardName(""_s), webPageIDInMainFrameProcess());
+    }
+}
+
+// FIXME: Move these functions to WebPageProxyIOS.mm.
+#if PLATFORM(IOS_FAMILY)
+
+void WebPageProxy::setPromisedDataForImage(const String&, const SharedMemory::Handle&, const String&, const String&, const String&, const String&, const String&, const SharedMemory::Handle&, const String&)
+{
+    notImplemented();
+}
+
+void WebPageProxy::setDragCaretRect(const IntRect& dragCaretRect)
+{
+    if (m_currentDragCaretRect == dragCaretRect)
+        return;
+
+    auto previousRect = m_currentDragCaretRect;
+    m_currentDragCaretRect = dragCaretRect;
+    pageClient()->didChangeDragCaretRect(previousRect, dragCaretRect);
+}
+
+#endif // PLATFORM(IOS_FAMILY)
+
+#endif // ENABLE(DRAG_SUPPORT)
 
 #if ENABLE(ATTACHMENT_ELEMENT)
 
diff --git a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm
index 6eca9f4d7e1e1d54bc41a68f689ec1dcce54f354..7feb9b894f852d4a2c93ebeb580f7b6636da9670 100644
--- a/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm
+++ b/Source/WebKit/UIProcess/Cocoa/WebProcessPoolCocoa.mm
@@ -435,7 +435,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     auto screenProperties = WebCore::collectScreenProperties();
     parameters.screenProperties = WTFMove(screenProperties);
 #if PLATFORM(MAC)
-    parameters.useOverlayScrollbars = ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay);
+    parameters.useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay);
 #endif
     
 #if (PLATFORM(IOS) || PLATFORM(VISION)) && HAVE(AGX_COMPILER_SERVICE)
@@ -830,8 +830,8 @@ void WebProcessPool::registerNotificationObservers()
     }];
 
     m_scrollerStyleNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSPreferredScrollerStyleDidChangeNotification object:nil queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
-        auto scrollbarStyle = [NSScroller preferredScrollerStyle];
-        sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(scrollbarStyle));
+        bool useOverlayScrollbars = m_configuration->forceOverlayScrollbars() || ([NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay);
+        sendToAllProcesses(Messages::WebProcess::ScrollerStylePreferenceChanged(useOverlayScrollbars));
     }];
 
     m_activationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidBecomeActiveNotification object:NSApp queue:[NSOperationQueue currentQueue] usingBlock:^(NSNotification *notification) {
diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp
index c09616b4b076136888cda95c3c74137cf2668a42..f2ee3ee1417f4716157f004ef53d441d94c7e1c3 100644
--- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp
+++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.cpp
@@ -33,6 +33,7 @@
 #include "LayerTreeContext.h"
 #include "MessageSenderInlines.h"
 #include "UpdateInfo.h"
+#include "WebPageInspectorController.h"
 #include "WebPageProxy.h"
 #include "WebPreferences.h"
 #include "WebProcessPool.h"
@@ -40,8 +41,10 @@
 #include <WebCore/Region.h>
 #include <optional>
 #include <wtf/TZoneMallocInlines.h>
+#include <wtf/Vector.h>
 
 #if PLATFORM(GTK)
+#include "WebKitWebViewBasePrivate.h"
 #include <gtk/gtk.h>
 #endif
 
@@ -49,6 +52,13 @@
 #include <wtf/glib/RunLoopSourcePriority.h>
 #endif
 
+#if PLATFORM(WIN)
+#include <cairo-win32.h>
+#include <windows.h>
+#include <WebCore/HWndDC.h>
+#include <WebCore/RefPtrCairo.h>
+#endif
+
 namespace WebKit {
 using namespace WebCore;
 
@@ -180,6 +190,11 @@ void DrawingAreaProxyCoordinatedGraphics::deviceScaleFactorDidChange(CompletionH
     completionHandler();
 }
 
+void DrawingAreaProxyCoordinatedGraphics::waitForSizeUpdate(Function<void (const DrawingAreaProxyCoordinatedGraphics&)>&& callback)
+{
+    m_callbacks.append(WTFMove(callback));
+}
+
 void DrawingAreaProxyCoordinatedGraphics::setBackingStoreIsDiscardable(bool isBackingStoreDiscardable)
 {
 #if !PLATFORM(WPE)
@@ -241,6 +256,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<cairo_surface_t> surface;
+#if PLATFORM(WIN)
+    HWndDC dc;
+    if (m_isInAcceleratedCompositingMode) {
+        dc.setHWnd(reinterpret_cast<HWND>(protectedWebPageProxy()->viewWidget()));
+        surface = adoptRef(cairo_win32_surface_create(dc));
+#else
+    if (isInAcceleratedCompositingMode()) {
+#  if PLATFORM(GTK)
+        AcceleratedBackingStore* backingStore = webkitWebViewBaseGetAcceleratedBackingStore(WEBKIT_WEB_VIEW_BASE(protectedWebPageProxy()->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;
+
+    protectedWebPageProxy()->inspectorController().didPaint(surface.get());
+}
+#endif
+
 bool DrawingAreaProxyCoordinatedGraphics::alwaysUseCompositing() const
 {
     if (!m_webPageProxy)
@@ -300,6 +354,12 @@ void DrawingAreaProxyCoordinatedGraphics::didUpdateGeometry()
     // we need to resend the new size here.
     if (m_lastSentSize != m_size)
         sendUpdateGeometry();
+    else {
+        Vector<Function<void (const DrawingAreaProxyCoordinatedGraphics&)>> callbacks;
+        callbacks.swap(m_callbacks);
+        for (auto& cb : callbacks)
+            cb(*this);
+    }
 }
 
 #if !PLATFORM(WPE)
diff --git a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h
index 69f3479dd407e43d2cf3193b599c35d94d320aff..8b042dc992a1160b312d119cccee8c84b954eb15 100644
--- a/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h
+++ b/Source/WebKit/UIProcess/CoordinatedGraphics/DrawingAreaProxyCoordinatedGraphics.h
@@ -29,6 +29,7 @@
 
 #include "DrawingAreaProxy.h"
 #include "LayerTreeContext.h"
+#include <wtf/Function.h>
 #include <wtf/RefCounted.h>
 #include <wtf/RunLoop.h>
 #include <wtf/TZoneMalloc.h>
@@ -60,6 +61,10 @@ public:
 
     bool isInAcceleratedCompositingMode() const { return !m_layerTreeContext.isEmpty(); }
     const LayerTreeContext& layerTreeContext() const { return m_layerTreeContext; }
+    void waitForSizeUpdate(Function<void (const DrawingAreaProxyCoordinatedGraphics&)>&&);
+#if !PLATFORM(WPE)
+    void captureFrame();
+#endif
 
     void dispatchAfterEnsuringDrawing(CompletionHandler<void()>&&);
 
@@ -85,6 +90,9 @@ private:
     void enterAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) override;
     void exitAcceleratedCompositingMode(uint64_t backingStoreStateID, UpdateInfo&&) override;
     void updateAcceleratedCompositingMode(uint64_t backingStoreStateID, const LayerTreeContext&) override;
+#if PLATFORM(WIN)
+    void didChangeAcceleratedCompositingMode(bool enabled) override;
+#endif
 
     bool shouldSendWheelEventsToEventDispatcher() const override { return true; }
 
@@ -128,6 +136,7 @@ private:
     // The last size we sent to the web process.
     WebCore::IntSize m_lastSentSize;
 
+    Vector<Function<void (const DrawingAreaProxyCoordinatedGraphics&)>> m_callbacks;
 
 #if !PLATFORM(WPE)
     bool m_isBackingStoreDiscardable { true };
@@ -136,6 +145,10 @@ private:
     RunLoop::Timer m_discardBackingStoreTimer;
 #endif
     std::unique_ptr<DrawingMonitor> 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 1a6f1e5eae420cd6f792de69748be771e735d083..6c31ab3e5f8ed3327f52cf2e54e9055219b06cce 100644
--- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp
+++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.cpp
@@ -41,8 +41,10 @@
 #include <WebCore/MIMETypeRegistry.h>
 #include <WebCore/ResourceResponseBase.h>
 #include <wtf/FileSystem.h>
+#include <wtf/NeverDestroyed.h>
 #include <wtf/text/CString.h>
 #include <wtf/text/WTFString.h>
+#include <wtf/UUID.h>
 
 #if PLATFORM(MAC)
 #include <pal/spi/mac/QuarantineSPI.h>
@@ -66,7 +68,10 @@ DownloadProxy::DownloadProxy(DownloadProxyMap& downloadProxyMap, WebsiteDataStor
 #if HAVE(MODERN_DOWNLOADPROGRESS)
     , m_assertion(ProcessAssertion::create(getCurrentProcessID(), "WebKit DownloadProxy DecideDestination"_s, ProcessAssertionType::FinishTaskInterruptable))
 #endif
+    , m_uuid(createVersion4UUIDString())
 {
+    if (auto* instrumentation = m_dataStore->downloadInstrumentation())
+      instrumentation->downloadCreated(m_uuid, m_request, frameInfoData, originatingPage, this);
 }
 
 DownloadProxy::~DownloadProxy()
@@ -85,12 +90,15 @@ static RefPtr<API::Data> createData(std::span<const uint8_t> data)
 void DownloadProxy::cancel(CompletionHandler<void(API::Data*)>&& completionHandler)
 {
     if (m_dataStore) {
-        protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler)] (std::span<const uint8_t> resumeData) mutable {
+        auto* instrumentation = m_dataStore->downloadInstrumentation();
+        protectedDataStore()->protectedNetworkProcess()->sendWithAsyncReply(Messages::NetworkProcess::CancelDownload(m_downloadID), [weakThis = WeakPtr { *this }, completionHandler = WTFMove(completionHandler), instrumentation] (std::span<const uint8_t> resumeData) mutable {
             RefPtr protectedThis = weakThis.get();
             if (!protectedThis)
                 return completionHandler(nullptr);
             protectedThis->m_legacyResumeData = createData(resumeData);
             completionHandler(protectedThis->m_legacyResumeData.get());
+            if (instrumentation)
+                instrumentation->downloadFinished(protectedThis->m_uuid, "canceled"_s);
             if (RefPtr downloadProxyMap = protectedThis->m_downloadProxyMap.get())
                 downloadProxyMap->downloadFinished(*protectedThis);
         });
@@ -162,6 +170,33 @@ void DownloadProxy::decideDestinationWithSuggestedFilename(const WebCore::Resour
         suggestedFilename = m_suggestedFilename;
     suggestedFilename = MIMETypeRegistry::appendFileExtensionIfNecessary(suggestedFilename, response.mimeType());
 
+    if (auto* instrumentation = m_dataStore->downloadInstrumentation())
+      instrumentation->downloadFilenameSuggested(m_uuid, suggestedFilename);
+
+    if (m_dataStore->allowDownloadForAutomation()) {
+        SandboxExtension::Handle sandboxExtensionHandle;
+        String destination;
+        if (*m_dataStore->allowDownloadForAutomation()) {
+            destination = FileSystem::pathByAppendingComponent(m_dataStore->downloadPathForAutomation(), m_uuid);
+            if (auto handle = SandboxExtension::createHandle(destination, SandboxExtension::Type::ReadWrite))
+                sandboxExtensionHandle = WTFMove(*handle);
+        }
+        m_client->decidePlaceholderPolicy(*this, [completionHandler = WTFMove(completionHandler), destination = WTFMove(destination), sandboxExtensionHandle = WTFMove(sandboxExtensionHandle)] (WebKit::UseDownloadPlaceholder usePlaceholder, const URL& url) mutable {
+            SandboxExtension::Handle placeHolderSandboxExtensionHandle;
+            Vector<uint8_t> bookmarkData;
+            Vector<uint8_t> activityTokenData;
+#if HAVE(MODERN_DOWNLOADPROGRESS)
+            bookmarkData = bookmarkDataForURL(url);
+            activityTokenData = activityAccessToken();
+#else
+            if (auto handle = SandboxExtension::createHandle(url.fileSystemPath(), SandboxExtension::Type::ReadWrite))
+                placeHolderSandboxExtensionHandle = WTFMove(*handle);
+#endif
+            completionHandler(destination, WTFMove(sandboxExtensionHandle), AllowOverwrite::Yes, WebKit::UseDownloadPlaceholder::No, url, WTFMove(placeHolderSandboxExtensionHandle), bookmarkData.span(), activityTokenData.span());
+        });
+        return;
+    }
+
     protectedClient()->decideDestinationWithSuggestedFilename(*this, response, ResourceResponseBase::sanitizeSuggestedFilename(suggestedFilename), [this, protectedThis = Ref { *this }, completionHandler = WTFMove(completionHandler)] (AllowOverwrite allowOverwrite, String destination) mutable {
         SandboxExtension::Handle sandboxExtensionHandle;
         if (!destination.isNull()) {
@@ -224,6 +259,8 @@ void DownloadProxy::didFinish()
     updateQuarantinePropertiesIfPossible();
 #endif
     m_client->didFinish(*this);
+    if (auto* instrumentation = m_dataStore->downloadInstrumentation())
+      instrumentation->downloadFinished(m_uuid, String());
 
     // This can cause the DownloadProxy object to be deleted.
     if (RefPtr downloadProxyMap = m_downloadProxyMap.get())
@@ -235,6 +272,8 @@ void DownloadProxy::didFail(const ResourceError& error, std::span<const uint8_t>
     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.
     if (RefPtr downloadProxyMap = m_downloadProxyMap.get())
diff --git a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h
index c11230e2bdf0260db06b011a235d7687908d8943..015d84a1c1e3bc94ad11602879460256508313fa 100644
--- a/Source/WebKit/UIProcess/Downloads/DownloadProxy.h
+++ b/Source/WebKit/UIProcess/Downloads/DownloadProxy.h
@@ -165,6 +165,7 @@ private:
 #if HAVE(MODERN_DOWNLOADPROGRESS)
     RefPtr<ProcessAssertion> m_assertion;
 #endif
+    String m_uuid;
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.h b/Source/WebKit/UIProcess/DrawingAreaProxy.h
index 575ef6907ad84bcedf75b5fe2fd205a70e4edfb3..12d06c53ff697feec8a4816d44368b7df81bc803 100644
--- a/Source/WebKit/UIProcess/DrawingAreaProxy.h
+++ b/Source/WebKit/UIProcess/DrawingAreaProxy.h
@@ -91,6 +91,7 @@ public:
 
     const WebCore::IntSize& size() const { return m_size; }
     bool setSize(const WebCore::IntSize&, const WebCore::IntSize& scrollOffset = { });
+    void waitForSizeUpdate(Function<void ()>&&);
 
     virtual void minimumSizeForAutoLayoutDidChange() { }
     virtual void sizeToContentAutoSizeMaximumSizeDidChange() { }
@@ -178,6 +179,10 @@ private:
     virtual void update(uint64_t /* backingStoreStateID */, UpdateInfo&&) { }
     virtual void exitAcceleratedCompositingMode(uint64_t /* backingStoreStateID */, UpdateInfo&&) { }
 #endif
+
+#if PLATFORM(WIN)
+    virtual void didChangeAcceleratedCompositingMode(bool) { }
+#endif
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in b/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in
index 4d19362fcc71426002d8aafdd7401c01077ef051..7a1ebc8b200d3214f7fd0c4b1d062890bc49995e 100644
--- a/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in
+++ b/Source/WebKit/UIProcess/DrawingAreaProxy.messages.in
@@ -30,4 +30,7 @@ messages -> DrawingAreaProxy {
     Update(uint64_t stateID, struct WebKit::UpdateInfo updateInfo) CanDispatchOutOfOrder
     ExitAcceleratedCompositingMode(uint64_t backingStoreStateID, struct 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..8d20e2aa36ba0f7996c20a6a02792c7f151bbed5
--- /dev/null
+++ b/Source/WebKit/UIProcess/Inspector/Agents/CairoJpegEncoder.cpp
@@ -0,0 +1,246 @@
+/* Copyright 2018 Bernhard R. Fischer, 4096R/8E24F29D <bf@abenteuerland.at>
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+/*! \file cairo_jpg.c
+ * This file contains two functions for reading and writing JPEG files from
+ * and to Cairo image surfaces. It uses the functions from the libjpeg.
+ * Most of the code is directly derived from the online example at
+ * http://libjpeg-turbo.virtualgl.org/Documentation/Documentation
+ *
+ * All prototypes are defined in cairo_jpg.h All functions and their parameters
+ * and return values are described below directly at the functions. You may
+ * also have a look at the preprocessor macros defined below.
+ *
+ * To compile this code you need to have installed the packages libcairo2-dev
+ * and libjpeg-dev. Compile with the following to create an object file to link
+ * with your code:
+ * gcc -std=c99 -Wall -c `pkg-config cairo libjpeg --cflags --libs` cairo_jpg.c
+ * Use the following command to include the main() function and create an
+ * executable for testing of this code:
+ * gcc -std=c99 -Wall -o cairo_jpg -DCAIRO_JPEG_MAIN `pkg-config cairo libjpeg --cflags --libs` cairo_jpg.c
+ *
+ * @author Bernhard R. Fischer, 4096R/8E24F29D bf@abenteuerland.at
+ * @version 2020/01/18
+ * @license LGPL3.
+ */
+
+#include "config.h"
+
+#if USE(CAIRO) || PLATFORM(GTK)
+
+#include "CairoJpegEncoder.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <cairo.h>
+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 <cairo-pdf.h>
+#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.h>
+
+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..033bf77bca2de127e55cbf55a9e0b0c358fc81f9
--- /dev/null
+++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorScreencastAgent.h"
+
+#include "PageClient.h"
+#include "ScreencastEncoder.h"
+#include "WebPageInspectorController.h"
+#include "WebPageProxy.h"
+#include "WebsiteDataStore.h"
+#include <pal/crypto/CryptoDigest.h>
+#include <JavaScriptCore/InspectorFrontendRouter.h>
+#include <WebCore/NotImplemented.h>
+#include <wtf/Compiler.h>
+#include <wtf/RunLoop.h>
+#include <wtf/UUID.h>
+#include <wtf/text/Base64.h>
+
+#if USE(SKIA)
+#include "DrawingAreaProxyCoordinatedGraphics.h"
+#include "DrawingAreaProxy.h"
+#include <skia/core/SkBitmap.h>
+#include <skia/core/SkCanvas.h>
+#include <skia/core/SkImage.h>
+#include <skia/core/SkPixmap.h>
+#include <skia/core/SkData.h>
+#include <skia/core/SkStream.h>
+#include <skia/encode/SkJpegEncoder.h>
+#endif
+
+#if USE(CAIRO) || PLATFORM(GTK)
+#include "CairoJpegEncoder.h"
+#include "DrawingAreaProxyCoordinatedGraphics.h"
+#include "DrawingAreaProxy.h"
+#endif
+
+#if PLATFORM(MAC)
+#include <WebCore/ImageBufferUtilitiesCG.h>
+#endif
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
+
+namespace WebKit {
+
+const int kMaxFramesInFlight = 1;
+
+using namespace Inspector;
+
+InspectorScreencastAgent::InspectorScreencastAgent(BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page)
+    : InspectorAgentBase("Screencast"_s)
+    , m_frontendDispatcher(makeUnique<ScreencastFrontendDispatcher>(frontendRouter))
+    , m_backendDispatcher(ScreencastBackendDispatcher::create(backendDispatcher, this))
+    , m_page(page)
+{
+}
+
+InspectorScreencastAgent::~InspectorScreencastAgent()
+{
+}
+
+void InspectorScreencastAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
+{
+}
+
+void InspectorScreencastAgent::willDestroyFrontendAndBackend(DisconnectReason)
+{
+    if (!m_encoder)
+        return;
+
+    // The agent may be destroyed when the callback is invoked.
+    m_encoder->finish([sessionID = m_page.websiteDataStore().sessionID(), screencastID = WTFMove(m_currentScreencastID)] {
+        if (WebPageInspectorController::observer())
+            WebPageInspectorController::observer()->didFinishScreencast(sessionID, screencastID);
+    });
+
+    m_encoder = nullptr;
+}
+
+#if USE(SKIA) && !PLATFORM(GTK)
+void InspectorScreencastAgent::didPaint(sk_sp<SkImage>&& surface)
+{
+    sk_sp<SkImage> image(surface);
+#if PLATFORM(WPE)
+    // Get actual image size (in device pixels).
+    WebCore::IntSize displaySize(image->width(), image->height());
+
+    WebCore::IntSize drawingAreaSize = m_page.drawingArea()->size();
+    drawingAreaSize.scale(m_page.deviceScaleFactor());
+    if (drawingAreaSize != displaySize) {
+        return;
+    }
+#else
+    WebCore::IntSize displaySize = m_page.drawingArea()->size();
+#endif
+    // Do not WTFMove image here as it is used below
+    if (m_encoder)
+        m_encoder->encodeFrame(sk_sp<SkImage>(image), displaySize);
+    if (m_screencast) {
+        {
+            SkPixmap pixmap;
+            if (!image->peekPixels(&pixmap)) {
+                fprintf(stderr, "Failed to peek pixels from SkImage to compute hash\n");
+                return;
+            }
+            // Do not send the same frame over and over.
+            size_t len = pixmap.computeByteSize();
+            auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1);
+            cryptoDigest->addBytes(std::span(reinterpret_cast<const unsigned char*>(pixmap.addr()), len));
+            auto digest = cryptoDigest->computeHash();
+            if (m_lastFrameDigest == digest)
+                return;
+            m_lastFrameDigest = digest;
+        }
+
+        if (m_screencastFramesInFlight > kMaxFramesInFlight)
+            return;
+        // Scale image to fit width / height
+        double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height());
+        if (scale < 1) {
+            SkBitmap dstBitmap;
+            dstBitmap.allocPixels(SkImageInfo::MakeN32Premul(displaySize.width() * scale, displaySize.height() * scale));
+            SkCanvas canvas(dstBitmap);
+            canvas.scale(scale, scale);
+            canvas.drawImage(image, 0, 0);
+            image = dstBitmap.asImage();
+        }
+
+        SkPixmap pixmap;
+        if (!image->peekPixels(&pixmap)) {
+            fprintf(stderr, "Failed to peek pixels from SkImage for JPEG encoding\n");
+            return;
+        }
+
+        SkJpegEncoder::Options options;
+        options.fQuality = 90;
+        SkDynamicMemoryWStream stream;
+        if (!SkJpegEncoder::Encode(&stream, pixmap, options)) {
+            fprintf(stderr, "Failed to encode image to JPEG\n");
+            return;
+        }
+        sk_sp<SkData> jpegData = stream.detachAsData();
+        String result = base64EncodeToString(std::span(reinterpret_cast<const unsigned char*>(jpegData->data()), jpegData->size()));
+        ++m_screencastFramesInFlight;
+        m_frontendDispatcher->screencastFrame(result, displaySize.width(), displaySize.height());
+    }
+}
+#endif
+
+#if USE(CAIRO) || PLATFORM(GTK)
+void InspectorScreencastAgent::didPaint(cairo_surface_t* surface)
+{
+#if PLATFORM(WPE)
+    // Get actual image size (in device pixels).
+    WebCore::IntSize displaySize(cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface));
+
+    WebCore::IntSize drawingAreaSize = m_page.drawingArea()->size();
+    drawingAreaSize.scale(m_page.deviceScaleFactor());
+    if (drawingAreaSize != displaySize) {
+        return;
+    }
+
+#else
+    WebCore::IntSize displaySize = m_page.drawingArea()->size();
+#endif
+    if (m_encoder)
+        m_encoder->encodeFrame(surface, displaySize);
+    if (m_screencast) {
+
+        {
+            // Do not send the same frame over and over.
+            unsigned char *data = cairo_image_surface_get_data(surface);
+            int stride = cairo_image_surface_get_stride(surface);
+            int height = cairo_image_surface_get_height(surface);
+            auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1);
+            cryptoDigest->addBytes(std::span(data, stride * height));
+            auto digest = cryptoDigest->computeHash();
+            if (m_lastFrameDigest == digest)
+                return;
+            m_lastFrameDigest = digest;
+        }
+
+        if (m_screencastFramesInFlight > kMaxFramesInFlight)
+            return;
+        // Scale image to fit width / height
+        double scale = std::min(m_screencastWidth / displaySize.width(), m_screencastHeight / displaySize.height());
+        RefPtr<cairo_surface_t> 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<cairo_t> cr = adoptRef(cairo_create(scaledSurface.get()));
+            cairo_transform(cr.get(), &transform);
+            cairo_set_source_surface(cr.get(), surface, 0, 0);
+            cairo_paint(cr.get());
+            surface = scaledSurface.get();
+        }
+        unsigned char *data = nullptr;
+        size_t len = 0;
+        cairo_image_surface_write_to_jpeg_mem(surface, &data, &len, m_screencastQuality);
+        String result = base64EncodeToString(std::span(data, len));
+        ++m_screencastFramesInFlight;
+        m_frontendDispatcher->screencastFrame(result, displaySize.width(), displaySize.height());
+    }
+}
+#endif
+
+Inspector::Protocol::ErrorStringOr<String /* screencastID */> InspectorScreencastAgent::startVideo(const String& file, int width, int height, int toolbarHeight)
+{
+    if (m_encoder)
+        return makeUnexpected("Already recording"_s);
+
+    if (width < 10 || width > 10000 || height < 10 || height > 10000)
+        return makeUnexpected("Invalid size"_s);
+
+    String errorString;
+    m_encoder = ScreencastEncoder::create(errorString, file, WebCore::IntSize(width, height));
+    if (!m_encoder)
+        return makeUnexpected(errorString);
+
+    m_currentScreencastID = createVersion4UUIDString();
+
+#if PLATFORM(MAC)
+    m_encoder->setOffsetTop(toolbarHeight);
+#endif
+
+    kickFramesStarted();
+    return { { m_currentScreencastID } };
+}
+
+void InspectorScreencastAgent::stopVideo(Ref<StopVideoCallback>&& 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<int /* generation */> 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<void> InspectorScreencastAgent::screencastFrameAck(int generation)
+{
+    if (m_screencastGeneration != generation)
+        return { };
+    --m_screencastFramesInFlight;
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorScreencastAgent::stopScreencast()
+{
+    if (!m_screencast)
+        return makeUnexpected("Not screencasting"_s);
+    m_screencast = false;
+    if (!m_encoder)
+      m_framesAreGoing = false;
+    return { };
+}
+
+void InspectorScreencastAgent::kickFramesStarted()
+{
+    if (!m_framesAreGoing) {
+        m_framesAreGoing = true;
+#if !PLATFORM(WPE)
+        scheduleFrameEncoding();
+#endif
+    }
+    m_page.updateRenderingWithForcedRepaint([] { });
+}
+
+#if !PLATFORM(WPE)
+void InspectorScreencastAgent::scheduleFrameEncoding()
+{
+    if (!m_encoder && !m_screencast)
+        return;
+
+    RunLoop::main().dispatchAfter(Seconds(1.0 / ScreencastEncoder::fps), [agent = WeakPtr { this }]() mutable {
+        if (!agent)
+            return;
+        if (!agent->m_page.hasPageClient())
+            return;
+
+        agent->encodeFrame();
+        agent->scheduleFrameEncoding();
+    });
+}
+#endif
+
+#if PLATFORM(MAC)
+void InspectorScreencastAgent::encodeFrame()
+{
+    if (!m_encoder && !m_screencast)
+        return;
+    RetainPtr<CGImageRef> 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<CGImageRef> transformedImageRef;
+        if (scale < 1 || m_screencastToolbarHeight) {
+            WebCore::IntSize screencastSize = displaySize;
+            WebCore::IntSize scaledImageSize = imageSize;
+            if (scale < 1) {
+                screencastSize.scale(scale);
+                scaledImageSize.scale(scale);
+            }
+            auto colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
+            auto context = adoptCF(CGBitmapContextCreate(nullptr, screencastSize.width(), screencastSize.height(), 8, 4 * screencastSize.width(), colorSpace.get(), (CGBitmapInfo)kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+            CGContextDrawImage(context.get(), CGRectMake(0, 0, scaledImageSize.width(), scaledImageSize.height()), imagePtr);
+            transformedImageRef = adoptCF(CGBitmapContextCreateImage(context.get()));
+            imagePtr = transformedImageRef.get();
+        }
+        auto data = WebCore::encodeData(imagePtr, "image/jpeg"_s, m_screencastQuality * 0.1);
+
+        // Do not send the same frame over and over.
+        auto cryptoDigest = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_1);
+        cryptoDigest->addBytes(std::span(data.data(), data.size()));
+        auto digest = cryptoDigest->computeHash();
+        if (m_lastFrameDigest != digest) {
+            String base64Data = base64EncodeToString(data);
+            ++m_screencastFramesInFlight;
+            m_frontendDispatcher->screencastFrame(base64Data, displaySize.width(), displaySize.height());
+            m_lastFrameDigest = digest;
+        }
+    }
+    if (m_encoder)
+        m_encoder->encodeFrame(WTFMove(imageRef));
+}
+#endif
+
+#if (USE(CAIRO) && !PLATFORM(WPE)) || PLATFORM(GTK)
+void InspectorScreencastAgent::encodeFrame()
+{
+    if (!m_encoder && !m_screencast)
+        return;
+
+    if (auto* drawingArea = m_page.drawingArea())
+        static_cast<DrawingAreaProxyCoordinatedGraphics*>(drawingArea)->captureFrame();
+}
+#endif
+
+} // namespace WebKit
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_END
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h
new file mode 100644
index 0000000000000000000000000000000000000000..f53bb59c65a4ced0360e473fb9ed9a36d1179310
--- /dev/null
+++ b/Source/WebKit/UIProcess/Inspector/Agents/InspectorScreencastAgent.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <JavaScriptCore/InspectorAgentBase.h>
+#include <JavaScriptCore/InspectorBackendDispatchers.h>
+#include <JavaScriptCore/InspectorFrontendDispatchers.h>
+
+#if USE(CAIRO) || PLATFORM(GTK)
+#include <cairo.h>
+#endif
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/WeakPtr.h>
+
+namespace Inspector {
+class BackendDispatcher;
+class FrontendChannel;
+class FrontendRouter;
+class ScreencastFrontendDispatcher;
+}
+
+namespace WebKit {
+class InspectorScreencastAgent;
+}
+
+namespace WTF {
+template<typename T> struct IsDeprecatedWeakRefSmartPointerException;
+template<> struct IsDeprecatedWeakRefSmartPointerException<WebKit::InspectorScreencastAgent> : std::true_type { };
+}
+
+namespace WebKit {
+
+class ScreencastEncoder;
+class WebPageProxy;
+
+class InspectorScreencastAgent : public Inspector::InspectorAgentBase, public Inspector::ScreencastBackendDispatcherHandler, public CanMakeWeakPtr<InspectorScreencastAgent> {
+    WTF_MAKE_NONCOPYABLE(InspectorScreencastAgent);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    InspectorScreencastAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page);
+    ~InspectorScreencastAgent() override;
+
+    void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override;
+    void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override;
+
+#if USE(SKIA) && !PLATFORM(GTK)
+    void didPaint(sk_sp<SkImage>&& surface);
+#endif
+#if USE(CAIRO) || PLATFORM(GTK)
+    void didPaint(cairo_surface_t*);
+#endif
+
+    Inspector::Protocol::ErrorStringOr<String /* screencastID */> startVideo(const String& file, int width, int height, int toolbarHeight) override;
+    void stopVideo(Ref<StopVideoCallback>&&) override;
+
+    Inspector::Protocol::ErrorStringOr<int /* generation */> startScreencast(int width, int height, int toolbarHeight, int quality) override;
+    Inspector::Protocol::ErrorStringOr<void> screencastFrameAck(int generation) override;
+    Inspector::Protocol::ErrorStringOr<void> stopScreencast() override;
+
+private:
+#if !PLATFORM(WPE)
+    void scheduleFrameEncoding();
+    void encodeFrame();
+#endif
+
+    void kickFramesStarted();
+
+    std::unique_ptr<Inspector::ScreencastFrontendDispatcher> m_frontendDispatcher;
+    Ref<Inspector::ScreencastBackendDispatcher> m_backendDispatcher;
+    WebPageProxy& m_page;
+    Vector<uint8_t> m_lastFrameDigest;
+    RefPtr<ScreencastEncoder> 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..760f6ab8714c45f0019e583970767ea40e35d818
--- /dev/null
+++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.cpp
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2010, The WebM Project authors. All rights reserved.
+ * Copyright (c) 2013 The Chromium Authors. All rights reserved.
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScreencastEncoder.h"
+
+#include "WebMFileWriter.h"
+#include <algorithm>
+#include <libyuv.h>
+#include <vpx/vp8.h>
+#include <vpx/vp8cx.h>
+#include <vpx/vpx_encoder.h>
+#include <wtf/Compiler.h>
+#include <wtf/RunLoop.h>
+#include <wtf/UniqueArray.h>
+#include <wtf/WorkQueue.h>
+#include <wtf/text/MakeString.h>
+#include <wtf/text/StringConcatenateNumbers.h>
+
+#if USE(SKIA) && !PLATFORM(GTK)
+#include <skia/core/SkBitmap.h>
+#include <skia/core/SkCanvas.h>
+#include <skia/core/SkData.h>
+#include <skia/core/SkImage.h>
+#endif
+
+#if USE(CAIRO) || PLATFORM(GTK)
+#include <WebCore/RefPtrCairo.h>
+#endif
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
+
+using namespace WebCore;
+
+namespace WebKit {
+
+namespace {
+
+struct VpxCodecDeleter {
+  void operator()(vpx_codec_ctx_t* codec) {
+    if (codec) {
+        vpx_codec_err_t ret = vpx_codec_destroy(codec);
+        if (ret != VPX_CODEC_OK)
+            fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(codec));
+    }
+  }
+};
+
+using ScopedVpxCodec = std::unique_ptr<vpx_codec_ctx_t, VpxCodecDeleter>;
+
+// 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<vpx_image_t>& out_image,
+                 std::unique_ptr<uint8_t[]>& out_image_buffer) {
+  std::unique_ptr<vpx_image_t> 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<uint8_t[]> 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<unsigned char*>(image_buffer.get());
+  image->planes[0] = uchar_buffer;
+  image->planes[1] = image->planes[0] + y_stride * y_rows;
+  image->planes[2] = image->planes[1] + uv_stride * uv_rows;
+  image->stride[0] = y_stride;
+  image->stride[1] = uv_stride;
+  image->stride[2] = uv_stride;
+
+  out_image = std::move(image);
+  out_image_buffer = std::move(image_buffer);
+}
+
+} // namespace
+
+class ScreencastEncoder::VPXFrame {
+    WTF_MAKE_NONCOPYABLE(VPXFrame);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+#if USE(SKIA) && !PLATFORM(GTK)
+    explicit VPXFrame(sk_sp<SkImage>&& surface)
+        : m_surface(WTFMove(surface))
+    { }
+#elif USE(CAIRO) || PLATFORM(GTK)
+    explicit VPXFrame(RefPtr<cairo_surface_t>&& surface)
+        : m_surface(WTFMove(surface))
+    { }
+#elif PLATFORM(MAC)
+    VPXFrame(RetainPtr<CGImageRef> windowImage, int offsetTop)
+        : m_windowImage(WTFMove(windowImage))
+        , m_offsetTop(offsetTop)
+    { }
+#endif
+
+    void setDuration(Seconds duration) { m_duration = duration; }
+    Seconds duration() const { return m_duration; }
+
+    void convertToVpxImage(vpx_image_t* image)
+    {
+#if USE(SKIA) && !PLATFORM(GTK)
+        // Convert the updated region to YUV ready for encoding.
+        SkImageInfo info = SkImageInfo::Make(m_surface->width(), m_surface->height(), kN32_SkColorType, kPremul_SkAlphaType);
+        int argb_stride = info.minRowBytes();
+        size_t bufferSize = info.computeByteSize(argb_stride);
+        UniqueArray<uint8_t> buffer = makeUniqueArray<uint8_t>(bufferSize);
+        uint8_t* argb_data = buffer.get();
+        if (!m_surface->readPixels(info, argb_data, argb_stride, 0, 0))
+            fprintf(stderr, "Read SkImage to ARGB buffer\n");
+#elif USE(CAIRO) || PLATFORM(GTK)
+        // Convert the updated region to YUV ready for encoding.
+        const uint8_t* argb_data = cairo_image_surface_get_data(m_surface.get());
+        int argb_stride = cairo_image_surface_get_stride(m_surface.get());
+#elif PLATFORM(MAC)
+        int argb_stride = image->w * 4;
+        UniqueArray<uint8_t> buffer = makeUniqueArray<uint8_t>(argb_stride * image->h);
+        uint8_t* argb_data = buffer.get();
+        ScreencastEncoder::imageToARGB(m_windowImage.get(), argb_data, image->w, image->h, m_offsetTop);
+#endif
+        const int y_stride = image->stride[0];
+        ASSERT(image->stride[1] == image->stride[2]);
+        const int uv_stride = image->stride[1];
+        uint8_t* y_data = image->planes[0];
+        uint8_t* u_data = image->planes[1];
+        uint8_t* v_data = image->planes[2];
+
+        // TODO: redraw only damaged regions?
+        libyuv::ARGBToI420(argb_data, argb_stride,
+                            y_data, y_stride,
+                            u_data, uv_stride,
+                            v_data, uv_stride,
+                            image->w, image->h);
+    }
+
+private:
+#if USE(SKIA) && !PLATFORM(GTK)
+    sk_sp<SkImage> m_surface;
+#elif USE(CAIRO) || PLATFORM(GTK)
+    RefPtr<cairo_surface_t> m_surface;
+#elif PLATFORM(MAC)
+    RetainPtr<CGImageRef> m_windowImage;
+    int m_offsetTop { 0 };
+#endif
+    Seconds m_duration;
+};
+
+
+class ScreencastEncoder::VPXCodec {
+public:
+    VPXCodec(ScopedVpxCodec codec, vpx_codec_enc_cfg_t cfg, FILE* file)
+        : m_encoderQueue(WorkQueue::create("Screencast encoder"_s))
+        , m_codec(WTFMove(codec))
+        , m_cfg(cfg)
+        , m_file(file)
+        , m_writer(new WebMFileWriter(file, &m_cfg))
+    {
+        createImage(cfg.g_w, cfg.g_h, m_image, m_imageBuffer);
+    }
+
+    void encodeFrameAsync(std::unique_ptr<VPXFrame>&& 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<int>(1, frameCount * timeScale));
+        });
+    }
+
+    void finishAsync(Function<void()>&& callback)
+    {
+        m_encoderQueue->dispatch([this, callback = WTFMove(callback)] {
+            finish();
+            callback();
+        });
+    }
+
+private:
+    bool encodeFrame(vpx_image_t *img, int duration)
+    {
+        vpx_codec_iter_t iter = nullptr;
+        const vpx_codec_cx_pkt_t *pkt = nullptr;
+        int flags = 0;
+        const vpx_codec_err_t res = vpx_codec_encode(m_codec.get(), img, m_pts, duration, flags, VPX_DL_REALTIME);
+        if (res != VPX_CODEC_OK) {
+            fprintf(stderr, "Failed to encode frame: %s\n", vpx_codec_error(m_codec.get()));
+            return false;
+        }
+
+        bool gotPkts = false;
+        while ((pkt = vpx_codec_get_cx_data(m_codec.get(), &iter)) != nullptr) {
+            gotPkts = true;
+
+            if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
+                if (!m_writer->writeFrame(pkt)) {
+                    fprintf(stderr, "Failed to write compressed frame\n");
+                    return false;
+                }
+                ++m_frameCount;
+                m_pts += pkt->data.frame.duration;
+            }
+        }
+
+        return gotPkts;
+    }
+
+    void finish()
+    {
+        // Flush encoder.
+        while (encodeFrame(nullptr, 1))
+            ++m_frameCount;
+
+        m_writer->finish();
+        fclose(m_file);
+    }
+
+    Ref<WorkQueue> m_encoderQueue;
+    ScopedVpxCodec m_codec;
+    vpx_codec_enc_cfg_t m_cfg;
+    FILE* m_file { nullptr };
+    std::unique_ptr<WebMFileWriter> m_writer;
+    int m_frameCount { 0 };
+    int64_t m_pts { 0 };
+    std::unique_ptr<uint8_t[]> m_imageBuffer;
+    std::unique_ptr<vpx_image_t> m_image;
+};
+
+ScreencastEncoder::ScreencastEncoder(std::unique_ptr<VPXCodec>&& vpxCodec, IntSize size)
+    : m_vpxCodec(WTFMove(vpxCodec))
+    , m_size(size)
+{
+    ASSERT(!size.isZero());
+}
+
+ScreencastEncoder::~ScreencastEncoder()
+{
+}
+
+RefPtr<ScreencastEncoder> ScreencastEncoder::create(String& errorString, const String& filePath, IntSize size)
+{
+    vpx_codec_iface_t* codec_interface = vpx_codec_vp8_cx();
+    if (!codec_interface) {
+        errorString = "Codec not found."_s;
+        return nullptr;
+    }
+
+    if (size.width() <= 0 || size.height() <= 0 || (size.width() % 2) != 0 || (size.height() % 2) != 0) {
+        errorString = makeString("Invalid frame size: "_s, size.width(), "x"_s, size.height());
+        return nullptr;
+    }
+
+    vpx_codec_enc_cfg_t cfg;
+    memset(&cfg, 0, sizeof(cfg));
+    vpx_codec_err_t error = vpx_codec_enc_config_default(codec_interface, &cfg, 0);
+    if (error) {
+        errorString = makeString("Failed to get default codec config: "_s, span(vpx_codec_err_to_string(error)));
+        return nullptr;
+    }
+
+    cfg.g_w = size.width();
+    cfg.g_h = size.height();
+    cfg.g_timebase.num = 1;
+    cfg.g_timebase.den = fps * timeScale;
+    cfg.g_error_resilient = VPX_ERROR_RESILIENT_DEFAULT;
+
+    ScopedVpxCodec codec(new vpx_codec_ctx_t);
+    if (vpx_codec_enc_init(codec.get(), codec_interface, &cfg, 0)) {
+        errorString = makeString("Failed to initialize encoder: "_s, span(vpx_codec_error(codec.get())));
+        return nullptr;
+    }
+
+    FILE* file = fopen(filePath.utf8().data(), "wb");
+    if (!file) {
+        errorString = makeString("Failed to open file '"_s, filePath, "' for writing: "_s, span(strerror(errno)));
+        return nullptr;
+    }
+
+    std::unique_ptr<VPXCodec> vpxCodec(new VPXCodec(WTFMove(codec), cfg, file));
+    return adoptRef(new ScreencastEncoder(WTFMove(vpxCodec), size));
+}
+
+void ScreencastEncoder::flushLastFrame()
+{
+    MonotonicTime now = MonotonicTime::now();
+    if (m_lastFrameTimestamp) {
+        // If previous frame encoding failed for some rason leave the timestampt intact.
+        if (!m_lastFrame)
+            return;
+
+        Seconds seconds = now - m_lastFrameTimestamp;
+        m_lastFrame->setDuration(seconds);
+        m_vpxCodec->encodeFrameAsync(WTFMove(m_lastFrame));
+    }
+    m_lastFrameTimestamp = now;
+}
+
+#if USE(SKIA) && !PLATFORM(GTK)
+void ScreencastEncoder::encodeFrame(sk_sp<SkImage>&& image, IntSize size)
+{
+    flushLastFrame();
+    // Note that in WPE drawing area size is updated asynchronously and may differ from acutal
+    // size of the surface.
+    if (size.isZero()) {
+        return;
+    }
+    SkBitmap surface;
+    surface.allocPixels(SkImageInfo::Make(m_size.width(), m_size.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType));
+    SkCanvas canvas(surface);
+    SkMatrix transform;
+    if (size.width() > m_size.width() || size.height() > m_size.height()) {
+        // If no scale is specified shrink to fit the frame.
+        double scale = std::min(static_cast<double>(m_size.width()) / size.width(),
+                                static_cast<double>(m_size.height()) / size.height());
+        transform.setScale(scale, scale);
+        canvas.setMatrix(transform);
+    }
+    // Record top left part of the drawing area that fits into the frame.
+    canvas.drawImage(image, 0, 0);
+    m_lastFrame = makeUnique<VPXFrame>(surface.asImage());
+}
+#elif USE(CAIRO) || PLATFORM(GTK)
+void ScreencastEncoder::encodeFrame(cairo_surface_t* drawingAreaSurface, IntSize size)
+{
+    flushLastFrame();
+    // Note that in WPE drawing area size is updated asynchronously and may differ from acutal
+    // size of the surface.
+    if (size.isZero()) {
+        return;
+    }
+
+    RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_size.width(), m_size.height()));
+    {
+        RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
+
+        cairo_matrix_t transform;
+        if (size.width() > m_size.width() || size.height() > m_size.height()) {
+            // If no scale is specified shrink to fit the frame.
+            double scale = std::min(static_cast<double>(m_size.width()) / size.width(),
+                                    static_cast<double>(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<VPXFrame>(WTFMove(surface));
+}
+#elif PLATFORM(MAC)
+void ScreencastEncoder::encodeFrame(RetainPtr<CGImageRef>&& windowImage)
+{
+    flushLastFrame();
+
+    m_lastFrame = makeUnique<VPXFrame>(WTFMove(windowImage), m_offsetTop);
+}
+#endif
+
+void ScreencastEncoder::finish(Function<void()>&& callback)
+{
+    if (!m_vpxCodec) {
+        callback();
+        return;
+    }
+
+    flushLastFrame();
+    m_vpxCodec->finishAsync([protectRef = Ref { *this }, callback = WTFMove(callback)] () mutable {
+        RunLoop::main().dispatch([callback = WTFMove(callback)] {
+            callback();
+        });
+    });
+}
+
+
+} // namespace WebKit
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_END
diff --git a/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..caf0474267c1bda6346f7b025b6646bb4f1b56d9
--- /dev/null
+++ b/Source/WebKit/UIProcess/Inspector/Agents/ScreencastEncoder.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <WebCore/IntSize.h>
+#include <wtf/Forward.h>
+#include <wtf/MonotonicTime.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/ThreadSafeRefCounted.h>
+#include <wtf/WeakPtr.h>
+
+#if USE(CAIRO) || PLATFORM(GTK)
+#include <cairo.h>
+#endif
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class ScreencastEncoder : public ThreadSafeRefCounted<ScreencastEncoder> {
+    WTF_MAKE_NONCOPYABLE(ScreencastEncoder);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    static constexpr int fps = 25;
+
+    static RefPtr<ScreencastEncoder> create(String& errorString, const String& filePath, WebCore::IntSize);
+
+    class VPXCodec;
+    ScreencastEncoder(std::unique_ptr<VPXCodec>&&, WebCore::IntSize);
+    ~ScreencastEncoder();
+
+#if USE(SKIA) && !PLATFORM(GTK)
+    void encodeFrame(sk_sp<SkImage>&&, WebCore::IntSize);
+#elif USE(CAIRO) || PLATFORM(GTK)
+    void encodeFrame(cairo_surface_t*, WebCore::IntSize);
+#elif PLATFORM(MAC)
+    void encodeFrame(RetainPtr<CGImageRef>&&);
+    void setOffsetTop(int offset) { m_offsetTop = offset;}
+#endif
+
+    void finish(Function<void()>&& callback);
+
+private:
+    void flushLastFrame();
+#if PLATFORM(MAC)
+    static void imageToARGB(CGImageRef, uint8_t* rgba_data, int width, int height, int offsetTop);
+#endif
+
+    std::unique_ptr<VPXCodec> m_vpxCodec;
+    const WebCore::IntSize m_size;
+    MonotonicTime m_lastFrameTimestamp;
+    class VPXFrame;
+    std::unique_ptr<VPXFrame> 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 <string>
+#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<int>(m_cfg->g_w), static_cast<int>(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<uint8_t*>(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 <memory>
+#include <stdio.h>
+#include <stdlib.h>
+#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<mkvmuxer::MkvWriter> m_writer;
+    std::unique_ptr<mkvmuxer::Segment> 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 77bdb25abf77bc0f7f00d3dbd57b0eb751c99488..6d3a93a009cff0f70f2b1a1e674827c24a26a947 100644
--- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp
+++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.cpp
@@ -28,7 +28,7 @@
 
 #include "MessageSenderInlines.h"
 #include "ProvisionalPageProxy.h"
-#include "WebFrameProxy.h"
+#include "WebPageInspectorController.h"
 #include "WebPageInspectorTarget.h"
 #include "WebPageMessages.h"
 #include "WebPageProxy.h"
@@ -46,13 +46,13 @@ std::unique_ptr<InspectorTargetProxy> InspectorTargetProxy::create(WebPageProxy&
     return makeUnique<InspectorTargetProxy>(page, targetId, type);
 }
 
-std::unique_ptr<InspectorTargetProxy> InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId, Inspector::InspectorTargetType type)
+std::unique_ptr<InspectorTargetProxy> InspectorTargetProxy::create(ProvisionalPageProxy& provisionalPage, const String& targetId)
 {
     RefPtr page = provisionalPage.page();
     if (!page)
         return nullptr;
 
-    auto target = InspectorTargetProxy::create(*page, targetId, type);
+    auto target = InspectorTargetProxy::create(*page, targetId, Inspector::InspectorTargetType::Page);
     target->m_provisionalPage = provisionalPage;
     return target;
 }
@@ -105,6 +105,31 @@ void InspectorTargetProxy::didCommitProvisionalTarget()
     m_provisionalPage = nullptr;
 }
 
+void InspectorTargetProxy::willResume()
+{
+    if (m_page->hasRunningProcess())
+        m_page->legacyMainFrameProcess().send(Messages::WebPage::ResumeInspectorIfPausedInNewWindow(), m_page->webPageIDInMainFrameProcess());
+}
+
+void InspectorTargetProxy::activate(String& error)
+{
+    if (m_type != Inspector::InspectorTargetType::Page)
+        return InspectorTarget::activate(error);
+
+    platformActivate(error);
+}
+
+void InspectorTargetProxy::close(String& error, bool runBeforeUnload)
+{
+    if (m_type != Inspector::InspectorTargetType::Page)
+        return InspectorTarget::close(error, runBeforeUnload);
+
+    if (runBeforeUnload)
+        m_page->tryClose();
+    else
+        m_page->closePage();
+}
+
 bool InspectorTargetProxy::isProvisional() const
 {
     return !!m_provisionalPage;
diff --git a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h
index edd6e7f1799279ed3d0eb81b6c2eef9f5b375134..d4231f84f3c52641f4d9e88559e8e1a4845b7163 100644
--- a/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h
+++ b/Source/WebKit/UIProcess/Inspector/InspectorTargetProxy.h
@@ -38,12 +38,12 @@ class WebPageProxy;
 // NOTE: This UIProcess side InspectorTarget doesn't care about the frontend channel, since
 // any target -> frontend messages will be routed to the WebPageProxy with a targetId.
 
-class InspectorTargetProxy final : public Inspector::InspectorTarget {
+class InspectorTargetProxy : public Inspector::InspectorTarget {
     WTF_MAKE_TZONE_ALLOCATED(InspectorTargetProxy);
     WTF_MAKE_NONCOPYABLE(InspectorTargetProxy);
 public:
     static std::unique_ptr<InspectorTargetProxy> create(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType);
-    static std::unique_ptr<InspectorTargetProxy> create(ProvisionalPageProxy&, const String& targetId, Inspector::InspectorTargetType);
+    static std::unique_ptr<InspectorTargetProxy> create(ProvisionalPageProxy&, const String& targetId);
     InspectorTargetProxy(WebPageProxy&, const String& targetId, Inspector::InspectorTargetType);
     ~InspectorTargetProxy() = default;
 
@@ -56,8 +56,13 @@ public:
     void connect(Inspector::FrontendChannel::ConnectionType) override;
     void disconnect() override;
     void sendMessageToTargetBackend(const String&) override;
+    void activate(String& error) override;
+    void close(String& error, bool runBeforeUnload) override;
 
 private:
+    void willResume() override;
+    void platformActivate(String& error) const;
+
     WeakRef<WebPageProxy> m_page;
     String m_identifier;
     Inspector::InspectorTargetType m_type;
diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.cpp
index e4f2f719746ed69b1226be2d47b16666f2067772..c0e4452b9c8e286e1944b47e46acf49bdaee439a 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 <WebCore/ResourceError.h>
+#include <WebCore/WindowFeatures.h>
 #include <JavaScriptCore/InspectorAgentBase.h>
 #include <JavaScriptCore/InspectorBackendDispatcher.h>
 #include <JavaScriptCore/InspectorBackendDispatchers.h>
@@ -52,34 +60,121 @@ static String getTargetID(const ProvisionalPageProxy& provisionalPage)
 
 WTF_MAKE_TZONE_ALLOCATED_IMPL(WebPageInspectorController);
 
+WebPageInspectorControllerObserver* WebPageInspectorController::s_observer = nullptr;
+
+void WebPageInspectorController::setObserver(WebPageInspectorControllerObserver* observer)
+{
+    s_observer = observer;
+}
+
+WebPageInspectorControllerObserver* WebPageInspectorController::observer() {
+    return s_observer;
+}
+
 WebPageInspectorController::WebPageInspectorController(WebPageProxy& inspectedPage)
     : m_frontendRouter(FrontendRouter::create())
     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
     , m_inspectedPage(inspectedPage)
 {
-    auto targetAgent = makeUnique<InspectorTargetAgent>(m_frontendRouter.get(), m_backendDispatcher.get());
-    m_targetAgent = targetAgent.get();
-    m_agents.append(WTFMove(targetAgent));
 }
 
 WebPageInspectorController::~WebPageInspectorController() = default;
 
-Ref<WebPageProxy> WebPageInspectorController::protectedInspectedPage()
+WeakRef<WebPageProxy> WebPageInspectorController::protectedInspectedPage()
 {
-    return m_inspectedPage.get();
+    return m_inspectedPage;
 }
 
 void WebPageInspectorController::init()
 {
+    auto targetAgent = makeUnique<InspectorTargetAgent>(m_frontendRouter.get(), m_backendDispatcher.get());
+    m_targetAgent = targetAgent.get();
+    m_agents.append(WTFMove(targetAgent));
+    auto emulationAgent = makeUnique<WebPageInspectorEmulationAgent>(m_backendDispatcher.get(), m_inspectedPage);
+    m_emulationAgent = emulationAgent.get();
+    m_agents.append(WTFMove(emulationAgent));
+    auto inputAgent = makeUnique<WebPageInspectorInputAgent>(m_backendDispatcher.get(), m_inspectedPage);
+    m_inputAgent = inputAgent.get();
+    m_agents.append(WTFMove(inputAgent));
+    m_agents.append(makeUnique<InspectorDialogAgent>(m_backendDispatcher.get(), m_frontendRouter.get(), m_inspectedPage));
+    auto screencastAgent = makeUnique<InspectorScreencastAgent>(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->webPageIDInMainFrameProcess());
     createInspectorTarget(pageTargetId, Inspector::InspectorTargetType::Page);
 }
 
+void WebPageInspectorController::didFinishAttachingToWebProcess()
+{
+    String pageTargetID = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess());
+    // Create target only after attaching to a Web Process first time. Before that
+    // we cannot event establish frontend connection.
+    if (m_targets.contains(pageTargetID))
+        return;
+    createInspectorTarget(pageTargetID, Inspector::InspectorTargetType::Page);
+}
+
 void WebPageInspectorController::pageClosed()
 {
+    String pageTargetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess());
+    destroyInspectorTarget(pageTargetId);
+
     disconnectAllFrontends();
 
     m_agents.discardValues();
+
+    if (s_observer)
+        s_observer->willDestroyInspectorController(m_inspectedPage);
+}
+
+bool WebPageInspectorController::pageCrashed(ProcessTerminationReason reason)
+{
+    if (reason != ProcessTerminationReason::Crash)
+        return false;
+    String targetId = WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess());
+    auto it = m_targets.find(targetId);
+    if (it == m_targets.end())
+        return false;
+    m_targetAgent->targetCrashed(*it->value);
+    m_targets.remove(it);
+
+    return m_targetAgent->isConnected();
+}
+
+void WebPageInspectorController::willCreateNewPage(const WebCore::WindowFeatures& features, const URL& url)
+{
+    if (s_observer)
+        s_observer->willCreateNewPage(m_inspectedPage, features, url);
+}
+
+void WebPageInspectorController::didShowPage()
+{
+    if (m_frontendRouter->hasFrontends())
+        m_emulationAgent->didShowPage();
+}
+
+void WebPageInspectorController::didProcessAllPendingKeyboardEvents()
+{
+    if (m_frontendRouter->hasFrontends())
+        m_inputAgent->didProcessAllPendingKeyboardEvents();
+}
+
+void WebPageInspectorController::didProcessAllPendingMouseEvents()
+{
+    if (m_frontendRouter->hasFrontends())
+        m_inputAgent->didProcessAllPendingMouseEvents();
+}
+
+void WebPageInspectorController::didProcessAllPendingWheelEvents()
+{
+    if (m_frontendRouter->hasFrontends())
+        m_inputAgent->didProcessAllPendingWheelEvents();
 }
 
 bool WebPageInspectorController::hasLocalFrontend() const
@@ -93,6 +188,17 @@ void WebPageInspectorController::connectFrontend(Inspector::FrontendChannel& fro
 
     bool connectingFirstFrontend = !m_frontendRouter->hasFrontends();
 
+    // HACK: forcefully disconnect remote connections to show local inspector starting with initial
+    // agents' state.
+    if (frontendChannel.connectionType() == Inspector::FrontendChannel::ConnectionType::Local &&
+        !connectingFirstFrontend && !m_frontendRouter->hasLocalFrontend()) {
+        disconnectAllFrontends();
+        connectingFirstFrontend = true;
+    }
+
+    if (connectingFirstFrontend)
+        adjustPageSettings();
+
     m_frontendRouter->connectFrontend(frontendChannel);
 
     if (connectingFirstFrontend)
@@ -112,8 +218,10 @@ void WebPageInspectorController::disconnectFrontend(FrontendChannel& frontendCha
     m_frontendRouter->disconnectFrontend(frontendChannel);
 
     bool disconnectingLastFrontend = !m_frontendRouter->hasFrontends();
-    if (disconnectingLastFrontend)
+    if (disconnectingLastFrontend) {
         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
+        m_pendingNavigations.clear();
+    }
 
     auto inspectedPage = protectedInspectedPage();
     inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
@@ -137,6 +245,8 @@ void WebPageInspectorController::disconnectAllFrontends()
     // Disconnect any remaining remote frontends.
     m_frontendRouter->disconnectAllFrontends();
 
+    m_pendingNavigations.clear();
+
     auto inspectedPage = protectedInspectedPage();
     inspectedPage->didChangeInspectorFrontendCount(m_frontendRouter->frontendCount());
 
@@ -165,6 +275,75 @@ void WebPageInspectorController::setIndicating(bool indicating)
 }
 #endif
 
+#if USE(SKIA) && !PLATFORM(GTK)
+void WebPageInspectorController::didPaint(sk_sp<SkImage>&& surface)
+{
+    if (!m_frontendRouter->hasFrontends())
+        return;
+
+    m_screecastAgent->didPaint(WTFMove(surface));
+}
+#endif
+#if USE(CAIRO) || PLATFORM(GTK)
+void WebPageInspectorController::didPaint(cairo_surface_t* surface)
+{
+    if (!m_frontendRouter->hasFrontends())
+        return;
+
+    m_screecastAgent->didPaint(surface);
+}
+#endif
+
+
+void WebPageInspectorController::navigate(WebCore::ResourceRequest&& request, WebFrameProxy* frame, NavigationHandler&& completionHandler)
+{
+    auto navigation = m_inspectedPage->loadRequestForInspector(WTFMove(request), frame);
+    if (!navigation) {
+        completionHandler("Failed to navigate"_s, { });
+        return;
+    }
+
+    m_pendingNavigations.set(navigation->navigationID(), WTFMove(completionHandler));
+}
+
+void WebPageInspectorController::didReceivePolicyDecision(WebCore::PolicyAction action, std::optional<WebCore::NavigationIdentifier> navigationID)
+{
+    if (!m_frontendRouter->hasFrontends())
+        return;
+
+    if (!navigationID)
+        return;
+
+    auto completionHandler = m_pendingNavigations.take(*navigationID);
+    if (!completionHandler)
+        return;
+
+    if (action == WebCore::PolicyAction::Ignore)
+        completionHandler("Navigation cancelled"_s, { });
+    else
+        completionHandler(String(), *navigationID);
+}
+
+void WebPageInspectorController::didDestroyNavigation(WebCore::NavigationIdentifier navigationID)
+{
+    if (!m_frontendRouter->hasFrontends())
+        return;
+
+    auto completionHandler = m_pendingNavigations.take(navigationID);
+    if (!completionHandler)
+        return;
+
+    // Inspector initiated navigation is destroyed before policy check only when it
+    // becomes a fragment navigation (which always reuses current navigation).
+    completionHandler(String(), { });
+}
+
+void WebPageInspectorController::didFailProvisionalLoadForFrame(WebCore::NavigationIdentifier navigationID, const WebCore::ResourceError& error)
+{
+    if (s_observer)
+        s_observer->didFailProvisionalLoad(m_inspectedPage, navigationID, error.localizedDescription());
+}
+
 void WebPageInspectorController::createInspectorTarget(const String& targetId, Inspector::InspectorTargetType type)
 {
     addTarget(InspectorTargetProxy::create(protectedInspectedPage(), targetId, type));
@@ -184,6 +363,48 @@ void WebPageInspectorController::sendMessageToInspectorFrontend(const String& ta
     m_targetAgent->sendMessageFromTargetToFrontend(targetId, message);
 }
 
+void WebPageInspectorController::setPauseOnStart(bool shouldPause)
+{
+    ASSERT(m_frontendRouter->hasFrontends());
+    m_targetAgent->setPauseOnStart(shouldPause);
+}
+
+bool WebPageInspectorController::shouldPauseLoadRequest() const
+{
+    if (!m_frontendRouter->hasFrontends())
+        return false;
+
+    if (!m_inspectedPage->isPageOpenedByDOMShowingInitialEmptyDocument())
+        return false;
+
+    auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()));
+    // The method is expeted to be called only when the WebPage has already been
+    // initilized, so the target must exist.
+    ASSERT(target);
+    return target->isPaused();
+}
+
+bool WebPageInspectorController::shouldPauseInInspectorWhenShown() const
+{
+    if (!m_frontendRouter->hasFrontends())
+        return false;
+
+    if (!m_inspectedPage->isPageOpenedByDOMShowingInitialEmptyDocument())
+        return false;
+
+    // The method is called from WebPageProxy::initializePage and the
+    // target is not created yet (it is created after the new page is
+    //  initialized and attached to the process).
+    return m_targetAgent->shouldPauseOnStart();
+}
+
+void WebPageInspectorController::setContinueLoadingCallback(WTF::Function<void()>&& callback)
+{
+    auto* target = m_targets.get(WebPageInspectorTarget::toTargetID(m_inspectedPage->webPageIDInMainFrameProcess()));
+    ASSERT(target);
+    target->setResumeCallback(WTFMove(callback));
+}
+
 bool WebPageInspectorController::shouldPauseLoading(const ProvisionalPageProxy& provisionalPage) const
 {
     if (!m_frontendRouter->hasFrontends())
@@ -203,7 +424,7 @@ void WebPageInspectorController::setContinueLoadingCallback(const ProvisionalPag
 
 void WebPageInspectorController::didCreateProvisionalPage(ProvisionalPageProxy& provisionalPage)
 {
-    addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage), Inspector::InspectorTargetType::Page));
+    addTarget(InspectorTargetProxy::create(provisionalPage, getTargetID(provisionalPage)));
 }
 
 void WebPageInspectorController::willDestroyProvisionalPage(const ProvisionalPageProxy& provisionalPage)
@@ -287,4 +508,30 @@ void WebPageInspectorController::browserExtensionsDisabled(HashSet<String>&& 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);
+    }
+
+    // Disable local storage partitioning. See https://github.com/microsoft/playwright/issues/32230
+    m_inspectedPage->preferences().setStorageBlockingPolicy(static_cast<uint32_t>(WebCore::StorageBlockingPolicy::AllowAll));
+}
+
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h
index 29457fc3c76c963bf50b44c011f64398efbae676..b931b09dbf2768bdfa49633fc6329fb49b09205a 100644
--- a/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h
+++ b/Source/WebKit/UIProcess/Inspector/WebPageInspectorController.h
@@ -26,19 +26,43 @@
 #pragma once
 
 #include "InspectorTargetProxy.h"
+#include "ProcessTerminationReason.h"
 #include <JavaScriptCore/InspectorAgentRegistry.h>
 #include <JavaScriptCore/InspectorTargetAgent.h>
+#include <WebCore/NavigationIdentifier.h>
 #include <WebCore/PageIdentifier.h>
 #include <wtf/CheckedRef.h>
 #include <wtf/Forward.h>
 #include <wtf/Noncopyable.h>
 #include <wtf/TZoneMalloc.h>
 #include <wtf/text/WTFString.h>
+#include <wtf/URL.h>
+
+#if USE(SKIA)
+#include <skia/core/SkData.h>
+#include <skia/core/SkImage.h>
+#endif
+
+#if USE(CAIRO) || PLATFORM(GTK)
+#include <cairo.h>
+#endif
 
 namespace Inspector {
 class BackendDispatcher;
 class FrontendChannel;
 class FrontendRouter;
+class InspectorTarget;
+}
+
+namespace WebCore {
+class ResourceError;
+class ResourceRequest;
+enum class PolicyAction : uint8_t;
+struct WindowFeatures;
+}
+
+namespace PAL {
+class SessionID;
 }
 
 namespace WebKit {
@@ -46,6 +70,23 @@ namespace WebKit {
 class InspectorBrowserAgent;
 struct WebPageAgentContext;
 
+class InspectorScreencastAgent;
+class WebFrameProxy;
+class WebPageInspectorEmulationAgent;
+class WebPageInspectorInputAgent;
+
+class WebPageInspectorControllerObserver {
+public:
+    virtual void didCreateInspectorController(WebPageProxy&) = 0;
+    virtual void willDestroyInspectorController(WebPageProxy&) = 0;
+    virtual void didFailProvisionalLoad(WebPageProxy&, WebCore::NavigationIdentifier, const String& error) = 0;
+    virtual void willCreateNewPage(WebPageProxy&, const WebCore::WindowFeatures&, const URL&) = 0;
+    virtual void didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) = 0;
+
+protected:
+    virtual ~WebPageInspectorControllerObserver() = default;
+};
+
 class WebPageInspectorController {
     WTF_MAKE_TZONE_ALLOCATED(WebPageInspectorController);
     WTF_MAKE_NONCOPYABLE(WebPageInspectorController);
@@ -54,7 +95,21 @@ public:
     ~WebPageInspectorController();
 
     void init();
+    void 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();
+    void didProcessAllPendingWheelEvents();
 
     bool hasLocalFrontend() const;
 
@@ -67,11 +122,30 @@ public:
 #if ENABLE(REMOTE_INSPECTOR)
     void setIndicating(bool);
 #endif
+#if USE(SKIA) && !PLATFORM(GTK)
+    void didPaint(sk_sp<SkImage>&&);
+#endif
+#if USE(CAIRO) || PLATFORM(GTK)
+    void didPaint(cairo_surface_t*);
+#endif
+    using NavigationHandler = Function<void(const String&, Markable<WebCore::NavigationIdentifier>)>;
+    void navigate(WebCore::ResourceRequest&&, WebFrameProxy*, NavigationHandler&&);
+    void didReceivePolicyDecision(WebCore::PolicyAction action, std::optional<WebCore::NavigationIdentifier> navigationID);
+
+    void didDestroyNavigation(WebCore::NavigationIdentifier navigationID);
+
+    void didFailProvisionalLoadForFrame(WebCore::NavigationIdentifier navigationID, const WebCore::ResourceError& error);
 
     void createInspectorTarget(const String& targetId, Inspector::InspectorTargetType);
     void destroyInspectorTarget(const String& targetId);
     void sendMessageToInspectorFrontend(const String& targetId, const String& message);
 
+    void setPauseOnStart(bool);
+
+    bool shouldPauseLoadRequest() const;
+    bool shouldPauseInInspectorWhenShown() const;
+    void setContinueLoadingCallback(WTF::Function<void()>&&);
+
     bool shouldPauseLoading(const ProvisionalPageProxy&) const;
     void setContinueLoadingCallback(const ProvisionalPageProxy&, WTF::Function<void()>&&);
 
@@ -86,11 +160,12 @@ public:
     void browserExtensionsDisabled(HashSet<String>&&);
 
 private:
-    Ref<WebPageProxy> protectedInspectedPage();
+    WeakRef<WebPageProxy> protectedInspectedPage();
     WebPageAgentContext webPageAgentContext();
     void createLazyAgents();
 
     void addTarget(std::unique_ptr<InspectorTargetProxy>&&);
+    void adjustPageSettings();
 
     Ref<Inspector::FrontendRouter> m_frontendRouter;
     Ref<Inspector::BackendDispatcher> m_backendDispatcher;
@@ -101,9 +176,16 @@ private:
     CheckedPtr<Inspector::InspectorTargetAgent> m_targetAgent;
     HashMap<String, std::unique_ptr<InspectorTargetProxy>> m_targets;
 
+    WebPageInspectorEmulationAgent* m_emulationAgent { nullptr };
+    WebPageInspectorInputAgent* m_inputAgent { nullptr };
+    InspectorScreencastAgent* m_screecastAgent { nullptr };
+
     CheckedPtr<InspectorBrowserAgent> m_enabledBrowserAgent;
 
     bool m_didCreateLazyAgents { false };
+    UncheckedKeyHashMap<WebCore::NavigationIdentifier, NavigationHandler> m_pendingNavigations;
+
+    static WebPageInspectorControllerObserver* s_observer;
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm b/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..6a04ee480bc3a8270a7de20b1cd0da718242b4c1
--- /dev/null
+++ b/Source/WebKit/UIProcess/Inspector/mac/ScreencastEncoderMac.mm
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ScreencastEncoder.h"
+
+#include <algorithm>
+#include <CoreGraphics/CoreGraphics.h>
+#include <wtf/RetainPtr.h>
+
+namespace WebKit {
+
+void ScreencastEncoder::imageToARGB(CGImageRef image, uint8_t* argb_data, int width, int height, int offsetTop)
+{
+    size_t bitsPerComponent = 8;
+    size_t bytesPerPixel = 4;
+    size_t bytesPerRow = bytesPerPixel * width;
+    RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
+    RetainPtr<CGContextRef> context = adoptCF(CGBitmapContextCreate(argb_data, width, height, bitsPerComponent, bytesPerRow, colorSpace.get(), (CGBitmapInfo)kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little));
+    double imageWidth = CGImageGetWidth(image);
+    double imageHeight = CGImageGetHeight(image);
+    double pageHeight = imageHeight - offsetTop;
+    double ratio = 1;
+    if (imageWidth > width || pageHeight > height) {
+        ratio = std::min(width / imageWidth, height / pageHeight);
+    }
+    imageWidth *= ratio;
+    imageHeight *= ratio;
+    pageHeight *= ratio;
+    CGContextDrawImage(context.get(), CGRectMake(0, height - pageHeight, imageWidth, imageHeight), image);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/InspectorDialogAgent.cpp b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..663f92f0df76042cf6385b056f8a917d688259f9
--- /dev/null
+++ b/Source/WebKit/UIProcess/InspectorDialogAgent.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorDialogAgent.h"
+
+#include "APINavigation.h"
+#include "APIUIClient.h"
+#include "WebPageProxy.h"
+#include <JavaScriptCore/InspectorFrontendRouter.h>
+
+
+namespace WebKit {
+
+using namespace Inspector;
+
+InspectorDialogAgent::InspectorDialogAgent(Inspector::BackendDispatcher& backendDispatcher, Inspector::FrontendRouter& frontendRouter, WebPageProxy& page)
+    : InspectorAgentBase("Dialog"_s)
+    , m_frontendDispatcher(makeUnique<DialogFrontendDispatcher>(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<void> InspectorDialogAgent::enable()
+{
+    if (m_page.inspectorDialogAgent())
+        return makeUnexpected("Dialog domain is already enabled."_s);
+
+    m_page.setInspectorDialogAgent(this);
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorDialogAgent::disable()
+{
+    if (m_page.inspectorDialogAgent() != this)
+        return { };
+
+    m_page.setInspectorDialogAgent(nullptr);
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> 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 <JavaScriptCore/InspectorAgentBase.h>
+#include <JavaScriptCore/InspectorBackendDispatchers.h>
+#include <JavaScriptCore/InspectorFrontendDispatchers.h>
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+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<void> enable() override;
+    Inspector::Protocol::ErrorStringOr<void> disable() override;
+    Inspector::Protocol::ErrorStringOr<void> 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<Inspector::DialogFrontendDispatcher> m_frontendDispatcher;
+    Ref<Inspector::DialogBackendDispatcher> 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..f7b2ecd583cd1eb5bb9e81becdfe07f5a855f2a9
--- /dev/null
+++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.cpp
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorPlaywrightAgent.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "APIGeolocationProvider.h"
+#include "APIHTTPCookieStore.h"
+#include "APIPageConfiguration.h"
+#include "FrameInfoData.h"
+#include "InspectorPlaywrightAgentClient.h"
+#include "InspectorTargetProxy.h"
+#include "NetworkProcessMessages.h"
+#include "NetworkProcessProxy.h"
+#include "PageClient.h"
+#include "PlaywrightFullScreenManagerProxyClient.h"
+#include "SandboxExtension.h"
+#include "StorageNamespaceIdentifier.h"
+#include "WebAutomationSession.h"
+#include "WebGeolocationManagerProxy.h"
+#include "WebGeolocationPosition.h"
+#include "WebFrameProxy.h"
+#include "WebInspectorUtilities.h"
+#include "WebPageGroup.h"
+#include "WebPageInspectorController.h"
+#include "WebPageInspectorTarget.h"
+#include "WebPageMessages.h"
+#include "WebPageProxy.h"
+#include "WebProcessPool.h"
+#include "WebProcessProxy.h"
+#include "WebsiteDataRecord.h"
+#include <WebCore/FrameIdentifier.h>
+#include <WebCore/GeolocationPositionData.h>
+#include <WebCore/InspectorPageAgent.h>
+#include <WebCore/ProcessIdentifier.h>
+#include <WebCore/ResourceRequest.h>
+#include <WebCore/SecurityOriginData.h>
+#include <WebCore/WindowFeatures.h>
+#include <JavaScriptCore/InspectorBackendDispatcher.h>
+#include <JavaScriptCore/InspectorFrontendChannel.h>
+#include <JavaScriptCore/InspectorFrontendRouter.h>
+#include <pal/SessionID.h>
+#include <stdlib.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/HexNumber.h>
+#include <wtf/URL.h>
+#include <wtf/text/MakeString.h>
+
+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<JSON::Value> parsedMessage = JSON::Value::parseJSON(message);
+        if (!parsedMessage)
+            return message;
+
+        RefPtr<JSON::Object> messageObject = parsedMessage->asObject();
+        if (!messageObject)
+            return message;
+
+        messageObject->setString("browserContextId"_s, m_browserContextID);
+        messageObject->setString("pageProxyId"_s, m_pageProxyID);
+        return messageObject->toJSONString();
+    }
+
+    String m_browserContextID;
+    String m_pageProxyID;
+    FrontendChannel& m_frontendChannel;
+    WebPageProxy& m_page;
+};
+
+class OverridenGeolocationProvider final : public API::GeolocationProvider, public CanMakeWeakPtr<OverridenGeolocationProvider> {
+     WTF_MAKE_NONCOPYABLE(OverridenGeolocationProvider);
+public:
+    OverridenGeolocationProvider()
+        : m_position(WebGeolocationPosition::create(WebCore::GeolocationPositionData()))
+    {
+    }
+
+    void setPosition(const Ref<WebGeolocationPosition>& position) {
+        m_position = position;
+    }
+
+private:
+    void startUpdating(WebGeolocationManagerProxy& proxy) override
+    {
+        proxy.providerDidChangePosition(&m_position.get());
+    }
+
+    void stopUpdating(WebGeolocationManagerProxy&) override
+    {
+    }
+
+    void setEnableHighAccuracy(WebGeolocationManagerProxy&, bool enabled) override
+    {
+    }
+
+    Ref<WebGeolocationPosition> m_position;
+};
+
+namespace {
+
+void setGeolocationProvider(BrowserContext* browserContext) {
+    auto provider = makeUnique<OverridenGeolocationProvider>();
+    browserContext->geolocationProvider = *provider;
+    auto* geoManager = browserContext->processPool->supplement<WebGeolocationManagerProxy>();
+    geoManager->setProvider(WTFMove(provider));
+}
+
+String toBrowserContextIDProtocolString(const PAL::SessionID& sessionID)
+{
+    StringBuilder builder;
+    builder.append(hex(sessionID.toUInt64(), 16));
+    return builder.toString();
+}
+
+String toPageProxyIDProtocolString(const WebPageProxy& page)
+{
+    return makeString(page.identifier().toUInt64());
+}
+
+
+static Ref<JSON::ArrayOf<String>> getEnabledWindowFeatures(const WebCore::WindowFeatures& features) {
+  auto result = JSON::ArrayOf<String>::create();
+  if (features.x)
+    result->addItem(makeString("left="_s, String::number(*features.x)));
+  if (features.y)
+    result->addItem(makeString("top="_s, String::number(*features.y)));
+  if (features.width)
+    result->addItem(makeString("width="_s, String::number(*features.width)));
+  if (features.height)
+    result->addItem(makeString("height="_s, String::number(*features.height)));
+  if (features.menuBarVisible)
+    result->addItem("menubar"_s);
+  if (features.toolBarVisible)
+    result->addItem("toolbar"_s);
+  if (features.statusBarVisible)
+    result->addItem("status"_s);
+  if (features.locationBarVisible)
+    result->addItem("location"_s);
+  if (features.scrollbarsVisible)
+    result->addItem("scrollbars"_s);
+  if (features.resizable)
+    result->addItem("resizable"_s);
+  if (features.fullscreen)
+    result->addItem("fullscreen"_s);
+  if (features.dialog)
+    result->addItem("dialog"_s);
+  if (features.noopener)
+    result->addItem("noopener"_s);
+  if (features.noreferrer)
+    result->addItem("noreferrer"_s);
+  for (const auto& additionalFeature : features.additionalFeatures)
+    result->addItem(additionalFeature);
+  return result;
+}
+
+Inspector::Protocol::Playwright::CookieSameSitePolicy cookieSameSitePolicy(WebCore::Cookie::SameSitePolicy policy)
+{
+    switch (policy) {
+    case WebCore::Cookie::SameSitePolicy::None:
+        return Inspector::Protocol::Playwright::CookieSameSitePolicy::None;
+    case WebCore::Cookie::SameSitePolicy::Lax:
+        return Inspector::Protocol::Playwright::CookieSameSitePolicy::Lax;
+    case WebCore::Cookie::SameSitePolicy::Strict:
+        return Inspector::Protocol::Playwright::CookieSameSitePolicy::Strict;
+    }
+    ASSERT_NOT_REACHED();
+    return Inspector::Protocol::Playwright::CookieSameSitePolicy::None;
+}
+
+Ref<Inspector::Protocol::Playwright::Cookie> 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<BrowserContext>&& context, size_t numberOfPages, Ref<DeleteContextCallback>&& 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<BrowserContext> m_browserContext;
+    size_t m_numberOfPages;
+    Ref<DeleteContextCallback> m_callback;
+};
+
+
+InspectorPlaywrightAgent::InspectorPlaywrightAgent(std::unique_ptr<InspectorPlaywrightAgentClient> client)
+    : m_frontendChannel(nullptr)
+    , m_frontendRouter(FrontendRouter::create())
+    , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
+    , m_client(std::move(client))
+    , m_frontendDispatcher(makeUnique<PlaywrightFrontendDispatcher>(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<JSON::Object>& messageObject) {
+        RefPtr<JSON::Value> idValue;
+        if (!messageObject->getValue("id"_s, idValue))
+            return BackendDispatcher::InterceptionResult::Continue;
+        RefPtr<JSON::Value> 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<int> requestId = idValue->asInteger();
+        if (!requestId) {
+            m_backendDispatcher->reportProtocolError(BackendDispatcher::InvalidRequest, "The type of 'id' must be number"_s);
+            m_backendDispatcher->sendPendingErrors();
+            return BackendDispatcher::InterceptionResult::Intercepted;
+        }
+
+        m_backendDispatcher->reportProtocolError(*requestId, BackendDispatcher::InvalidParams, "Cannot find page proxy with provided 'pageProxyId'"_s);
+        m_backendDispatcher->sendPendingErrors();
+        return BackendDispatcher::InterceptionResult::Intercepted;
+    });
+}
+
+void InspectorPlaywrightAgent::didCreateInspectorController(WebPageProxy& page)
+{
+    if (!m_isEnabled)
+        return;
+
+    if (isInspectorProcessPool(page.legacyMainFrameProcess().processPool()))
+        return;
+
+    ASSERT(m_frontendChannel);
+
+    String browserContextID = toBrowserContextIDProtocolString(page.sessionID());
+    String pageProxyID = toPageProxyIDProtocolString(page);
+    auto* opener = page.configuration().openerPageForInspector();
+    String openerId;
+    if (opener)
+        openerId = toPageProxyIDProtocolString(*opener);
+
+    BrowserContext* browserContext = getExistingBrowserContext(browserContextID);
+    browserContext->pages.add(&page);
+    m_frontendDispatcher->pageProxyCreated(browserContextID, pageProxyID, openerId);
+
+    // Auto-connect to all new pages.
+    auto pageProxyChannel = makeUnique<PageProxyChannel>(*m_frontendChannel, browserContextID, pageProxyID, page);
+    page.inspectorController().connectFrontend(*pageProxyChannel);
+    // Always pause new targets if controlled remotely.
+    page.inspectorController().setPauseOnStart(true);
+    m_pageProxyChannels.set(pageProxyID, WTFMove(pageProxyChannel));
+    page.setFullScreenManagerClientOverride(makeUnique<PlaywrightFullScreenManagerProxyClient>(page));
+}
+
+void InspectorPlaywrightAgent::willDestroyInspectorController(WebPageProxy& page)
+{
+    if (!m_isEnabled)
+        return;
+
+    if (isInspectorProcessPool(page.legacyMainFrameProcess().processPool()))
+        return;
+
+    String browserContextID = toBrowserContextIDProtocolString(page.sessionID());
+    BrowserContext* browserContext = getExistingBrowserContext(browserContextID);
+    browserContext->pages.remove(&page);
+    m_frontendDispatcher->pageProxyDestroyed(toPageProxyIDProtocolString(page));
+
+    auto it = m_browserContextDeletions.find(browserContextID);
+    if (it != m_browserContextDeletions.end()) {
+        it->value->didDestroyPage(page);
+        if (it->value->isFinished())
+            m_browserContextDeletions.remove(it);
+    }
+
+    String pageProxyID = toPageProxyIDProtocolString(page);
+    auto channelIt = m_pageProxyChannels.find(pageProxyID);
+    ASSERT(channelIt != m_pageProxyChannels.end());
+    channelIt->value->disconnect();
+    m_pageProxyChannels.remove(channelIt);
+}
+
+void InspectorPlaywrightAgent::didFailProvisionalLoad(WebPageProxy& page, WebCore::NavigationIdentifier navigationID, const String& error)
+{
+    if (!m_isEnabled)
+        return;
+
+    m_frontendDispatcher->provisionalLoadFailed(
+        toPageProxyIDProtocolString(page),
+        String::number(navigationID.toUInt64()), error);
+}
+
+void InspectorPlaywrightAgent::willCreateNewPage(WebPageProxy& page, const WebCore::WindowFeatures& features, const URL& url)
+{
+    if (!m_isEnabled)
+        return;
+
+    m_frontendDispatcher->windowOpen(
+        toPageProxyIDProtocolString(page),
+        url.string(),
+        getEnabledWindowFeatures(features));
+}
+
+void InspectorPlaywrightAgent::didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID)
+{
+    if (!m_isEnabled)
+        return;
+
+    m_frontendDispatcher->screencastFinished(screencastID);
+}
+
+static WebsiteDataStore* findDefaultWebsiteDataStore() {
+    WebsiteDataStore* result = nullptr;
+    WebsiteDataStore::forEachWebsiteDataStore([&result] (WebsiteDataStore& dataStore) {
+        if (dataStore.isPersistent()) {
+            RELEASE_ASSERT(result == nullptr);
+            result = &dataStore;
+        }
+    });
+    return result;
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorPlaywrightAgent::enable()
+{
+    if (m_isEnabled)
+        return { };
+
+    m_isEnabled = true;
+
+    auto* defaultDataStore = findDefaultWebsiteDataStore();
+    if (!m_defaultContext && defaultDataStore) {
+        auto context = std::make_unique<BrowserContext>();
+        m_defaultContext = context.get();
+        context->processPool = WebProcessPool::allProcessPools().first().ptr();
+        context->dataStore = defaultDataStore;
+        setGeolocationProvider(context.get());
+        // Add default context to the map so that we can easily find it for
+        // created/deleted pages.
+        PAL::SessionID sessionID = context->dataStore->sessionID();
+        m_browserContexts.set(toBrowserContextIDProtocolString(sessionID), WTFMove(context));
+    }
+
+    WebsiteDataStore::forEachWebsiteDataStore([this] (WebsiteDataStore& dataStore) {
+        dataStore.setDownloadInstrumentation(this);
+    });
+    for (Ref pool : WebProcessPool::allProcessPools()) {
+        for (Ref process : pool->processes()) {
+            for (Ref page : process->pages())
+                didCreateInspectorController(WTFMove(page));
+        }
+    }
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> 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<bool>(), String());
+    });
+    for (auto& it : m_browserContexts) {
+        it.value->dataStore->setDownloadInstrumentation(nullptr);
+        it.value->pages.clear();
+    }
+    m_browserContextDeletions.clear();
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<String> InspectorPlaywrightAgent::getInfo()
+{
+#if PLATFORM(MAC)
+    return { "macOS"_s };
+#elif PLATFORM(GTK) || PLATFORM(WPE)
+    return { "Linux"_s };
+#elif PLATFORM(WIN)
+    return { "Windows"_s };
+#else
+#error "Unsupported platform."
+#endif
+}
+
+void InspectorPlaywrightAgent::close(Ref<CloseCallback>&& callback)
+{
+    closeImpl([callback = WTFMove(callback)] (String error) {
+        if (!callback->isActive())
+            return;
+        if (error.isNull())
+            callback->sendSuccess();
+        else
+            callback->sendFailure(error);
+    });
+}
+
+void InspectorPlaywrightAgent::closeImpl(Function<void(String)>&& callback)
+{
+    Vector<Ref<WebPageProxy>> pages;
+    // If Web Process crashed it will be disconnected from its pool until
+    // the page reloads. So we cannot discover such processes and the pages
+    // by traversing all process pools and their processes. Instead we look at
+    // all existing Web Processes wether in a pool or not.
+    for (Ref process : WebProcessProxy::allProcessesForInspector()) {
+        for (Ref page : process->pages())
+            pages.append(WTFMove(page));
+    }
+    for (Ref page : pages)
+        page->closePage();
+
+    if (!m_defaultContext) {
+        m_client->closeBrowser();
+        callback(String());
+        return;
+    }
+
+    m_defaultContext->dataStore->syncLocalStorage([this, callback = WTFMove(callback)] () {
+        if (m_client == nullptr) {
+            callback("no platform delegate to close browser"_s);
+        } else {
+            m_client->closeBrowser();
+            callback(String());
+        }
+    });
+
+}
+
+Inspector::Protocol::ErrorStringOr<String /* browserContextID */> InspectorPlaywrightAgent::createContext(const String& proxyServer, const String& proxyBypassList)
+{
+    String errorString;
+    std::unique_ptr<BrowserContext> browserContext = m_client->createBrowserContext(errorString, proxyServer, proxyBypassList);
+    if (!browserContext)
+        return makeUnexpected(errorString);
+
+    // Ensure network process.
+    browserContext->dataStore->networkProcess();
+    browserContext->dataStore->setDownloadInstrumentation(this);
+    setGeolocationProvider(browserContext.get());
+    PAL::SessionID sessionID = browserContext->dataStore->sessionID();
+    String browserContextID = toBrowserContextIDProtocolString(sessionID);
+    m_browserContexts.set(browserContextID, WTFMove(browserContext));
+    return browserContextID;
+}
+
+void InspectorPlaywrightAgent::deleteContext(const String& browserContextID, Ref<DeleteContextCallback>&& 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<BrowserContextDeletion>(WTFMove(contextHolder), pages.size(), WTFMove(callback)));
+        for (auto* page : pages)
+            page->closePage();
+    }
+    m_client->deleteBrowserContext(errorString, sessionID);
+}
+
+Inspector::Protocol::ErrorStringOr<String /* pageProxyID */> InspectorPlaywrightAgent::createPage(const String& browserContextID)
+{
+    String errorString;
+    BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID);
+    if (!browserContext)
+        return makeUnexpected(errorString);
+
+    RefPtr<WebPageProxy> page = m_client->createPage(errorString, *browserContext);
+    if (!page)
+        return makeUnexpected(errorString);
+
+    return toPageProxyIDProtocolString(*page);
+}
+
+WebFrameProxy* InspectorPlaywrightAgent::frameForID(const String& frameID, String& error)
+{
+    std::optional<WebCore::FrameIdentifier> frameIdentifier = WebCore::InspectorPageAgent::parseFrameID(frameID);
+    if (!frameIdentifier) {
+        error = "Invalid frame id"_s;
+        return nullptr;
+    }
+
+    WebFrameProxy* frame = WebFrameProxy::webFrame(*frameIdentifier);
+    if (!frame) {
+        error = "Cannot find web frame for the frame id"_s;
+        return nullptr;
+    }
+
+    return frame;
+}
+
+void InspectorPlaywrightAgent::navigate(const String& url, const String& pageProxyID, const String& frameID, const String& referrer, Ref<NavigateCallback>&& callback)
+{
+    auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID);
+    if (!pageProxyChannel) {
+        callback->sendFailure("Cannot find page proxy with provided 'pageProxyId'"_s);
+        return;
+    }
+
+    WebCore::ResourceRequest resourceRequest { url };
+
+    if (!!referrer)
+        resourceRequest.setHTTPReferrer(referrer);
+
+    if (!resourceRequest.url().isValid()) {
+        callback->sendFailure("Cannot navigate to invalid URL"_s);
+        return;
+    }
+
+    WebFrameProxy* frame = nullptr;
+    if (!!frameID) {
+        String error;
+        frame = frameForID(frameID, error);
+        if (!frame) {
+            callback->sendFailure(error);
+            return;
+        }
+
+        if (frame->page() != &pageProxyChannel->page()) {
+            callback->sendFailure("Frame with specified is not from the specified page"_s);
+            return;
+        }
+    }
+
+    pageProxyChannel->page().inspectorController().navigate(WTFMove(resourceRequest), frame, [callback = WTFMove(callback)](const String& error, Markable<WebCore::NavigationIdentifier> navigationID) {
+        if (!error.isEmpty()) {
+            callback->sendFailure(error);
+            return;
+        }
+
+        String navigationIDString;
+        if (navigationID)
+            navigationIDString = String::number(navigationID->toUInt64());
+        callback->sendSuccess(navigationIDString);
+    });
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorPlaywrightAgent::grantFileReadAccess(const String& pageProxyID, Ref<JSON::Array>&& paths)
+{
+#if ENABLE(SANDBOX_EXTENSIONS)
+    auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID);
+    if (!pageProxyChannel)
+        return makeUnexpected("Unknown pageProxyID"_s);
+
+    Vector<String> files;
+    for (const auto& value : paths.get()) {
+        String path;
+        if (!value->asString(path))
+            return makeUnexpected("Filr path must be a string"_s);
+
+        files.append(path);
+    }
+
+    auto sandboxExtensionHandles = SandboxExtension::createReadOnlyHandlesForFiles("InspectorPlaywrightAgent::grantFileReadAccess"_s, files);
+    pageProxyChannel->page().legacyMainFrameProcess().send(Messages::WebPage::ExtendSandboxForFilesFromOpenPanel(WTFMove(sandboxExtensionHandles)), pageProxyChannel->page().webPageIDInMainFrameProcess());
+#endif
+    return { };
+}
+
+void InspectorPlaywrightAgent::takePageScreenshot(const String& pageProxyID, int x, int y, int width, int height, std::optional<bool>&& omitDeviceScaleFactor, Ref<TakePageScreenshotCallback>&& callback)
+{
+#if PLATFORM(MAC) || PLATFORM(GTK) || PLATFORM(WPE)
+    auto* pageProxyChannel = m_pageProxyChannels.get(pageProxyID);
+    if (!pageProxyChannel) {
+        callback->sendFailure("Unknown pageProxyID"_s);
+        return;
+    }
+
+    bool nominalResolution = omitDeviceScaleFactor.has_value() && *omitDeviceScaleFactor;
+    WebCore::IntRect clip(x, y, width, height);
+    m_client->takePageScreenshot(pageProxyChannel->page(), WTFMove(clip), nominalResolution, [callback = WTFMove(callback)](const String& error, const String& data) {
+        if (error.isEmpty())
+            callback->sendSuccess(data);
+        else
+            callback->sendFailure(error);
+    });
+#else
+    return callback->sendFailure("This method is not supported on this platform."_s);
+#endif
+}
+
+
+Inspector::Protocol::ErrorStringOr<void> 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<GetAllCookiesCallback>&& callback) {
+    String errorString;
+    BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID);
+    if (!errorString.isEmpty()) {
+        callback->sendFailure(errorString);
+        return;
+    }
+
+    browserContext->dataStore->cookieStore().cookies(
+        [callback = WTFMove(callback)](const Vector<WebCore::Cookie>& allCookies) {
+            if (!callback->isActive())
+                return;
+            auto cookies = JSON::ArrayOf<Inspector::Protocol::Playwright::Cookie>::create();
+
+// Soup returns cookies in the reverse order.
+#if USE(SOUP)
+            for (const auto& cookie : makeReversedRange(allCookies))
+#else
+            for (const auto& cookie : allCookies)
+#endif
+                cookies->addItem(buildObjectForCookie(cookie));
+            callback->sendSuccess(WTFMove(cookies));
+        });
+}
+
+void InspectorPlaywrightAgent::setCookies(const String& browserContextID, Ref<JSON::Array>&& in_cookies, Ref<SetCookiesCallback>&& callback) {
+    String errorString;
+    BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID);
+    if (!errorString.isEmpty()) {
+        callback->sendFailure(errorString);
+        return;
+    }
+
+    Vector<WebCore::Cookie> cookies;
+    for (unsigned i = 0; i < in_cookies->length(); ++i) {
+        RefPtr<JSON::Value> item = in_cookies->get(i);
+        RefPtr<JSON::Object> obj = item->asObject();
+        if (!obj) {
+            callback->sendFailure("Invalid cookie payload format"_s);
+            return;
+        }
+
+        WebCore::Cookie cookie;
+        cookie.name = obj->getString("name"_s);
+        cookie.value = obj->getString("value"_s);
+        cookie.domain = obj->getString("domain"_s);
+        cookie.path = obj->getString("path"_s);
+        if (!cookie.name || !cookie.value || !cookie.domain || !cookie.path) {
+            callback->sendFailure("Invalid file payload format"_s);
+            return;
+        }
+
+        std::optional<double> expires = obj->getDouble("expires"_s);
+        if (expires && *expires != -1)
+            cookie.expires = *expires;
+        if (std::optional<bool> value = obj->getBoolean("httpOnly"_s))
+            cookie.httpOnly = *value;
+        if (std::optional<bool> value = obj->getBoolean("secure"_s))
+            cookie.secure = *value;
+        if (std::optional<bool> value = obj->getBoolean("session"_s))
+            cookie.session = *value;
+        String sameSite;
+        if (obj->getString("sameSite"_s, sameSite)) {
+            if (sameSite == "None"_s)
+                cookie.sameSite = WebCore::Cookie::SameSitePolicy::None;
+            if (sameSite == "Lax"_s)
+                cookie.sameSite = WebCore::Cookie::SameSitePolicy::Lax;
+            if (sameSite == "Strict"_s)
+                cookie.sameSite = WebCore::Cookie::SameSitePolicy::Strict;
+#if USE(SOUP)
+        } else {
+            // Cookies are Lax by default in libsoup and will reject cookies with
+            // sameSite: None and secure: false (defaults in WebCore::Cookie).
+            cookie.sameSite = WebCore::Cookie::SameSitePolicy::Lax;
+#endif
+        }
+        cookies.append(WTFMove(cookie));
+    }
+
+    browserContext->dataStore->cookieStore().setCookies(WTFMove(cookies),
+        [callback = WTFMove(callback)]() {
+            if (!callback->isActive())
+                return;
+            callback->sendSuccess();
+        });
+}
+
+void InspectorPlaywrightAgent::deleteAllCookies(const String& browserContextID, Ref<DeleteAllCookiesCallback>&& callback) {
+    String errorString;
+    BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID);
+    if (!errorString.isEmpty()) {
+        callback->sendFailure(errorString);
+        return;
+    }
+
+    browserContext->dataStore->cookieStore().deleteAllCookies(
+        [callback = WTFMove(callback)]() {
+            if (!callback->isActive())
+                return;
+            callback->sendSuccess();
+        });
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorPlaywrightAgent::setLanguages(Ref<JSON::Array>&& languages, const String& browserContextID)
+{
+    String errorString;
+    BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID);
+    if (!errorString.isEmpty())
+        return makeUnexpected(errorString);
+
+    Vector<String> items;
+    for (const auto& value : languages.get()) {
+        String language;
+        if (!value->asString(language))
+            return makeUnexpected("Language must be a string"_s);
+
+        items.append(language);
+    }
+
+    browserContext->processPool->configuration().setOverrideLanguages(WTFMove(items));
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> 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<bool> allow;
+    if (behavior == "allow"_s)
+      allow = true;
+    if (behavior == "deny"_s)
+      allow = false;
+    browserContext->dataStore->setDownloadForAutomation(allow, downloadPath);
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorPlaywrightAgent::setGeolocationOverride(const String& browserContextID, RefPtr<JSON::Object>&& geolocation)
+{
+    String errorString;
+    BrowserContext* browserContext = lookupBrowserContext(errorString, browserContextID);
+    if (!errorString.isEmpty())
+        return makeUnexpected(errorString);
+
+    auto* geoManager = browserContext->processPool->supplement<WebGeolocationManagerProxy>();
+    if (!geoManager)
+        return makeUnexpected("Internal error: geolocation manager is not available."_s);
+
+    if (geolocation) {
+        std::optional<double> timestamp = geolocation->getDouble("timestamp"_s);
+        std::optional<double> latitude = geolocation->getDouble("latitude"_s);
+        std::optional<double> longitude = geolocation->getDouble("longitude"_s);
+        std::optional<double> accuracy = geolocation->getDouble("accuracy"_s);
+        if (!timestamp || !latitude || !longitude || !accuracy)
+            return makeUnexpected("Invalid geolocation format"_s);
+
+        auto position = WebGeolocationPosition::create(WebCore::GeolocationPositionData(*timestamp, *latitude, *longitude, *accuracy));
+        if (!browserContext->geolocationProvider)
+            return makeUnexpected("Internal error: geolocation provider has been destroyed."_s);
+        browserContext->geolocationProvider->setPosition(position);
+        geoManager->providerDidChangePosition(&position.get());
+    } else {
+        geoManager->providerDidFailToDeterminePosition("Position unavailable"_s);
+    }
+    return { };
+}
+
+void InspectorPlaywrightAgent::downloadCreated(const String& uuid, const WebCore::ResourceRequest& request, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr<DownloadProxy> download)
+{
+    if (!m_isEnabled)
+        return;
+    String frameID = WebCore::InspectorPageAgent::serializeFrameID(*frameInfoData.frameID);
+    m_downloads.set(uuid, download);
+    m_frontendDispatcher->downloadCreated(
+        toPageProxyIDProtocolString(*page),
+        frameID,
+        uuid, request.url().string());
+}
+
+void InspectorPlaywrightAgent::downloadFilenameSuggested(const String& uuid, const String& suggestedFilename)
+{
+    if (!m_isEnabled)
+        return;
+    m_frontendDispatcher->downloadFilenameSuggested(uuid, suggestedFilename);
+}
+
+void InspectorPlaywrightAgent::downloadFinished(const String& uuid, const String& error)
+{
+    if (!m_isEnabled)
+        return;
+    m_frontendDispatcher->downloadFinished(uuid, error);
+    m_downloads.remove(uuid);
+}
+
+Inspector::Protocol::ErrorStringOr<void> InspectorPlaywrightAgent::cancelDownload(const String& uuid)
+{
+    if (!m_isEnabled)
+        return { };
+    auto download = m_downloads.get(uuid);
+    if (!download)
+        return { };
+    download->cancel([] (auto*) {});
+    return { };
+}
+
+void InspectorPlaywrightAgent::clearMemoryCache(const String& browserContextID, Ref<ClearMemoryCacheCallback>&& callback)
+{
+    if (!m_isEnabled) {
+        callback->sendSuccess();
+        return;
+    }
+    auto browserContext = getExistingBrowserContext(browserContextID);
+    if (!browserContext) {
+        callback->sendSuccess();
+        return;
+    }
+    browserContext->dataStore->removeData(WebKit::WebsiteDataType::MemoryCache, -WallTime::infinity(), [callback] {
+        callback->sendSuccess();
+    });
+}
+
+BrowserContext* InspectorPlaywrightAgent::getExistingBrowserContext(const String& browserContextID)
+{
+    BrowserContext* browserContext = m_browserContexts.get(browserContextID);
+    if (browserContext)
+        return browserContext;
+
+    auto it = m_browserContextDeletions.find(browserContextID);
+    RELEASE_ASSERT(it != m_browserContextDeletions.end());
+    return it->value->context();
+}
+
+BrowserContext* InspectorPlaywrightAgent::lookupBrowserContext(ErrorString& errorString, const String& browserContextID)
+{
+    if (!browserContextID) {
+        if (!m_defaultContext)
+            errorString = "Browser started with no default context"_s;
+        return m_defaultContext;
+    }
+
+    BrowserContext* browserContext = m_browserContexts.get(browserContextID);
+    if (!browserContext)
+        errorString = "Could not find browser context for given id"_s;
+    return browserContext;
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h
new file mode 100644
index 0000000000000000000000000000000000000000..2cd467df987e1679ff8918c2867bf253ce105b8c
--- /dev/null
+++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgent.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorPlaywrightAgentClient.h"
+#include <JavaScriptCore/InspectorBackendDispatchers.h>
+#include "WebPageInspectorController.h"
+#include "WebProcessPool.h"
+#include "DownloadProxy.h"
+#include <wtf/HashMap.h>
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <WebCore/NavigationIdentifier.h>
+
+namespace Inspector {
+class BackendDispatcher;
+class FrontendChannel;
+class FrontendRouter;
+class PlaywrightFrontendDispatcher;
+}
+
+namespace PAL {
+class SessionID;
+}
+
+namespace WebKit {
+class OverridenGeolocationProvider;
+}
+
+namespace WTF {
+template<typename T> struct IsDeprecatedWeakRefSmartPointerException;
+template<> struct IsDeprecatedWeakRefSmartPointerException<WebKit::OverridenGeolocationProvider> : std::true_type { };
+}
+
+namespace WebKit {
+
+class WebFrameProxy;
+
+class InspectorPlaywrightAgent final
+    : public WebPageInspectorControllerObserver
+    , public Inspector::PlaywrightBackendDispatcherHandler
+    , public DownloadInstrumentation {
+    WTF_MAKE_NONCOPYABLE(InspectorPlaywrightAgent);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit InspectorPlaywrightAgent(std::unique_ptr<InspectorPlaywrightAgentClient> client);
+    ~InspectorPlaywrightAgent() override;
+
+    // Transport
+    void connectFrontend(Inspector::FrontendChannel&);
+    void disconnectFrontend();
+    void dispatchMessageFromFrontend(const String& message);
+
+private:
+    class BrowserContextDeletion;
+    class PageProxyChannel;
+    class TargetHandler;
+
+    // WebPageInspectorControllerObserver
+    void didCreateInspectorController(WebPageProxy&) override;
+    void willDestroyInspectorController(WebPageProxy&) override;
+    void didFailProvisionalLoad(WebPageProxy&, WebCore::NavigationIdentifier navigationID, const String& error) override;
+    void willCreateNewPage(WebPageProxy&, const WebCore::WindowFeatures&, const URL&) override;
+    void didFinishScreencast(const PAL::SessionID& sessionID, const String& screencastID) override;
+
+    // PlaywrightDispatcherHandler
+    Inspector::Protocol::ErrorStringOr<void> enable() override;
+    Inspector::Protocol::ErrorStringOr<void> disable() override;
+    Inspector::Protocol::ErrorStringOr<String> getInfo() override;
+    void close(Ref<CloseCallback>&&) override;
+    Inspector::Protocol::ErrorStringOr<String /* browserContextID */> createContext(const String& proxyServer, const String& proxyBypassList) override;
+    void deleteContext(const String& browserContextID, Ref<DeleteContextCallback>&& callback) override;
+    Inspector::Protocol::ErrorStringOr<String /* pageProxyID */> createPage(const String& browserContextID) override;
+    void navigate(const String& url, const String& pageProxyID, const String& frameId, const String& referrer, Ref<NavigateCallback>&&) override;
+    Inspector::Protocol::ErrorStringOr<void> grantFileReadAccess(const String& pageProxyID, Ref<JSON::Array>&& paths) override;
+    void takePageScreenshot(const String& pageProxyID, int x, int y, int width, int height, std::optional<bool>&& omitDeviceScaleFactor, Ref<TakePageScreenshotCallback>&&) override;
+    Inspector::Protocol::ErrorStringOr<void> setIgnoreCertificateErrors(const String& browserContextID, bool ignore) override;
+
+    void getAllCookies(const String& browserContextID, Ref<GetAllCookiesCallback>&&) override;
+    void setCookies(const String& browserContextID, Ref<JSON::Array>&& in_cookies, Ref<SetCookiesCallback>&&) override;
+    void deleteAllCookies(const String& browserContextID, Ref<DeleteAllCookiesCallback>&&) override;
+
+    Inspector::Protocol::ErrorStringOr<void> setGeolocationOverride(const String& browserContextID, RefPtr<JSON::Object>&& geolocation) override;
+    Inspector::Protocol::ErrorStringOr<void> setLanguages(Ref<JSON::Array>&& languages, const String& browserContextID) override;
+    Inspector::Protocol::ErrorStringOr<void> setDownloadBehavior(const String& behavior, const String& downloadPath, const String& browserContextID) override;
+    Inspector::Protocol::ErrorStringOr<void> cancelDownload(const String& uuid) override;
+    void clearMemoryCache(const String& browserContextID, Ref<ClearMemoryCacheCallback>&&) override;
+
+    // DownloadInstrumentation
+    void downloadCreated(const String& uuid, const WebCore::ResourceRequest&, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr<DownloadProxy> 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<void(String)>&&);
+
+    Inspector::FrontendChannel* m_frontendChannel { nullptr };
+    Ref<Inspector::FrontendRouter> m_frontendRouter;
+    Ref<Inspector::BackendDispatcher> m_backendDispatcher;
+    std::unique_ptr<InspectorPlaywrightAgentClient> m_client;
+    std::unique_ptr<Inspector::PlaywrightFrontendDispatcher> m_frontendDispatcher;
+    Ref<Inspector::PlaywrightBackendDispatcher> m_playwrightDispatcher;
+    UncheckedKeyHashMap<String, std::unique_ptr<PageProxyChannel>> m_pageProxyChannels;
+    BrowserContext* m_defaultContext;
+    UncheckedKeyHashMap<String, RefPtr<DownloadProxy>> m_downloads;
+    UncheckedKeyHashMap<String, std::unique_ptr<BrowserContext>> m_browserContexts;
+    UncheckedKeyHashMap<String, std::unique_ptr<BrowserContextDeletion>> m_browserContextDeletions;
+    bool m_isEnabled { false };
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h
new file mode 100644
index 0000000000000000000000000000000000000000..e7a3dcc533294bb6e12f65d79b5b716bd3c12236
--- /dev/null
+++ b/Source/WebKit/UIProcess/InspectorPlaywrightAgentClient.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include <memory>
+#include <pal/SessionID.h>
+#include <WebCore/IntRect.h>
+#include <wtf/Forward.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/RefCounted.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebKit {
+
+class OverridenGeolocationProvider;
+class WebsiteDataStore;
+class WebPageProxy;
+class WebProcessPool;
+
+class BrowserContext {
+    WTF_MAKE_NONCOPYABLE(BrowserContext);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    BrowserContext();
+    ~BrowserContext();
+
+    RefPtr<WebsiteDataStore> dataStore;
+    RefPtr<WebProcessPool> processPool;
+    HashSet<WebPageProxy*> pages;
+    WeakPtr<OverridenGeolocationProvider> geolocationProvider;
+};
+
+class InspectorPlaywrightAgentClient {
+public:
+    virtual ~InspectorPlaywrightAgentClient() = default;
+    virtual RefPtr<WebKit::WebPageProxy> createPage(WTF::String& error, const BrowserContext& context) = 0;
+    virtual void closeBrowser() = 0;
+    virtual std::unique_ptr<BrowserContext> createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) = 0;
+    virtual void deleteBrowserContext(WTF::String& error, PAL::SessionID) = 0;
+#if PLATFORM(COCOA) || PLATFORM(GTK) || PLATFORM(WPE)
+    virtual void takePageScreenshot(WebPageProxy&, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler<void(const String&, const String&)>&& completionHandler) = 0;
+#endif
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp
index 348b454826ee9278e45ed6e265136a55296ee2d1..16575216af8c7b836c52f3747d73ce206b226855 100644
--- a/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp
+++ b/Source/WebKit/UIProcess/Launcher/glib/ProcessLauncherGLib.cpp
@@ -178,6 +178,13 @@ void ProcessLauncher::launchProcess()
         nargs++;
     }
 #endif
+// Playwright begin
+    bool enableSharedArrayBuffer = false;
+    if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web && m_client && m_client->shouldEnableSharedArrayBuffer()) {
+        enableSharedArrayBuffer = true;
+        nargs++;
+    }
+// Playwright end
 
     WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN // GTK/WPE port
 
@@ -196,6 +203,10 @@ void ProcessLauncher::launchProcess()
     if (configureJSCForTesting)
         argv[i++] = const_cast<char*>("--configure-jsc-for-testing");
 #endif
+// Playwright begin
+    if (enableSharedArrayBuffer)
+        argv[i++] = const_cast<char*>("--enable-shared-array-buffer");
+// Playwright end
     argv[i++] = nullptr;
 
     WTF_ALLOW_UNSAFE_BUFFER_USAGE_END
diff --git a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp
index fac881d7c3d44758591d7a9f392a3992ce9f9a72..35eba5a0b31fc6e2d6e5c05c9f866c03d2e1c7d0 100644
--- a/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp
+++ b/Source/WebKit/UIProcess/Launcher/win/ProcessLauncherWin.cpp
@@ -91,14 +91,21 @@ void ProcessLauncher::launchProcess()
         commandLineBuilder.append(" -configure-jsc-for-testing"_s);
     if (!m_client->isJITEnabled())
         commandLineBuilder.append(" -disable-jit"_s);
+// Playwright begin
+    if (m_launchOptions.processType == ProcessLauncher::ProcessType::Web && m_client->shouldEnableSharedArrayBuffer())
+        commandLineBuilder.append(" -enable-shared-array-buffer"_s);
+// Playwright end
     commandLineBuilder.append('\0');
 
     auto commandLine = commandLineBuilder.toString().wideCharacters();
 
     STARTUPINFO startupInfo { };
     startupInfo.cb = sizeof(startupInfo);
-    startupInfo.dwFlags = STARTF_USESHOWWINDOW;
+    startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
     startupInfo.wShowWindow = SW_HIDE;
+    startupInfo.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
+    startupInfo.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
+    startupInfo.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
     PROCESS_INFORMATION processInformation { };
     BOOL result = ::CreateProcess(0, commandLine.data(), 0, 0, true, 0, 0, 0, &startupInfo, &processInformation);
 
diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h
index 06169e91f403da8cb53b1fe6b718b22eeb0a51fe..0162c16f55d6ef76c31887fdf48d184c54f38f18 100644
--- a/Source/WebKit/UIProcess/PageClient.h
+++ b/Source/WebKit/UIProcess/PageClient.h
@@ -74,6 +74,11 @@
 #include <WebCore/PlatformTextAlternatives.h>
 #endif
 
+#if USE(SKIA)
+#include <skia/core/SkData.h>
+#include <skia/core/SkImage.h>
+#endif
+
 OBJC_CLASS AVPlayerViewController;
 OBJC_CLASS CALayer;
 OBJC_CLASS NSFileWrapper;
@@ -95,6 +100,12 @@ OBJC_CLASS WKView;
 #endif
 #endif
 
+#if PLATFORM(GTK) || PLATFORM(WPE)
+#if USE(CAIRO)
+#include <WebCore/RefPtrCairo.h>
+#endif
+#endif
+
 namespace API {
 class Attachment;
 class HitTestResult;
@@ -372,7 +383,20 @@ public:
     virtual void selectionDidChange() = 0;
 #endif
 
-#if PLATFORM(COCOA) || PLATFORM(GTK)
+// Paywright begin
+#if PLATFORM(COCOA)
+    virtual RetainPtr<CGImageRef> takeSnapshotForAutomation() = 0;
+#elif PLATFORM(WPE)
+#if USE(SKIA)
+    virtual sk_sp<SkImage> takeViewSnapshot(std::optional<WebCore::IntRect>&&, bool nominalResolution = false) = 0;
+#elif USE(CAIRO)
+    virtual RefPtr<cairo_surface_t> takeViewSnapshot(std::optional<WebCore::IntRect>&&, bool nominalResolution = false) = 0;
+#endif
+#elif PLATFORM(GTK)
+    virtual RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&, bool nominalResolution = false) = 0;
+#endif
+// Paywright end
+#if PLATFORM(COCOA)
     virtual RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&) = 0;
 #endif
 
diff --git a/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.cpp b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d365dfd28dcc5d101b4d3859302b1bfe75f01a55
--- /dev/null
+++ b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2023 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+#include "PlaywrightFullScreenManagerProxyClient.h"
+
+#if ENABLE(FULLSCREEN_API)
+
+#include "WebPageProxy.h"
+
+namespace WebKit {
+using namespace WebCore;
+
+PlaywrightFullScreenManagerProxyClient::PlaywrightFullScreenManagerProxyClient(WebPageProxy& page)
+    : m_pageProxy(page)
+{
+}
+
+void PlaywrightFullScreenManagerProxyClient::enterFullScreen()
+{
+    m_pageProxy.fullScreenManager()->willEnterFullScreen();
+    m_pageProxy.fullScreenManager()->didEnterFullScreen();
+}
+
+void PlaywrightFullScreenManagerProxyClient::exitFullScreen()
+{
+    m_pageProxy.fullScreenManager()->willExitFullScreen();
+    m_pageProxy.fullScreenManager()->didExitFullScreen();
+
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(FULLSCREEN_API)
diff --git a/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.h b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c8fd0549f1847515d35092f0f49b0602be86819
--- /dev/null
+++ b/Source/WebKit/UIProcess/PlaywrightFullScreenManagerProxyClient.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2023 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(FULLSCREEN_API)
+
+#include "WebFullScreenManagerProxy.h"
+
+namespace WebKit {
+
+class WebPageProxy;
+
+class PlaywrightFullScreenManagerProxyClient : public WebFullScreenManagerProxyClient {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    PlaywrightFullScreenManagerProxyClient(WebPageProxy&);
+    ~PlaywrightFullScreenManagerProxyClient() override = default;
+
+private:
+    void closeFullScreenManager() override { }
+    bool isFullScreen() override { return m_isFullScreen; }
+    void enterFullScreen() override;
+    void exitFullScreen() override;
+    void beganEnterFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame) override { }
+    void beganExitFullScreen(const WebCore::IntRect& initialFrame, const WebCore::IntRect& finalFrame) override { }
+
+    WebPageProxy& m_pageProxy;
+    bool m_isFullScreen { false };
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(FULLSCREEN_API)
diff --git a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp
index 949c12f22544a17e9047def6f1ddf6a6e6fc1adc..bfd4d442f971e3956ed6d6962f7a570ff0a0755c 100644
--- a/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp
+++ b/Source/WebKit/UIProcess/ProvisionalFrameProxy.cpp
@@ -25,6 +25,7 @@
 
 #include "config.h"
 #include "ProvisionalFrameProxy.h"
+#include "WebFrameProxy.h"
 
 #include "FrameProcess.h"
 #include "ProvisionalFrameCreationParameters.h"
diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b1ddac8c1442cb4da17f50d92599ef9aff6d4066
--- /dev/null
+++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.cpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RemoteInspectorPipe.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorPlaywrightAgent.h"
+#include <JavaScriptCore/InspectorFrontendChannel.h>
+#include <wtf/Compiler.h>
+#include <wtf/MainThread.h>
+#include <wtf/RunLoop.h>
+#include <wtf/UniqueArray.h>
+#include <wtf/Vector.h>
+#include <wtf/WorkQueue.h>
+
+#if OS(UNIX)
+#include <stdio.h>
+#include <unistd.h>
+#endif
+
+#if PLATFORM(WIN)
+#include <io.h>
+#endif
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN
+
+namespace WebKit {
+
+namespace {
+
+const int readFD = 3;
+const int writeFD = 4;
+
+const size_t kWritePacketSize = 1 << 16;
+
+#if PLATFORM(WIN)
+HANDLE readHandle;
+HANDLE writeHandle;
+#endif
+
+size_t ReadBytes(void* buffer, size_t size, bool exact_size)
+{
+    size_t bytesRead = 0;
+    while (bytesRead < size) {
+#if PLATFORM(WIN)
+        DWORD sizeRead = 0;
+        bool hadError = !ReadFile(readHandle, static_cast<char*>(buffer) + bytesRead,
+            size - bytesRead, &sizeRead, nullptr);
+#else
+        int sizeRead = read(readFD, static_cast<char*>(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<DWORD>(length), &bytesWritten, nullptr);
+#else
+        int bytesWritten = write(writeFD, bytes + totalWritten, length);
+        if (bytesWritten < 0 && errno == EINTR)
+            continue;
+        bool hadError = bytesWritten <= 0;
+#endif
+        if (hadError)
+            return;
+        totalWritten += bytesWritten;
+    }
+}
+
+}  // namespace
+
+class RemoteInspectorPipe::RemoteFrontendChannel : public Inspector::FrontendChannel {
+    WTF_MAKE_FAST_ALLOCATED;
+
+public:
+    RemoteFrontendChannel()
+        : m_senderQueue(WorkQueue::create("Inspector pipe writer"_s))
+    {
+    }
+
+    ~RemoteFrontendChannel() override = default;
+
+    ConnectionType connectionType() const override
+    {
+        return ConnectionType::Remote;
+    }
+
+    void sendMessageToFrontend(const String& message) override
+    {
+        m_senderQueue->dispatch([message = message.isolatedCopy()]() {
+            auto utf8 = message.utf8();
+            WriteBytes(utf8.data(), utf8.length());
+            WriteBytes("\0", 1);
+        });
+    }
+
+private:
+    Ref<WorkQueue> m_senderQueue;
+};
+
+RemoteInspectorPipe::RemoteInspectorPipe(InspectorPlaywrightAgent& playwrightAgent)
+    : m_playwrightAgent(playwrightAgent)
+{
+    m_remoteFrontendChannel = makeUnique<RemoteFrontendChannel>();
+    start();
+}
+
+RemoteInspectorPipe::~RemoteInspectorPipe()
+{
+    stop();
+}
+
+bool RemoteInspectorPipe::start()
+{
+    if (m_receiverThread)
+        return true;
+
+#if PLATFORM(WIN)
+    readHandle = reinterpret_cast<HANDLE>(_get_osfhandle(readFD));
+    writeHandle = reinterpret_cast<HANDLE>(_get_osfhandle(writeFD));
+#endif
+
+    m_playwrightAgent.connectFrontend(*m_remoteFrontendChannel);
+    m_terminated = false;
+    m_receiverThread = Thread::create("Inspector pipe reader"_s, [this] {
+        workerRun();
+    });
+    return true;
+}
+
+void RemoteInspectorPipe::stop()
+{
+    if (!m_receiverThread)
+        return;
+
+    m_playwrightAgent.disconnectFrontend();
+
+    m_terminated = true;
+    m_receiverThread->waitForCompletion();
+    m_receiverThread = nullptr;
+}
+
+void RemoteInspectorPipe::workerRun()
+{
+    const size_t bufSize = 256 * 1024;
+    auto buffer = makeUniqueArray<char>(bufSize);
+    Vector<char> line;
+    while (!m_terminated) {
+        size_t size = ReadBytes(buffer.get(), bufSize, false);
+        if (!size) {
+            RunLoop::main().dispatch([this] {
+                if (!m_terminated)
+                    m_playwrightAgent.disconnectFrontend();
+            });
+            break;
+        }
+        size_t start = 0;
+        size_t end = line.size();
+        line.append(std::span { buffer.get(), size });
+        while (true) {
+            for (; end < line.size(); ++end) {
+                if (line[end] == '\0')
+                    break;
+            }
+            if (end == line.size())
+                break;
+
+            if (end > start) {
+                String message = String::fromUTF8({ line.data() + start, end - start });
+                RunLoop::main().dispatch([this, message = WTFMove(message)] {
+                    if (!m_terminated)
+                        m_playwrightAgent.dispatchMessageFromFrontend(message);
+                });
+            }
+            ++end;
+            start = end;
+        }
+        if (start != 0 && start < line.size())
+            memmove(line.data(), line.data() + start, line.size() - start);
+        line.shrink(line.size() - start);
+    }
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
+
+WTF_ALLOW_UNSAFE_BUFFER_USAGE_END
diff --git a/Source/WebKit/UIProcess/RemoteInspectorPipe.h b/Source/WebKit/UIProcess/RemoteInspectorPipe.h
new file mode 100644
index 0000000000000000000000000000000000000000..6d04f9290135069359ce6bf8726546482fd1dc95
--- /dev/null
+++ b/Source/WebKit/UIProcess/RemoteInspectorPipe.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include <wtf/Ref.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+
+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<Thread> m_receiverThread;
+    std::atomic<bool> m_terminated { false };
+    std::unique_ptr<Inspector::FrontendChannel> m_remoteFrontendChannel;
+    InspectorPlaywrightAgent& m_playwrightAgent;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/RemotePageProxy.cpp b/Source/WebKit/UIProcess/RemotePageProxy.cpp
index eae3ae7fdac55067463e1571068ec8cf25408bd9..707e9feec18d94c3a14b49e5826cab1026ff234a 100644
--- a/Source/WebKit/UIProcess/RemotePageProxy.cpp
+++ b/Source/WebKit/UIProcess/RemotePageProxy.cpp
@@ -44,6 +44,7 @@
 #include "WebProcessActivityState.h"
 #include "WebProcessMessages.h"
 #include "WebProcessProxy.h"
+#include "WebProcessMessages.h"
 #include <WebCore/RemoteUserInputEventData.h>
 #include <wtf/TZoneMallocInlines.h>
 
diff --git a/Source/WebKit/UIProcess/WebContextMenuProxy.h b/Source/WebKit/UIProcess/WebContextMenuProxy.h
index c951d8577473371d8eb59ad651451737349c4389..b38cd0967ae45733a94594fd25900ddc1d49c3f6 100644
--- a/Source/WebKit/UIProcess/WebContextMenuProxy.h
+++ b/Source/WebKit/UIProcess/WebContextMenuProxy.h
@@ -49,6 +49,7 @@ public:
     void deref() const final { RefCounted::deref(); }
 
     virtual void show();
+    virtual void hide() {}
 
     WebPageProxy* page() const { return m_page.get(); }
 
diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0a8d10ae990997684766df46719c65aa8dd77f28
--- /dev/null
+++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.cpp
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebPageInspectorEmulationAgent.h"
+
+#include "APIPageConfiguration.h"
+#include "WebPageProxy.h"
+#include "WebPreferences.h"
+#include "PageClient.h"
+#include <JavaScriptCore/InspectorFrontendRouter.h>
+#include <WebCore/Credential.h>
+
+
+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<double>&& deviceScaleFactor, Ref<SetDeviceMetricsOverrideCallback>&& 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<SetDeviceMetricsOverrideCallback>&& callback)
+{
+    platformSetSize(width, height, [callback = WTFMove(callback)](const String& error) {
+        if (error.isEmpty())
+            callback->sendSuccess();
+        else
+            callback->sendFailure(error);
+    });
+}
+
+Inspector::Protocol::ErrorStringOr<void> WebPageInspectorEmulationAgent::setJavaScriptEnabled(bool enabled)
+{
+    auto copy = m_page.preferences().copy();
+    copy->setJavaScriptEnabled(enabled);
+    m_page.setPreferences(copy);
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> WebPageInspectorEmulationAgent::setAuthCredentials(const String& username, const String& password, const String& origin)
+{
+    if (!!username && !!password)
+        m_page.setAuthCredentialsForAutomation(WebCore::Credential(username, password, WebCore::CredentialPersistence::Permanent), URL(origin));
+    else
+        m_page.setAuthCredentialsForAutomation(std::optional<WebCore::Credential>(), std::optional<URL>());
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> WebPageInspectorEmulationAgent::setActiveAndFocused(std::optional<bool>&& active)
+{
+    m_page.setActiveForAutomation(WTFMove(active));
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> WebPageInspectorEmulationAgent::grantPermissions(const String& origin, Ref<JSON::Array>&& values)
+{
+    HashSet<String> 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<void> WebPageInspectorEmulationAgent::resetPermissions()
+{
+    m_permissions.clear();
+    m_page.setPermissionsForAutomation(m_permissions);
+    return { };
+}
+
+Inspector::Protocol::ErrorStringOr<void> WebPageInspectorEmulationAgent::setOrientationOverride(std::optional<int>&& angle)
+{
+#if ENABLE(ORIENTATION_EVENTS)
+    m_page.setOrientationOverride(WTFMove(angle));
+    return { };
+#else
+    UNUSED_PARAM(angle);
+    return makeUnexpected("Orientation events are disabled in this build"_s);
+#endif
+}
+
+
+void WebPageInspectorEmulationAgent::didShowPage()
+{
+    for (auto& command : m_commandsToRunWhenShown)
+        command();
+    m_commandsToRunWhenShown.clear();
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h
new file mode 100644
index 0000000000000000000000000000000000000000..d00d00ce8fd800dc1497b36b8a495c5b9aef6f58
--- /dev/null
+++ b/Source/WebKit/UIProcess/WebPageInspectorEmulationAgent.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <JavaScriptCore/InspectorAgentBase.h>
+#include <JavaScriptCore/InspectorBackendDispatchers.h>
+
+#include <wtf/Forward.h>
+#include <wtf/Function.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+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<double>&& deviceScaleFactor, Ref<SetDeviceMetricsOverrideCallback>&&) override;
+    Inspector::Protocol::ErrorStringOr<void> setJavaScriptEnabled(bool enabled) override;
+    Inspector::Protocol::ErrorStringOr<void> setAuthCredentials(const String&, const String&, const String&) override;
+    Inspector::Protocol::ErrorStringOr<void> setActiveAndFocused(std::optional<bool>&&) override;
+    Inspector::Protocol::ErrorStringOr<void> grantPermissions(const String& origin, Ref<JSON::Array>&& permissions) override;
+    Inspector::Protocol::ErrorStringOr<void> resetPermissions() override;
+    Inspector::Protocol::ErrorStringOr<void> setOrientationOverride(std::optional<int>&& angle) override;
+
+    void didShowPage();
+
+private:
+    void setSize(int width, int height, Ref<SetDeviceMetricsOverrideCallback>&& callback);
+    void platformSetSize(int width, int height, Function<void (const String& error)>&&);
+
+    Ref<Inspector::EmulationBackendDispatcher> m_backendDispatcher;
+    WebPageProxy& m_page;
+    Vector<Function<void()>> m_commandsToRunWhenShown;
+    UncheckedKeyHashMap<String, HashSet<String>> m_permissions;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..447af997796cf74a2c6259f16aad4da5581254f9
--- /dev/null
+++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.cpp
@@ -0,0 +1,394 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MessageSenderInlines.h"
+#include "WebPageInspectorInputAgent.h"
+
+#include "NativeWebKeyboardEvent.h"
+#include "NativeWebMouseEvent.h"
+#include "NativeWebWheelEvent.h"
+#include "WebPageProxy.h"
+#include "WebTouchEvent.h"
+#include "WebWheelEvent.h"
+#include <wtf/MathExtras.h>
+#include <wtf/HexNumber.h>
+#include <WebCore/Scrollbar.h>
+
+#include "WebPageMessages.h"
+
+namespace WebKit {
+
+using namespace Inspector;
+
+namespace {
+
+template<class T>
+class CallbackList {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    ~CallbackList()
+    {
+        for (const auto& callback : m_callbacks)
+            callback->sendFailure("Page closed"_s);
+    }
+
+    void append(Ref<T>&& callback)
+    {
+        m_callbacks.append(WTFMove(callback));
+    }
+
+    void sendSuccess()
+    {
+        for (const auto& callback : m_callbacks)
+            callback->sendSuccess();
+        m_callbacks.clear();
+    }
+
+private:
+    Vector<Ref<T>> m_callbacks;
+};
+
+} // namespace
+
+class WebPageInspectorInputAgent::KeyboardCallbacks : public CallbackList<Inspector::InputBackendDispatcherHandler::DispatchKeyEventCallback> {
+};
+
+class WebPageInspectorInputAgent::MouseCallbacks : public CallbackList<Inspector::InputBackendDispatcherHandler::DispatchMouseEventCallback> {
+};
+
+class WebPageInspectorInputAgent::WheelCallbacks : public CallbackList<Inspector::InputBackendDispatcherHandler::DispatchWheelEventCallback> {
+};
+
+WebPageInspectorInputAgent::WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page)
+    : InspectorAgentBase("Input"_s)
+    , m_backendDispatcher(InputBackendDispatcher::create(backendDispatcher, this))
+    , m_page(page)
+{
+}
+
+WebPageInspectorInputAgent::~WebPageInspectorInputAgent() = default;
+
+void WebPageInspectorInputAgent::didProcessAllPendingKeyboardEvents()
+{
+    m_keyboardCallbacks->sendSuccess();
+}
+
+void WebPageInspectorInputAgent::didProcessAllPendingMouseEvents()
+{
+    m_page.setInterceptDrags(false);
+    m_mouseCallbacks->sendSuccess();
+}
+
+void WebPageInspectorInputAgent::didProcessAllPendingWheelEvents()
+{
+    m_wheelCallbacks->sendSuccess();
+}
+
+void WebPageInspectorInputAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
+{
+    m_keyboardCallbacks = makeUnique<KeyboardCallbacks>();
+    m_mouseCallbacks = makeUnique<MouseCallbacks>();
+    m_wheelCallbacks = makeUnique<WheelCallbacks>();
+}
+
+void WebPageInspectorInputAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
+{
+    m_keyboardCallbacks = nullptr;
+    m_mouseCallbacks = nullptr;
+    m_wheelCallbacks = nullptr;
+}
+
+static String keyIdentifierForKey(const String& key)
+{
+    if (key.length() == 1)
+        return makeString("U+"_s, hex(toASCIIUpper(key.characterAt(0)), 4));
+    if (key == "Delete"_s)
+        return "U+007F"_s;
+    if (key == "Backspace"_s)
+        return "U+0008"_s;
+    if (key == "ArrowUp"_s)
+        return "Up"_s;
+    if (key == "ArrowDown"_s)
+        return "Down"_s;
+    if (key == "ArrowLeft"_s)
+        return "Left"_s;
+    if (key == "ArrowRight"_s)
+        return "Right"_s;
+    if (key == "Tab"_s)
+        return "U+0009"_s;
+    if (key == "Pause"_s)
+        return "Pause"_s;
+    if (key == "ScrollLock"_s)
+        return "Scroll"_s;
+    return key;
+}
+
+void WebPageInspectorInputAgent::dispatchKeyEvent(const String& type, std::optional<int>&& modifiers, const String& text, const String& unmodifiedText, const String& code, const String& key, std::optional<int>&& windowsVirtualKeyCode, std::optional<int>&& nativeVirtualKeyCode, std::optional<bool>&& autoRepeat, std::optional<bool>&& isKeypad, std::optional<bool>&& isSystemKey, RefPtr<JSON::Array>&& commands, Ref<Inspector::InputBackendDispatcherHandler::DispatchKeyEventCallback>&& callback)
+{
+    WebEventType eventType;
+    if (type == "keyDown"_s) {
+        eventType = WebEventType::KeyDown;
+    } else if (type == "keyUp"_s) {
+        eventType = WebEventType::KeyUp;
+    } else {
+        callback->sendFailure("Unsupported event type."_s);
+        return;
+    }
+    OptionSet<WebEventModifier> eventModifiers;
+    if (modifiers)
+        eventModifiers = eventModifiers.fromRaw(*modifiers);
+    int eventWindowsVirtualKeyCode = 0;
+    if (windowsVirtualKeyCode)
+        eventWindowsVirtualKeyCode = *windowsVirtualKeyCode;
+    int eventNativeVirtualKeyCode = 0;
+    if (nativeVirtualKeyCode)
+        eventNativeVirtualKeyCode = *nativeVirtualKeyCode;
+    Vector<String> eventCommands;
+    if (commands) {
+      for (const auto& value : *commands) {
+        String command;
+        if (!value->asString(command)) {
+          callback->sendFailure("Command must be string"_s);
+          return;
+        }
+        eventCommands.append(command);
+      }
+    }
+
+    String keyIdentifier = keyIdentifierForKey(key);
+
+    bool eventIsAutoRepeat = false;
+    if (autoRepeat)
+        eventIsAutoRepeat = *autoRepeat;
+    bool eventIsKeypad = false;
+    if (isKeypad)
+        eventIsKeypad = *isKeypad;
+    bool eventIsSystemKey = false;
+    if (isSystemKey)
+        eventIsSystemKey = *isSystemKey;
+    WallTime timestamp = WallTime::now();
+
+    // cancel any active drag on Escape
+    if (eventType == WebEventType::KeyDown && key == "Escape"_s && m_page.cancelDragIfNeeded()) {
+        callback->sendSuccess();
+        return;
+    }
+
+    m_keyboardCallbacks->append(WTFMove(callback));
+    platformDispatchKeyEvent(
+        eventType,
+        text,
+        unmodifiedText,
+        key,
+        code,
+        keyIdentifier,
+        eventWindowsVirtualKeyCode,
+        eventNativeVirtualKeyCode,
+        eventIsAutoRepeat,
+        eventIsKeypad,
+        eventIsSystemKey,
+        eventModifiers,
+        eventCommands,
+        timestamp);
+}
+
+void WebPageInspectorInputAgent::dispatchMouseEvent(const String& type, int x, int y, std::optional<int>&& modifiers, const String& button, std::optional<int>&& buttons, std::optional<int>&& clickCount, std::optional<int>&& deltaX, std::optional<int>&& deltaY, Ref<DispatchMouseEventCallback>&& callback)
+{
+    WebEventType eventType = WebEventType::MouseMove;
+    if (type == "down"_s)
+        eventType = WebEventType::MouseDown;
+    else if (type == "up"_s)
+        eventType = WebEventType::MouseUp;
+    else if (type == "move"_s)
+        eventType = WebEventType::MouseMove;
+    else {
+        callback->sendFailure("Unsupported event type"_s);
+        return;
+    }
+
+    OptionSet<WebEventModifier> eventModifiers;
+    if (modifiers)
+        eventModifiers = eventModifiers.fromRaw(*modifiers);
+
+    WebMouseEventButton eventButton = WebMouseEventButton::None;
+    if (!!button) {
+        if (button == "left"_s)
+            eventButton = WebMouseEventButton::Left;
+        else if (button == "middle"_s)
+            eventButton = WebMouseEventButton::Middle;
+        else if (button == "right"_s)
+            eventButton = WebMouseEventButton::Right;
+        else if (button == "none"_s)
+            eventButton = WebMouseEventButton::None;
+        else {
+            callback->sendFailure("Unsupported eventButton"_s);
+            return;
+        }
+    }
+
+    unsigned short eventButtons = 0;
+    if (buttons)
+        eventButtons = *buttons;
+
+    int eventClickCount = 0;
+    if (clickCount)
+        eventClickCount = *clickCount;
+    int eventDeltaX = 0;
+    if (deltaX)
+        eventDeltaX = *deltaX;
+    int eventDeltaY = 0;
+    if (deltaY)
+        eventDeltaY = *deltaY;
+    m_mouseCallbacks->append(WTFMove(callback));
+
+    // Convert css coordinates to view coordinates (dip).
+    double totalScale = m_page.pageScaleFactor() * m_page.viewScaleFactor();
+    x = clampToInteger(roundf(x * totalScale));
+    y = clampToInteger(roundf(y * totalScale));
+    eventDeltaX = clampToInteger(roundf(eventDeltaX * totalScale));
+    eventDeltaY = clampToInteger(roundf(eventDeltaY * totalScale));
+
+    // We intercept any drags generated by this mouse event
+    // to prevent them from creating actual drags in the host
+    // operating system. This is turned off in the callback.
+    m_page.setInterceptDrags(true);
+#if PLATFORM(MAC)
+    UNUSED_VARIABLE(eventType);
+    UNUSED_VARIABLE(eventButton);
+    UNUSED_VARIABLE(eventClickCount);
+    platformDispatchMouseEvent(type, x, y, WTFMove(modifiers), button, WTFMove(clickCount), eventButtons);
+#elif PLATFORM(GTK) || PLATFORM(WPE) || PLATFORM(WIN)
+    WallTime timestamp = WallTime::now();
+    NativeWebMouseEvent event(
+        eventType,
+        eventButton,
+        eventButtons,
+        {x, y},
+        WebCore::IntPoint(),
+        eventDeltaX,
+        eventDeltaY,
+        0,
+        eventClickCount,
+        eventModifiers,
+        timestamp);
+    m_page.handleMouseEvent(event);
+#endif
+}
+
+void WebPageInspectorInputAgent::dispatchTapEvent(int x, int y, std::optional<int>&& modifiers, Ref<DispatchTapEventCallback>&& callback)
+{
+    m_page.legacyMainFrameProcess().sendWithAsyncReply(Messages::WebPage::FakeTouchTap(WebCore::IntPoint(x, y), modifiers ? *modifiers : 0), [callback]() {
+        callback->sendSuccess();
+    }, m_page.webPageIDInMainFrameProcess());
+}
+
+void WebPageInspectorInputAgent::dispatchTouchEvent(const String& type, std::optional<int>&& modifiers, RefPtr<JSON::Array>&& in_touchPoints, Ref<DispatchTouchEventCallback>&& callback)
+{
+    float rotationAngle = 0.0;
+    float force = 1.0;
+    const WebCore::IntSize radius(1, 1);
+
+    uint8_t unsignedModifiers = modifiers ? static_cast<uint8_t>(*modifiers) : 0;
+    OptionSet<WebEventModifier> eventModifiers;
+    eventModifiers = eventModifiers.fromRaw(unsignedModifiers);
+
+    WebPlatformTouchPoint::State state;
+    if (type == "touchStart"_s)
+        state = WebPlatformTouchPoint::State::Pressed;
+    else if (type == "touchMove"_s)
+        state = WebPlatformTouchPoint::State::Moved;
+    else if (type == "touchEnd"_s)
+        state = WebPlatformTouchPoint::State::Released;
+    else if (type == "touchCancel"_s)
+        state = WebPlatformTouchPoint::State::Cancelled;
+    else {
+        callback->sendFailure("Unsupported event type"_s);
+        return;
+    }
+
+    Vector<WebPlatformTouchPoint> touchPoints;
+    for (unsigned i = 0; i < in_touchPoints->length(); ++i) {
+        RefPtr<JSON::Value> item = in_touchPoints->get(i);
+        RefPtr<JSON::Object> obj = item->asObject();
+        if (!obj) {
+            callback->sendFailure("Invalid TouchPoint format"_s);
+            return;
+        }
+        std::optional<int> x = obj->getInteger("x"_s);
+        if (!x) {
+            callback->sendFailure("TouchPoint does not have x"_s);
+            return;
+        }
+        std::optional<int> y = obj->getInteger("y"_s);
+        if (!y) {
+            callback->sendFailure("TouchPoint does not have y"_s);
+            return;
+        }
+        std::optional<int> optionalId = obj->getInteger("id"_s);
+        int id = optionalId ? *optionalId : 0;
+        const WebCore::IntPoint position(*x, *y);
+        touchPoints.append(WebPlatformTouchPoint(id, state, position, position, radius, rotationAngle, force));
+    }
+
+    WebTouchEvent touchEvent({WebEventType::TouchStart, eventModifiers, WallTime::now()}, WTFMove(touchPoints), {}, {});
+    m_page.legacyMainFrameProcess().sendWithAsyncReply(Messages::WebPage::TouchEvent(touchEvent), [callback] (std::optional<WebEventType> eventType, bool) {
+        if (!eventType) {
+            callback->sendFailure("Failed to dispatch touch event."_s);
+            return;
+        }
+        callback->sendSuccess();
+    }, m_page.webPageIDInMainFrameProcess());
+}
+
+void WebPageInspectorInputAgent::dispatchWheelEvent(int x, int y, std::optional<int>&& modifiers, std::optional<int>&& deltaX, std::optional<int>&& deltaY, Ref<DispatchWheelEventCallback>&& callback)
+{
+    OptionSet<WebEventModifier> eventModifiers;
+    if (modifiers)
+        eventModifiers = eventModifiers.fromRaw(*modifiers);
+
+    float eventDeltaX = 0.0f;
+    if (deltaX)
+        eventDeltaX = *deltaX;
+    float eventDeltaY = 0.0f;
+    if (deltaY)
+        eventDeltaY = *deltaY;
+    m_wheelCallbacks->append(WTFMove(callback));
+
+    // Convert css coordinates to view coordinates (dip).
+    double totalScale = m_page.pageScaleFactor() * m_page.viewScaleFactor();
+    x = clampToInteger(roundf(x * totalScale));
+    y = clampToInteger(roundf(y * totalScale));
+
+    WallTime timestamp = WallTime::now();
+    WebCore::FloatSize delta = {-eventDeltaX, -eventDeltaY};
+    WebCore::FloatSize wheelTicks = delta;
+    wheelTicks.scale(1.0f / WebCore::Scrollbar::pixelsPerLineStep());
+    WebWheelEvent webEvent({WebEventType::Wheel, eventModifiers, timestamp}, {x, y}, {x, y}, delta, wheelTicks, WebWheelEvent::ScrollByPixelWheelEvent);
+    NativeWebWheelEvent event(webEvent);
+    m_page.handleNativeWheelEvent(event);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h
new file mode 100644
index 0000000000000000000000000000000000000000..26a2a3c0791c334f811ec99a630314f8e8521d02
--- /dev/null
+++ b/Source/WebKit/UIProcess/WebPageInspectorInputAgent.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebEvent.h"
+#include "WebKeyboardEvent.h"
+#include "WebMouseEvent.h"
+#include <JavaScriptCore/InspectorAgentBase.h>
+#include <JavaScriptCore/InspectorBackendDispatchers.h>
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace Inspector {
+class BackendDispatcher;
+class FrontendChannel;
+class FrontendRouter;
+}
+
+namespace WebKit {
+
+class NativeWebKeyboardEvent;
+class WebPageProxy;
+
+class WebPageInspectorInputAgent : public Inspector::InspectorAgentBase, public Inspector::InputBackendDispatcherHandler {
+    WTF_MAKE_NONCOPYABLE(WebPageInspectorInputAgent);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    WebPageInspectorInputAgent(Inspector::BackendDispatcher& backendDispatcher, WebPageProxy& page);
+    ~WebPageInspectorInputAgent() override;
+
+    void didProcessAllPendingKeyboardEvents();
+    void didProcessAllPendingMouseEvents();
+    void didProcessAllPendingWheelEvents();
+
+    void didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*) override;
+    void willDestroyFrontendAndBackend(Inspector::DisconnectReason) override;
+
+    // Protocol handler
+    void dispatchKeyEvent(const String& type, std::optional<int>&& modifiers, const String& text, const String& unmodifiedText, const String& code, const String& key, std::optional<int>&& windowsVirtualKeyCode, std::optional<int>&& nativeVirtualKeyCode, std::optional<bool>&& autoRepeat, std::optional<bool>&& isKeypad, std::optional<bool>&& isSystemKey, RefPtr<JSON::Array>&&, Ref<DispatchKeyEventCallback>&& callback) override;
+    void dispatchMouseEvent(const String& type, int x, int y, std::optional<int>&& modifiers, const String& button, std::optional<int>&& buttons, std::optional<int>&& clickCount, std::optional<int>&& deltaX, std::optional<int>&& deltaY, Ref<DispatchMouseEventCallback>&& callback) override;
+    void dispatchTapEvent(int x, int y, std::optional<int>&& modifiers, Ref<DispatchTapEventCallback>&& callback) override;
+    void dispatchTouchEvent(const String& type, std::optional<int>&& modifiers, RefPtr<JSON::Array>&& touchPoints, Ref<DispatchTouchEventCallback>&& callback) override;
+    void dispatchWheelEvent(int x, int y, std::optional<int>&& modifiers, std::optional<int>&& deltaX, std::optional<int>&& deltaY, Ref<DispatchWheelEventCallback>&& callback) override;
+
+private:
+    void platformDispatchKeyEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, Vector<String>& commands, WallTime timestamp);
+#if PLATFORM(MAC)
+    void platformDispatchMouseEvent(const String& type, int x, int y, std::optional<int>&& modifier, const String& button, std::optional<int>&& clickCount, unsigned short buttons);
+#endif
+
+    Ref<Inspector::InputBackendDispatcher> 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<KeyboardCallbacks> m_keyboardCallbacks;
+    class MouseCallbacks;
+    std::unique_ptr<MouseCallbacks> m_mouseCallbacks;
+    class WheelCallbacks;
+    std::unique_ptr<WheelCallbacks> m_wheelCallbacks;
+};
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp
index d6d3a2ad0eca1473543f79daa4a4a6fbf8c0d2a9..0c38e87c731d802974780d4d84a3e02db2fc180e 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.cpp
+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp
@@ -197,12 +197,14 @@
 #include <WebCore/ArchiveError.h>
 #include <WebCore/BitmapImage.h>
 #include <WebCore/CaptureDeviceManager.h>
+#include <WebCore/Color.h>
 #include <WebCore/CompositionHighlight.h>
 #include <WebCore/CrossSiteNavigationDataTransfer.h>
 #include <WebCore/DOMPasteAccess.h>
 #include <WebCore/DeprecatedGlobalSettings.h>
 #include <WebCore/DiagnosticLoggingClient.h>
 #include <WebCore/DiagnosticLoggingKeys.h>
+#include <WebCore/DiagnosticLoggingResultType.h>
 #include <WebCore/DragController.h>
 #include <WebCore/DragData.h>
 #include <WebCore/ElementContext.h>
@@ -225,6 +227,7 @@
 #include <WebCore/ModalContainerTypes.h>
 #include <WebCore/NotImplemented.h>
 #include <WebCore/OrganizationStorageAccessPromptQuirk.h>
+#include <WebCore/PageIdentifier.h>
 #include <WebCore/PerformanceLoggingClient.h>
 #include <WebCore/PermissionDescriptor.h>
 #include <WebCore/PermissionState.h>
@@ -232,11 +235,14 @@
 #include <WebCore/PublicSuffixStore.h>
 #include <WebCore/Quirks.h>
 #include <WebCore/RealtimeMediaSourceCenter.h>
+#include <WebCore/RegistrableDomain.h>
 #include <WebCore/RemoteUserInputEventData.h>
 #include <WebCore/RenderEmbeddedObject.h>
 #include <WebCore/ResourceLoadStatistics.h>
 #include <WebCore/RunJavaScriptParameters.h>
+#include <WebCore/SecurityOriginData.h>
 #include <WebCore/SerializedCryptoKeyWrap.h>
+#include <WebCore/ScreenOrientationType.h>
 #include <WebCore/ShareData.h>
 #include <WebCore/SharedBuffer.h>
 #include <WebCore/ShouldTreatAsContinuingLoad.h>
@@ -321,6 +327,9 @@
 #if USE(GBM)
 #include "AcceleratedBackingStoreDMABuf.h"
 #endif
+#endif
+
+#if PLATFORM(GTK) || PLATFORM(WPE)
 #include <WebCore/SelectionData.h>
 #endif
 
@@ -445,6 +454,8 @@ static constexpr Seconds tryCloseTimeoutDelay = 50_ms;
 static constexpr Seconds audibleActivityClearDelay = 10_s;
 #endif
 
+using namespace WebCore;
+
 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webPageProxyCounter, ("WebPageProxy"));
 
 #if PLATFORM(COCOA)
@@ -916,6 +927,10 @@ WebPageProxy::~WebPageProxy()
     if (preferences->mediaSessionCoordinatorEnabled())
         GroupActivitiesSessionNotifier::singleton().removeWebPage(*this);
 #endif
+
+#if PLATFORM(COCOA)
+    releaseInspectorDragPasteboard();
+#endif
 }
 
 Ref<WebPageProxy> WebPageProxy::Internals::protectedPage() const
@@ -1487,6 +1502,7 @@ void WebPageProxy::finishAttachingToWebProcess(const Site& site, ProcessLaunchRe
     if (RefPtr pageClient = this->pageClient())
         pageClient->didRelaunchProcess();
     protectedPageLoadState()->didSwapWebProcesses();
+    m_inspectorController->didFinishAttachingToWebProcess();
 }
 
 void WebPageProxy::didAttachToRunningProcess()
@@ -1495,7 +1511,7 @@ void WebPageProxy::didAttachToRunningProcess()
 
 #if ENABLE(FULLSCREEN_API)
     ASSERT(!m_fullScreenManager);
-    m_fullScreenManager = WebFullScreenManagerProxy::create(*this, protectedPageClient()->fullScreenManagerProxyClient());
+    m_fullScreenManager = WebFullScreenManagerProxy::create(*this, m_fullScreenManagerClientOverride ? *m_fullScreenManagerClientOverride : protectedPageClient()->fullScreenManagerProxyClient());
 #endif
 #if ENABLE(VIDEO_PRESENTATION_MODE)
     ASSERT(!m_playbackSessionManager);
@@ -1951,6 +1967,21 @@ Ref<WebProcessProxy> WebPageProxy::ensureProtectedRunningProcess()
     return ensureRunningProcess();
 }
 
+RefPtr<API::Navigation> WebPageProxy::loadRequestForInspector(WebCore::ResourceRequest&& request, WebFrameProxy* frame)
+{
+    if (!frame || frame == mainFrame())
+        return loadRequest(WTFMove(request), WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow);
+
+    auto navigation = m_navigationState->createLoadRequestNavigation(legacyMainFrameProcess().coreProcessIdentifier(), ResourceRequest(request), m_backForwardList->currentItem());
+    LoadParameters loadParameters;
+    loadParameters.navigationID = navigation->navigationID();
+    loadParameters.request = WTFMove(request);
+    loadParameters.shouldOpenExternalURLsPolicy = WebCore::ShouldOpenExternalURLsPolicy::ShouldNotAllow;
+    loadParameters.shouldTreatAsContinuingLoad = ShouldTreatAsContinuingLoad::No;
+    m_legacyMainFrameProcess->send(Messages::WebPage::LoadRequestInFrameForInspector(WTFMove(loadParameters), frame->frameID()), m_webPageID);
+    return navigation;
+}
+
 RefPtr<API::Navigation> WebPageProxy::loadRequest(WebCore::ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, IsPerformingHTTPFallback isPerformingHTTPFallback, std::unique_ptr<NavigationActionData>&& lastNavigationAction, API::Object* userData)
 {
     if (m_isClosed)
@@ -2042,11 +2073,29 @@ void WebPageProxy::loadRequestWithNavigationShared(Ref<WebProcessProxy>&& proces
 
         navigation->setIsLoadedWithNavigationShared(true);
         protectedProcess->markProcessAsRecentlyUsed();
-        if (!protectedProcess->isLaunching() || !url.protocolIsFile())
-            protectedProcess->send(Messages::WebPage::LoadRequest(WTFMove(loadParameters)), webPageID);
+
+        // Pause loading for new window navigation.
+        Function<void()> continuation = [
+            weakThis = WeakPtr { protectedThis },
+            weakProcess = WeakPtr { protectedProcess },
+            loadParameters = WTFMove(loadParameters),
+            webPageID,
+            url
+        ]() mutable {
+            RefPtr innerProtectedProcess = weakProcess.get();
+            RefPtr innerProtectedThis = weakThis.get();
+            if (!innerProtectedProcess || !innerProtectedThis)
+                return;
+            if (!innerProtectedProcess->isLaunching() || !url.protocolIsFile())
+                innerProtectedProcess->send(Messages::WebPage::LoadRequest(WTFMove(loadParameters)), webPageID);
+            else
+                innerProtectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTFMove(loadParameters), innerProtectedThis->internals().pageLoadState.resourceDirectoryURL(), innerProtectedThis->identifier(), true), webPageID);
+            innerProtectedProcess->startResponsivenessTimer();
+        };
+        if (protectedThis->m_inspectorController->shouldPauseLoadRequest())
+            protectedThis->m_inspectorController->setContinueLoadingCallback(WTFMove(continuation));
         else
-            protectedProcess->send(Messages::WebPage::LoadRequestWaitingForProcessLaunch(WTFMove(loadParameters), protectedThis->internals().pageLoadState.resourceDirectoryURL(), protectedThis->identifier(), true), webPageID);
-        protectedProcess->startResponsivenessTimer();
+            continuation();
     });
 }
 
@@ -2588,6 +2637,61 @@ void WebPageProxy::setControlledByAutomation(bool controlled)
     protectedWebsiteDataStore()->protectedNetworkProcess()->send(Messages::NetworkProcess::SetSessionIsControlledByAutomation(m_websiteDataStore->sessionID(), m_controlledByAutomation), 0);
 }
 
+void WebPageProxy::setAuthCredentialsForAutomation(std::optional<WebCore::Credential>&& credentials, std::optional<URL>&& origin)
+{
+    m_credentialsForAutomation = WTFMove(credentials);
+    m_authOriginForAutomation = WTFMove(origin);
+}
+
+void WebPageProxy::setPermissionsForAutomation(const UncheckedKeyHashMap<String, HashSet<String>>& permissions)
+{
+    m_permissionsForAutomation = permissions;
+}
+
+static inline WebCore::ScreenOrientationType toScreenOrientationType(int angle)
+{
+    if (angle == -90)
+        return WebCore::ScreenOrientationType::LandscapeSecondary;
+    if (angle == 180)
+        return WebCore::ScreenOrientationType::PortraitSecondary;
+    if (angle == 90)
+        return WebCore::ScreenOrientationType::LandscapePrimary;
+    return WebCore::ScreenOrientationType::PortraitPrimary;
+}
+
+void WebPageProxy::setOrientationOverride(std::optional<int>&& angle)
+{
+    auto deviceOrientation = toScreenOrientationType(angle.value_or(0));
+    if (m_screenOrientationManager)
+        m_screenOrientationManager->setCurrentOrientation(deviceOrientation);
+    m_legacyMainFrameProcess->send(Messages::WebPage::SetDeviceOrientation(angle.value_or(0)), webPageIDInMainFrameProcess());
+}
+
+std::optional<bool> WebPageProxy::permissionForAutomation(const String& origin, const String& permission) const
+{
+    auto permissions = m_permissionsForAutomation.find(origin);
+    if (permissions == m_permissionsForAutomation.end())
+        permissions = m_permissionsForAutomation.find("*"_s);
+    if (permissions == m_permissionsForAutomation.end())
+        return std::nullopt;
+    return permissions->value.contains(permission);
+}
+
+void WebPageProxy::setActiveForAutomation(std::optional<bool> active) {
+    m_activeForAutomation = active;
+    OptionSet<ActivityState> 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(IPC::Connection& connection, const String& targetId, Inspector::InspectorTargetType type)
 {
     MESSAGE_CHECK_BASE(!targetId.isEmpty(), connection);
@@ -2837,6 +2941,24 @@ void WebPageProxy::updateActivityState(OptionSet<ActivityState> flagsToUpdate)
     bool wasVisible = isViewVisible();
     RefPtr pageClient = this->pageClient();
     internals().activityState.remove(flagsToUpdate);
+
+    if (m_activeForAutomation) {
+        if (*m_activeForAutomation) {
+            if (flagsToUpdate & ActivityState::IsFocused)
+                internals().activityState.add(ActivityState::IsFocused);
+            if (flagsToUpdate & ActivityState::WindowIsActive)
+                internals().activityState.add(ActivityState::WindowIsActive);
+            if (flagsToUpdate & ActivityState::IsVisible)
+                internals().activityState.add(ActivityState::IsVisible);
+            if (flagsToUpdate & ActivityState::IsVisibleOrOccluded)
+                internals().activityState.add(ActivityState::IsVisibleOrOccluded);
+        }
+        flagsToUpdate.remove(ActivityState::IsFocused);
+        flagsToUpdate.remove(ActivityState::WindowIsActive);
+        flagsToUpdate.remove(ActivityState::IsVisible);
+        flagsToUpdate.remove(ActivityState::IsVisibleOrOccluded);
+    }
+
     if (flagsToUpdate & ActivityState::IsFocused && pageClient->isViewFocused())
         internals().activityState.add(ActivityState::IsFocused);
     if (flagsToUpdate & ActivityState::WindowIsActive && pageClient->isViewWindowActive())
@@ -3603,7 +3725,7 @@ void WebPageProxy::performDragOperation(DragData& dragData, const String& dragSt
     if (!hasRunningProcess())
         return;
 
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
     URL url { dragData.asURL() };
     if (url.protocolIsFile())
         protectedLegacyMainFrameProcess()->assumeReadAccessToBaseURL(*this, url.string(), [] { });
@@ -3631,6 +3753,8 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag
     if (!hasRunningProcess())
         return;
 
+    m_dragEventsQueued++;
+
     auto completionHandler = [this, protectedThis = Ref { *this }, action, dragData] (std::optional<WebCore::DragOperation> dragOperation, WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, const IntRect& insertionRect, const IntRect& editableElementRect, std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData) mutable {
         if (!m_pageClient)
             return;
@@ -3642,7 +3766,7 @@ void WebPageProxy::performDragControllerAction(DragControllerAction action, Drag
         dragData.setClientPosition(remoteUserInputEventData->transformedPoint);
         performDragControllerAction(action, dragData, remoteUserInputEventData->targetFrameID);
     };
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
     ASSERT(dragData.platformData());
     sendWithAsyncReplyToProcessContainingFrame(frameID, Messages::WebPage::PerformDragControllerAction(action, dragData.clientPosition(), dragData.globalPosition(), dragData.draggingSourceOperationMask(), *dragData.platformData(), dragData.flags()), WTFMove(completionHandler));
 #else
@@ -3676,14 +3800,35 @@ void WebPageProxy::didPerformDragControllerAction(std::optional<WebCore::DragOpe
     setDragCaretRect(insertionRect);
     if (RefPtr pageClient = this->pageClient())
         pageClient->didPerformDragControllerAction();
+    m_dragEventsQueued--;
+    if (m_dragEventsQueued == 0 && internals().mouseEventQueue.isEmpty())
+        m_inspectorController->didProcessAllPendingMouseEvents();
 }
 
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
 void WebPageProxy::startDrag(SelectionData&& selectionData, OptionSet<WebCore::DragOperation> dragOperationMask, std::optional<ShareableBitmap::Handle>&& dragImageHandle, IntPoint&& dragImageHotspot)
 {
-    if (RefPtr pageClient = this->pageClient()) {
-        RefPtr dragImage = dragImageHandle ? ShareableBitmap::create(WTFMove(*dragImageHandle)) : nullptr;
-        pageClient->startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage), WTFMove(dragImageHotspot));
+    if (m_interceptDrags) {
+        m_dragSelectionData = WTFMove(selectionData);
+        m_dragSourceOperationMask = dragOperationMask;
+    } else {
+#if PLATFORM(GTK)
+        if (RefPtr pageClient = this->pageClient()) {
+            RefPtr dragImage = dragImageHandle ? ShareableBitmap::create(WTFMove(*dragImageHandle)) : nullptr;
+            pageClient->startDrag(WTFMove(selectionData), dragOperationMask, WTFMove(dragImage), WTFMove(dragImageHotspot));
+        }
+#endif
+    }
+    didStartDrag();
+}
+#endif
+
+#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT)
+void WebPageProxy::startDrag(WebCore::DragDataMap&& dragDataMap)
+{
+    if (m_interceptDrags) {
+        m_dragSelectionData = WTFMove(dragDataMap);
+        m_dragSourceOperationMask = WebCore::anyDragOperation();
     }
     didStartDrag();
 }
@@ -3705,6 +3850,24 @@ void WebPageProxy::dragEnded(const IntPoint& clientPosition, const IntPoint& glo
     setDragCaretRect({ });
 }
 
+bool WebPageProxy::cancelDragIfNeeded() {
+    if (!m_dragSelectionData)
+        return false;
+    m_dragSelectionData = std::nullopt;
+#if PLATFORM(COCOA)
+    releaseInspectorDragPasteboard();
+#endif
+
+    dragEnded(m_lastMousePositionForDrag, IntPoint(), m_dragSourceOperationMask);
+    return true;
+}
+
+#if !PLATFORM(COCOA)
+void WebPageProxy::setInterceptDrags(bool shouldIntercept) {
+    m_interceptDrags = shouldIntercept;
+}
+#endif
+
 void WebPageProxy::didStartDrag()
 {
     if (!hasRunningProcess())
@@ -3712,6 +3875,26 @@ void WebPageProxy::didStartDrag()
 
     discardQueuedMouseEvents();
     send(Messages::WebPage::DidStartDrag());
+
+    if (m_interceptDrags) {
+        {
+#if PLATFORM(WIN) || PLATFORM(COCOA)
+            DragData dragData(*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask);
+#else
+            DragData dragData(&*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask);
+#endif
+            dragEntered(dragData);
+        }
+
+        {
+#if PLATFORM(WIN) || PLATFORM(COCOA)
+            DragData dragData(*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask);
+#else
+            DragData dragData(&*m_dragSelectionData, m_lastMousePositionForDrag, WebCore::IntPoint(), m_dragSourceOperationMask);
+#endif
+            dragUpdated(dragData);
+        }
+    }
 }
 
 void WebPageProxy::dragCancelled()
@@ -3859,26 +4042,47 @@ void WebPageProxy::processNextQueuedMouseEvent()
         process->startResponsivenessTimer();
     }
 
-    std::optional<Vector<SandboxExtension::Handle>> sandboxExtensions;
+    m_lastMousePositionForDrag = event.position();
+    if (!m_dragSelectionData) {
+        std::optional<Vector<SandboxExtension::Handle>> sandboxExtensions;
 
 #if PLATFORM(MAC)
-    bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEventType::MouseMove && event.button() != WebMouseEventButton::None;
-    if (eventMayStartDrag)
-        sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, process->auditToken(), SandboxExtension::MachBootstrapOptions::EnableMachBootstrap);
+        bool eventMayStartDrag = !m_currentDragOperation && eventType == WebEventType::MouseMove && event.button() != WebMouseEventButton::None;
+        if (eventMayStartDrag)
+            sandboxExtensions = SandboxExtension::createHandlesForMachLookup({ "com.apple.iconservices"_s, "com.apple.iconservices.store"_s }, process->auditToken(), SandboxExtension::MachBootstrapOptions::EnableMachBootstrap);
 #endif
 
-    auto eventWithCoalescedEvents = event;
+        auto eventWithCoalescedEvents = event;
 
-    if (event.type() == WebEventType::MouseMove) {
-        internals().coalescedMouseEvents.append(event);
-        eventWithCoalescedEvents.setCoalescedEvents(internals().coalescedMouseEvents);
-    }
+        if (event.type() == WebEventType::MouseMove) {
+            internals().coalescedMouseEvents.append(event);
+            eventWithCoalescedEvents.setCoalescedEvents(internals().coalescedMouseEvents);
+        }
 
-    LOG_WITH_STREAM(MouseHandling, stream << "UIProcess: sent mouse event " << eventType << " (queue size " << internals().mouseEventQueue.size() << ", coalesced events size " << internals().coalescedMouseEvents.size() << ")");
+        LOG_WITH_STREAM(MouseHandling, stream << "UIProcess: sent mouse event " << eventType << " (queue size " << internals().mouseEventQueue.size() << ", coalesced events size " << internals().coalescedMouseEvents.size() << ")");
 
-    sendMouseEvent(m_mainFrame->frameID(), eventWithCoalescedEvents, WTFMove(sandboxExtensions));
+        sendMouseEvent(m_mainFrame->frameID(), eventWithCoalescedEvents, WTFMove(sandboxExtensions));
 
-    internals().coalescedMouseEvents.clear();
+        internals().coalescedMouseEvents.clear();
+    } else {
+#if PLATFORM(WIN) || PLATFORM(COCOA)
+        DragData dragData(*m_dragSelectionData, event.position(), event.globalPosition(), m_dragSourceOperationMask);
+#else
+        DragData dragData(&*m_dragSelectionData, event.position(), event.globalPosition(), m_dragSourceOperationMask);
+#endif
+        if (eventType == WebEventType::MouseMove) {
+            dragUpdated(dragData);
+        } else if (eventType == WebEventType::MouseUp) {
+            if (m_currentDragOperation && m_dragSourceOperationMask.containsAny(m_currentDragOperation.value())) {
+                SandboxExtension::Handle sandboxExtensionHandle;
+                Vector<SandboxExtension::Handle> sandboxExtensionsForUpload;
+                performDragOperation(dragData, ""_s, WTFMove(sandboxExtensionHandle), WTFMove(sandboxExtensionsForUpload));
+            }
+            m_dragSelectionData = std::nullopt;
+            dragEnded(event.position(), event.globalPosition(), m_dragSourceOperationMask);
+        }
+        didReceiveEvent(eventType, true, std::nullopt);
+    }
 }
 
 void WebPageProxy::doAfterProcessingAllPendingMouseEvents(WTF::Function<void ()>&& action)
@@ -4047,6 +4251,8 @@ void WebPageProxy::wheelEventHandlingCompleted(bool wasHandled)
     
     if (RefPtr automationSession = configuration().processPool().automationSession())
         automationSession->wheelEventsFlushedForPage(*this);
+
+    m_inspectorController->didProcessAllPendingWheelEvents();
 }
 
 void WebPageProxy::cacheWheelEventScrollingAccelerationCurve(const NativeWebWheelEvent& nativeWheelEvent)
@@ -4182,7 +4388,7 @@ static TrackingType mergeTrackingTypes(TrackingType a, TrackingType b)
 
 void WebPageProxy::updateTouchEventTracking(const WebTouchEvent& touchStartEvent)
 {
-#if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA)
+#if ENABLE(ASYNC_SCROLLING) && PLATFORM(IOS_FAMILY)
     for (auto& touchPoint : touchStartEvent.touchPoints()) {
         auto location = touchPoint.locationInRootView();
         auto update = [this, location](TrackingType& trackingType, EventTrackingRegions::EventType eventType) {
@@ -4804,6 +5010,7 @@ void WebPageProxy::receivedNavigationActionPolicyDecision(WebProcessProxy& proce
 
 void WebPageProxy::receivedPolicyDecision(PolicyAction action, API::Navigation* navigation, RefPtr<API::WebsitePolicies>&& websitePolicies, Ref<API::NavigationAction>&& navigationAction, WillContinueLoadInNewProcess willContinueLoadInNewProcess, std::optional<SandboxExtension::Handle> sandboxExtensionHandle, std::optional<PolicyDecisionConsoleMessage>&& consoleMessage, CompletionHandler<void(PolicyDecision&&)>&& completionHandler)
 {
+    m_inspectorController->didReceivePolicyDecision(action, navigation ? std::optional { navigation->navigationID() } : std::nullopt);
     if (!hasRunningProcess())
         return completionHandler(PolicyDecision { });
 
@@ -5790,6 +5997,7 @@ void WebPageProxy::viewScaleFactorDidChange(IPC::Connection& connection, double
     MESSAGE_CHECK_BASE(scaleFactorIsValid(scaleFactor), connection);
     if (!legacyMainFrameProcess().hasConnection(connection))
         return;
+    m_viewScaleFactor = scaleFactor;
 
     forEachWebContentProcess([&] (auto& process, auto pageID) {
         if (&process == &legacyMainFrameProcess())
@@ -6436,6 +6644,7 @@ void WebPageProxy::didDestroyNavigationShared(Ref<WebProcessProxy>&& process, We
     RefPtr protectedPageClient { pageClient() };
 
     protectedNavigationState()->didDestroyNavigation(process->coreProcessIdentifier(), navigationID);
+    m_inspectorController->didDestroyNavigation(navigationID);
 }
 
 void WebPageProxy::didStartProvisionalLoadForFrame(FrameIdentifier frameID, FrameInfoData&& frameInfo, ResourceRequest&& request, std::optional<WebCore::NavigationIdentifier> navigationID, URL&& url, URL&& unreachableURL, const UserData& userData, WallTime timestamp)
@@ -6761,6 +6970,8 @@ void WebPageProxy::didFailProvisionalLoadForFrameShared(Ref<WebProcessProxy>&& 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;
@@ -8151,8 +8362,9 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w
     if (RefPtr page = originatingFrameInfo->page())
         openerAppInitiatedState = page->lastNavigationWasAppInitiated();
 
-    auto navigationDataForNewProcess = navigationActionData.hasOpener ? nullptr : makeUnique<NavigationActionData>(navigationActionData);
+    m_inspectorController->willCreateNewPage(windowFeatures, request.url());
 
+    auto navigationDataForNewProcess = navigationActionData.hasOpener ? nullptr : makeUnique<NavigationActionData>(navigationActionData);
     auto completionHandler = [
         this,
         protectedThis = Ref { *this },
@@ -8221,6 +8433,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w
     configuration->setInitialSandboxFlags(effectiveSandboxFlags);
     configuration->setWindowFeatures(WTFMove(windowFeatures));
     configuration->setOpenedMainFrameName(openedMainFrameName);
+    configuration->setOpenerPageForInspector(*this);
 
     if (RefPtr openerFrame = WebFrameProxy::webFrame(originatingFrameInfoData.frameID); navigationActionData.hasOpener && openerFrame) {
         configuration->setRelatedPage(*this);
@@ -8245,6 +8458,7 @@ void WebPageProxy::createNewPage(IPC::Connection& connection, WindowFeatures&& w
 void WebPageProxy::showPage()
 {
     m_uiClient->showPage(this);
+    m_inspectorController->didShowPage();
 }
 
 bool WebPageProxy::hasOpenedPage() const
@@ -8359,6 +8573,10 @@ void WebPageProxy::closePage()
     if (isClosed())
         return;
 
+#if ENABLE(CONTEXT_MENUS)
+    if (m_activeContextMenu)
+        m_activeContextMenu->hide();
+#endif
     WEBPAGEPROXY_RELEASE_LOG(Process, "closePage:");
     if (RefPtr pageClient = this->pageClient())
         pageClient->clearAllEditCommands();
@@ -8396,6 +8614,8 @@ void WebPageProxy::runJavaScriptAlert(IPC::Connection& connection, FrameIdentifi
     }
 
     runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& 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();
@@ -8417,6 +8637,8 @@ void WebPageProxy::runJavaScriptConfirm(IPC::Connection& connection, FrameIdenti
         if (RefPtr automationSession = configuration().processPool().automationSession())
             automationSession->willShowJavaScriptDialog(*this);
     }
+    if (m_inspectorDialogAgent)
+        m_inspectorDialogAgent->javascriptDialogOpening("confirm"_s, message);
 
     runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply)](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
         page.m_uiClient->runJavaScriptConfirm(page, message, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](bool result) mutable {
@@ -8440,6 +8662,8 @@ void WebPageProxy::runJavaScriptPrompt(IPC::Connection& connection, FrameIdentif
         if (RefPtr automationSession = configuration().processPool().automationSession())
             automationSession->willShowJavaScriptDialog(*this);
     }
+    if (m_inspectorDialogAgent)
+        m_inspectorDialogAgent->javascriptDialogOpening("prompt"_s, message, defaultValue);
 
     runModalJavaScriptDialog(WTFMove(frame), WTFMove(frameInfo), message, [reply = WTFMove(reply), defaultValue](WebPageProxy& page, WebFrameProxy* frame, FrameInfoData&& frameInfo, const String& message, CompletionHandler<void()>&& completion) mutable {
         page.m_uiClient->runJavaScriptPrompt(page, message, defaultValue, frame, WTFMove(frameInfo), [reply = WTFMove(reply), completion = WTFMove(completion)](auto& result) mutable {
@@ -8568,6 +8792,8 @@ void WebPageProxy::runBeforeUnloadConfirmPanel(IPC::Connection& connection, Fram
             return;
         }
     }
+    if (m_inspectorDialogAgent)
+        m_inspectorDialogAgent->javascriptDialogOpening("beforeunload"_s, message);
 
     // Since runBeforeUnloadConfirmPanel() can spin a nested run loop we need to turn off the responsiveness timer and the tryClose timer.
     protectedLegacyMainFrameProcess()->stopResponsivenessTimer();
@@ -9134,6 +9360,11 @@ void WebPageProxy::resourceLoadDidCompleteWithError(ResourceLoadInfo&& loadInfo,
 }
 
 #if ENABLE(FULLSCREEN_API)
+void WebPageProxy::setFullScreenManagerClientOverride(std::unique_ptr<WebFullScreenManagerProxyClient>&& client)
+{
+    m_fullScreenManagerClientOverride = WTFMove(client);
+}
+
 WebFullScreenManagerProxy* WebPageProxy::fullScreenManager()
 {
     return m_fullScreenManager.get();
@@ -9244,6 +9475,17 @@ void WebPageProxy::requestDOMPasteAccess(IPC::Connection& connection, DOMPasteAc
         }
     }
 
+    if (isControlledByAutomation()) {
+        DOMPasteAccessResponse response = DOMPasteAccessResponse::DeniedForGesture;
+        if (permissionForAutomation(originIdentifier, "clipboard-read"_s).value_or(false)) {
+            response = DOMPasteAccessResponse::GrantedForGesture;
+            // Grant access to general pasteboard.
+            willPerformPasteCommand(DOMPasteAccessCategory::General, [] () { }, frameID);
+        }
+        completionHandler(response);
+        return;
+    }
+
     m_pageClient->requestDOMPasteAccess(pasteAccessCategory, requiresInteraction, elementRect, originIdentifier, WTFMove(completionHandler));
 }
 
@@ -10241,6 +10483,8 @@ void WebPageProxy::mouseEventHandlingCompleted(std::optional<WebEventType> event
         if (RefPtr automationSession = configuration().processPool().automationSession())
             automationSession->mouseEventsFlushedForPage(*this);
         didFinishProcessingAllPendingMouseEvents();
+        if (m_dragEventsQueued == 0)
+            m_inspectorController->didProcessAllPendingMouseEvents();
     }
 }
 
@@ -10275,6 +10519,7 @@ void WebPageProxy::keyEventHandlingCompleted(std::optional<WebEventType> eventTy
     if (!canProcessMoreKeyEvents) {
         if (RefPtr automationSession = configuration().processPool().automationSession())
             automationSession->keyboardEventsFlushedForPage(*this);
+        m_inspectorController->didProcessAllPendingKeyboardEvents();
     }
 }
 
@@ -10696,7 +10941,10 @@ void WebPageProxy::dispatchProcessDidTerminate(WebProcessProxy& process, Process
     if (m_preferences->siteIsolationEnabled())
         m_browsingContextGroup->processDidTerminate(*this, process);
 
-    bool handledByClient = false;
+    bool handledByClient = m_inspectorController->pageCrashed(reason);
+    if (handledByClient)
+        return;
+
     if (m_loaderClient)
         handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this);
     else
@@ -11343,6 +11591,8 @@ WebPageCreationParameters WebPageProxy::creationParameters(WebProcessProxy& proc
 
     parameters.httpsUpgradeEnabled = preferences->upgradeKnownHostsToHTTPSEnabled() ? configuration->httpsUpgradeEnabled() : false;
 
+    parameters.shouldPauseInInspectorWhenShown = m_inspectorController->shouldPauseInInspectorWhenShown();
+
 #if PLATFORM(IOS) || PLATFORM(VISION)
     // FIXME: This is also being passed over the to WebProcess via the PreferencesStore.
     parameters.allowsDeprecatedSynchronousXMLHttpRequestDuringUnload = allowsDeprecatedSynchronousXMLHttpRequestDuringUnload();
@@ -11502,8 +11752,42 @@ void WebPageProxy::allowGamepadAccess()
 
 #endif // ENABLE(GAMEPAD)
 
+bool WebPageProxy::shouldSendAutomationCredentialsForProtectionSpace(const WebProtectionSpace& protectionSpace)
+{
+    if (m_authOriginForAutomation.has_value() && !m_authOriginForAutomation.value().isEmpty()) {
+        switch (protectionSpace.serverType()) {
+            case WebCore::ProtectionSpace::ServerType::HTTP:
+                if (m_authOriginForAutomation.value().protocol() != "http"_s)
+                    return false;
+                break;
+            case WebCore::ProtectionSpace::ServerType::HTTPS:
+                if (m_authOriginForAutomation.value().protocol() != "https"_s)
+                    return false;
+                break;
+            default:
+                return false;
+        }
+
+        if (protectionSpace.host() != m_authOriginForAutomation.value().host())
+            return false;
+
+        if (protectionSpace.port() != m_authOriginForAutomation.value().port().value_or(0))
+            return false;
+    }
+    return true;
+}
+
 void WebPageProxy::didReceiveAuthenticationChallengeProxy(Ref<AuthenticationChallengeProxy>&& authenticationChallenge, NegotiatedLegacyTLS negotiatedLegacyTLS)
 {
+    if (m_credentialsForAutomation.has_value()) {
+        if (m_credentialsForAutomation->isEmpty() || authenticationChallenge->core().previousFailureCount() ||
+            !shouldSendAutomationCredentialsForProtectionSpace(*authenticationChallenge->protectionSpace())) {
+            authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::PerformDefaultHandling);
+            return;
+        }
+        authenticationChallenge->listener().completeChallenge(AuthenticationChallengeDisposition::UseCredential, *m_credentialsForAutomation);
+        return;
+    }
     if (negotiatedLegacyTLS == NegotiatedLegacyTLS::Yes) {
         m_navigationClient->shouldAllowLegacyTLS(*this, authenticationChallenge.get(), [this, protectedThis = Ref { *this }, authenticationChallenge] (bool shouldAllowLegacyTLS) {
             if (shouldAllowLegacyTLS)
@@ -11597,6 +11881,12 @@ void WebPageProxy::requestGeolocationPermissionForFrame(IPC::Connection& connect
             request->deny();
     };
 
+    if (isControlledByAutomation()) {
+        auto securityOrigin = frameInfo.securityOrigin.securityOrigin();
+        completionHandler(permissionForAutomation(securityOrigin->toString(), "geolocation"_s).value_or(false));
+        return;
+    }
+
     // FIXME: Once iOS migrates to the new WKUIDelegate SPI, clean this up
     // and make it one UIClient call that calls the completionHandler with false
     // if there is no delegate instead of returning the completionHandler
@@ -11659,6 +11949,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi
             shouldChangeDeniedToPrompt = false;
 
         if (sessionID().isEphemeral()) {
+            auto permission = permissionForAutomation(clientOrigin.topOrigin.toString(), name);
+            if (permission.has_value()) {
+                completionHandler(permission.value() ? PermissionState::Granted : PermissionState::Denied);
+                return;
+            }
+
             completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied);
             return;
         }
@@ -11673,6 +11969,12 @@ void WebPageProxy::queryPermission(const ClientOrigin& clientOrigin, const Permi
         return;
     }
 
+    auto permission = permissionForAutomation(clientOrigin.topOrigin.toString(), name);
+    if (permission.has_value()) {
+        completionHandler(permission.value() ? PermissionState::Granted : PermissionState::Denied);
+        return;
+    }
+
     if (!canAPISucceed) {
         completionHandler(shouldChangeDeniedToPrompt ? PermissionState::Prompt : PermissionState::Denied);
         return;
diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h
index 304e437942e1269b0ada34b4f11789b84713b1b1..8e4f32d830657337e6451932bb1f75b2f3d1430e 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.h
+++ b/Source/WebKit/UIProcess/WebPageProxy.h
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "APIObject.h"
+#include "APIWebsitePolicies.h"
 #include "MessageReceiver.h"
 #include <WebCore/FrameIdentifier.h>
 #include <WebCore/LayerTreeAsTextOptions.h>
@@ -40,6 +41,20 @@
 #include <wtf/ProcessID.h>
 #include <wtf/UniqueRef.h>
 #include <wtf/WeakHashSet.h>
+#include "InspectorDialogAgent.h"
+#include "WebProtectionSpace.h"
+#include <WebCore/Credential.h>
+#include <WebCore/IntRect.h>
+#include "WebPageDiagnosticLoggingClient.h"
+#include "WebPageInjectedBundleClient.h"
+#include "WebPreferences.h"
+#include "ViewSnapshotStore.h"
+
+OBJC_CLASS NSPasteboard;
+
+#if PLATFORM(GTK) || PLATFORM(WPE)
+#include <WebCore/SelectionData.h>
+#endif
 
 #if USE(DICTATION_ALTERNATIVES)
 #include <WebCore/PlatformTextAlternatives.h>
@@ -122,6 +137,7 @@ class DragData;
 class Exception;
 class FloatPoint;
 class FloatQuad;
+typedef UncheckedKeyHashMap<unsigned, Vector<String>> DragDataMap;
 class FloatRect;
 class FloatSize;
 class FontAttributeChanges;
@@ -467,6 +483,7 @@ class WebExtensionController;
 class WebFramePolicyListenerProxy;
 class WebFrameProxy;
 class WebFullScreenManagerProxy;
+class WebFullScreenManagerProxyClient;
 class WebInspectorUIProxy;
 class WebKeyboardEvent;
 class WebMouseEvent;
@@ -695,6 +712,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();
@@ -728,6 +747,7 @@ public:
     bool hasSleepDisabler() const;
 
 #if ENABLE(FULLSCREEN_API)
+    void setFullScreenManagerClientOverride(std::unique_ptr<WebFullScreenManagerProxyClient>&&);
     WebFullScreenManagerProxy* fullScreenManager();
 
     API::FullscreenClient& fullscreenClient() const { return *m_fullscreenClient; }
@@ -817,6 +837,12 @@ public:
 
     void setPageLoadStateObserver(RefPtr<PageLoadStateObserverBase>&&);
 
+    void setAuthCredentialsForAutomation(std::optional<WebCore::Credential>&&, std::optional<URL>&&);
+    void setPermissionsForAutomation(const UncheckedKeyHashMap<String, HashSet<String>>&);
+    void setOrientationOverride(std::optional<int>&& angle);
+    void setActiveForAutomation(std::optional<bool> active);
+    void logToStderr(const String& str);
+
     void initializeWebPage(const WebCore::Site&, WebCore::SandboxFlags);
     void setDrawingArea(RefPtr<DrawingAreaProxy>&&);
 
@@ -848,6 +874,8 @@ public:
     RefPtr<API::Navigation> loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback);
     RefPtr<API::Navigation> loadRequest(WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, WebCore::IsPerformingHTTPFallback, std::unique_ptr<NavigationActionData>&&, API::Object* userData = nullptr);
 
+    RefPtr<API::Navigation> loadRequestForInspector(WebCore::ResourceRequest&&, WebFrameProxy*);
+
     RefPtr<API::Navigation> loadFile(const String& fileURL, const String& resourceDirectoryURL, bool isAppInitiated = true, API::Object* userData = nullptr);
     RefPtr<API::Navigation> loadData(Ref<WebCore::SharedBuffer>&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData = nullptr);
     RefPtr<API::Navigation> loadData(Ref<WebCore::SharedBuffer>&&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldOpenExternalURLsPolicy);
@@ -931,6 +959,7 @@ public:
 
     PageClient* pageClient() const;
     RefPtr<PageClient> protectedPageClient() const;
+    bool hasPageClient() const { return !!m_pageClient; }
 
     void setViewNeedsDisplay(const WebCore::Region&);
     void requestScroll(const WebCore::FloatPoint& scrollPosition, const WebCore::IntPoint& scrollOrigin, WebCore::ScrollIsAnimated);
@@ -1556,14 +1585,20 @@ public:
     void didStartDrag();
     void dragCancelled();
     void setDragCaretRect(const WebCore::IntRect&);
+    void setInterceptDrags(bool shouldIntercept);
+    bool cancelDragIfNeeded();
 #if PLATFORM(COCOA)
     void startDrag(const WebCore::DragItem&, WebCore::ShareableBitmapHandle&& dragImageHandle);
     void setPromisedDataForImage(IPC::Connection&, const String& pasteboardName, WebCore::SharedMemoryHandle&& imageHandle, const String& filename, const String& extension,
         const String& title, const String& url, const String& visibleURL, WebCore::SharedMemoryHandle&& archiveHandle, const String& originIdentifier);
+    void releaseInspectorDragPasteboard();
 #endif
-#if PLATFORM(GTK)
+#if PLATFORM(GTK) || PLATFORM(WPE)
     void startDrag(WebCore::SelectionData&&, OptionSet<WebCore::DragOperation>, std::optional<WebCore::ShareableBitmapHandle>&& dragImage, WebCore::IntPoint&& dragImageHotspot);
 #endif
+#if PLATFORM(WIN)
+    void startDrag(WebCore::DragDataMap&& dragDataMap);
+#endif
 #endif
 
     void processDidBecomeUnresponsive();
@@ -1808,6 +1843,7 @@ public:
     void setViewportSizeForCSSViewportUnits(const WebCore::FloatSize&);
     WebCore::FloatSize viewportSizeForCSSViewportUnits() const;
 
+    bool shouldSendAutomationCredentialsForProtectionSpace(const WebProtectionSpace&);
     void didReceiveAuthenticationChallengeProxy(Ref<AuthenticationChallengeProxy>&&, NegotiatedLegacyTLS);
     void negotiatedLegacyTLS();
     void didNegotiateModernTLS(const URL&);
@@ -1841,6 +1877,8 @@ public:
 #if PLATFORM(COCOA) || PLATFORM(GTK)
     RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&);
     RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&, ForceSoftwareCapturingViewportSnapshot);
+#elif PLATFORM(WPE)
+    RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&) { return nullptr; }
 #endif
 
     void wrapCryptoKey(Vector<uint8_t>&&, CompletionHandler<void(std::optional<Vector<uint8_t>>&&)>&&);
@@ -2805,6 +2843,7 @@ private:
     RefPtr<API::Navigation> launchProcessForReload();
 
     void requestNotificationPermission(const String& originString, CompletionHandler<void(bool allowed)>&&);
+    std::optional<bool> permissionForAutomation(const String& origin, const String& permission) const;
 
     void didChangeContentSize(const WebCore::IntSize&);
     void didChangeIntrinsicContentSize(const WebCore::IntSize&);
@@ -3326,8 +3365,10 @@ private:
     String m_openedMainFrameName;
 
     RefPtr<WebInspectorUIProxy> m_inspector;
+    InspectorDialogAgent* m_inspectorDialogAgent { nullptr };
 
 #if ENABLE(FULLSCREEN_API)
+    std::unique_ptr<WebFullScreenManagerProxyClient> m_fullScreenManagerClientOverride;
     RefPtr<WebFullScreenManagerProxy> m_fullScreenManager;
     std::unique_ptr<API::FullscreenClient> m_fullscreenClient;
 #endif
@@ -3527,6 +3568,22 @@ private:
     std::optional<WebCore::DragOperation> m_currentDragOperation;
     bool m_currentDragIsOverFileInput { false };
     unsigned m_currentDragNumberOfFilesToBeAccepted { 0 };
+    WebCore::IntRect m_currentDragCaretRect;
+    WebCore::IntRect m_currentDragCaretEditableElementRect;
+    bool m_interceptDrags { false };
+    OptionSet<WebCore::DragOperation> m_dragSourceOperationMask;
+    WebCore::IntPoint m_lastMousePositionForDrag;
+    int m_dragEventsQueued = 0;
+#if PLATFORM(COCOA)
+    std::optional<String> m_dragSelectionData;
+    String m_overrideDragPasteboardName;
+#endif
+#if PLATFORM(GTK) || PLATFORM(WPE)
+    std::optional<WebCore::SelectionData> m_dragSelectionData;
+#endif
+#if PLATFORM(WIN)
+    std::optional<WebCore::DragDataMap> m_dragSelectionData;
+#endif
 #endif
 
     bool m_mainFrameHasHorizontalScrollbar { false };
@@ -3698,6 +3755,10 @@ private:
         RefPtr<API::Object> messageBody;
     };
     Vector<InjectedBundleMessage> m_pendingInjectedBundleMessages;
+    std::optional<WebCore::Credential> m_credentialsForAutomation;
+    std::optional<URL> m_authOriginForAutomation;
+    UncheckedKeyHashMap<String, HashSet<String>> m_permissionsForAutomation;
+    std::optional<bool> m_activeForAutomation;
         
 #if PLATFORM(IOS_FAMILY) && ENABLE(DEVICE_ORIENTATION)
     RefPtr<WebDeviceOrientationUpdateProviderProxy> m_webDeviceOrientationUpdateProviderProxy;
diff --git a/Source/WebKit/UIProcess/WebPageProxy.messages.in b/Source/WebKit/UIProcess/WebPageProxy.messages.in
index e28a28652ad75c4f4efe1b52868a10ab8ea4691b..218fe89bf5e342e496ccc986cc6bee750e23eb38 100644
--- a/Source/WebKit/UIProcess/WebPageProxy.messages.in
+++ b/Source/WebKit/UIProcess/WebPageProxy.messages.in
@@ -34,6 +34,7 @@ messages -> WebPageProxy {
     RunJavaScriptConfirm(WebCore::FrameIdentifier frameID, struct WebKit::FrameInfoData frameInfo, String message) -> (bool result) Synchronous
     RunJavaScriptPrompt(WebCore::FrameIdentifier frameID, struct WebKit::FrameInfoData frameInfo, String message, String defaultValue) -> (String result) Synchronous
     MouseDidMoveOverElement(struct WebKit::WebHitTestResultData hitTestResultData, OptionSet<WebKit::WebEventModifier> modifiers, WebKit::UserData userData)
+    LogToStderr(String text)
 
     DidReceiveEvent(enum:uint8_t WebKit::WebEventType eventType, bool handled, struct std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData)
     SetCursor(WebCore::Cursor cursor)
@@ -327,10 +328,14 @@ messages -> WebPageProxy {
     StartDrag(struct WebCore::DragItem dragItem, WebCore::ShareableBitmapHandle dragImage)
     SetPromisedDataForImage(String pasteboardName, WebCore::SharedMemory::Handle imageHandle, String filename, String extension, String title, String url, String visibleURL, WebCore::SharedMemory::Handle archiveHandle, String originIdentifier)
 #endif
-#if PLATFORM(GTK) && ENABLE(DRAG_SUPPORT)
+#if (PLATFORM(GTK) || PLATFORM(WPE)) && ENABLE(DRAG_SUPPORT)
     StartDrag(WebCore::SelectionData selectionData, OptionSet<WebCore::DragOperation> dragOperationMask, std::optional<WebCore::ShareableBitmapHandle> dragImage, WebCore::IntPoint dragImageHotspot)
 #endif
 
+#if PLATFORM(WIN) && ENABLE(DRAG_SUPPORT)
+    StartDrag(UncheckedKeyHashMap<unsigned, Vector<String>> dragDataMap)
+#endif
+
 #if PLATFORM(IOS_FAMILY) && ENABLE(DRAG_SUPPORT)
     DidHandleDragStartRequest(bool started)
     DidHandleAdditionalDragItemsRequest(bool added)
diff --git a/Source/WebKit/UIProcess/WebProcessCache.cpp b/Source/WebKit/UIProcess/WebProcessCache.cpp
index a52ebc98999087f70ff74a3a21355409a1224f95..460b87c90611bbbbea5970d6a45aacb8c17be0f3 100644
--- a/Source/WebKit/UIProcess/WebProcessCache.cpp
+++ b/Source/WebKit/UIProcess/WebProcessCache.cpp
@@ -92,6 +92,10 @@ bool WebProcessCache::canCacheProcess(WebProcessProxy& process) const
         return false;
     }
 
+    auto sessionID = process.websiteDataStore()->sessionID();
+    if (sessionID.isEphemeral() && !process.processPool().hasPagesUsingWebsiteDataStore(*process.websiteDataStore()))
+        return false;
+
     return true;
 }
 
diff --git a/Source/WebKit/UIProcess/WebProcessPool.cpp b/Source/WebKit/UIProcess/WebProcessPool.cpp
index 640f3f891ef5fc07eb88dbe2d5c74430061bfbac..6bac8aa05755a9686002d35e47aa8eee648993ee 100644
--- a/Source/WebKit/UIProcess/WebProcessPool.cpp
+++ b/Source/WebKit/UIProcess/WebProcessPool.cpp
@@ -438,10 +438,10 @@ void WebProcessPool::setAutomationClient(std::unique_ptr<API::AutomationClient>&
 
 void WebProcessPool::setOverrideLanguages(Vector<String>&& languages)
 {
-    WebKit::setOverrideLanguages(WTFMove(languages));
+    m_configuration->setOverrideLanguages(WTFMove(languages));
 
     LOG_WITH_STREAM(Language, stream << "WebProcessPool is setting OverrideLanguages: " << languages);
-    sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(overrideLanguages()));
+    sendToAllProcesses(Messages::WebProcess::UserPreferredLanguagesChanged(m_configuration->overrideLanguages()));
 
 #if ENABLE(GPU_PROCESS)
     if (RefPtr gpuProcess = GPUProcessProxy::singletonIfCreated())
@@ -449,9 +449,10 @@ void WebProcessPool::setOverrideLanguages(Vector<String>&& languages)
 #endif
 #if USE(SOUP)
     for (Ref networkProcess : NetworkProcessProxy::allNetworkProcesses())
-        networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(overrideLanguages()), 0);
+        networkProcess->send(Messages::NetworkProcess::UserPreferredLanguagesChanged(m_configuration->overrideLanguages()), 0);
 #endif
 }
+/* end playwright revert fb205fb */
 
 void WebProcessPool::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
 {
@@ -928,7 +929,7 @@ void WebProcessPool::initializeNewWebProcess(WebProcessProxy& process, WebsiteDa
 #endif
 
     parameters.cacheModel = LegacyGlobalSettings::singleton().cacheModel();
-    parameters.overrideLanguages = overrideLanguages();
+    parameters.overrideLanguages = configuration().overrideLanguages(); /* playwright revert fb205fb */
     LOG_WITH_STREAM(Language, stream << "WebProcessPool is initializing a new web process with overrideLanguages: " << parameters.overrideLanguages);
 
     parameters.urlSchemesRegisteredAsEmptyDocument = copyToVector(m_schemesToRegisterAsEmptyDocument);
diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp
index a9335579083e325126d2c1de5ca89108a5d9f4a8..c42e19f3f9aeca5202fbaf6cf88c922c3508d4bf 100644
--- a/Source/WebKit/UIProcess/WebProcessProxy.cpp
+++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp
@@ -192,6 +192,11 @@ Vector<Ref<WebProcessProxy>> WebProcessProxy::allProcesses()
     });
 }
 
+Vector<Ref<WebProcessProxy>> WebProcessProxy::allProcessesForInspector()
+{
+    return copyToVector(allProcesses());
+}
+
 RefPtr<WebProcessProxy> WebProcessProxy::processForIdentifier(ProcessIdentifier identifier)
 {
     return allProcessMap().get(identifier);
@@ -554,6 +559,26 @@ void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOpt
     if (WebKit::isInspectorProcessPool(protectedProcessPool()))
         launchOptions.extraInitializationData.add<HashTranslatorASCIILiteral>("inspector-process"_s, "1"_s);
 
+    /* playwright revert fb205fb, 50f8fee */
+    LOG(Language, "WebProcessProxy is getting launch options.");
+    auto overrideLanguages = m_processPool->configuration().overrideLanguages();
+    if (overrideLanguages.isEmpty()) {
+        LOG(Language, "overrideLanguages() reports empty. Calling platformOverrideLanguages()");
+        overrideLanguages = platformOverrideLanguages();
+    }
+    if (!overrideLanguages.isEmpty()) {
+        StringBuilder languageString;
+        for (size_t i = 0; i < overrideLanguages.size(); ++i) {
+            if (i)
+                languageString.append(',');
+            languageString.append(overrideLanguages[i]);
+        }
+        LOG_WITH_STREAM(Language, stream << "Setting WebProcess's launch OverrideLanguages to " << languageString);
+        launchOptions.extraInitializationData.add<HashTranslatorASCIILiteral>("OverrideLanguages"_s, languageString.toString());
+    } else
+        LOG(Language, "overrideLanguages is still empty. Not setting WebProcess's launch OverrideLanguages.");
+    /* end playwright revert fb205fb, 50f8fee */
+
     launchOptions.nonValidInjectedCodeAllowed = shouldAllowNonValidInjectedCode();
 
     if (isPrewarmed())
diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h
index 7d9e93ea058e783f32ef1d0a6ca0182175da64c4..303655051c9b8f91868ebaaca74a61d851ddbd59 100644
--- a/Source/WebKit/UIProcess/WebProcessProxy.h
+++ b/Source/WebKit/UIProcess/WebProcessProxy.h
@@ -177,6 +177,7 @@ public:
 
     static void forWebPagesWithOrigin(PAL::SessionID, const WebCore::SecurityOriginData&, const Function<void(WebPageProxy&)>&);
     static Vector<std::pair<WebCore::ProcessIdentifier, WebCore::RegistrableDomain>> allowedFirstPartiesForCookies();
+    static Vector<Ref<WebProcessProxy>> allProcessesForInspector();
 
     void initializeWebProcess(WebProcessCreationParameters&&);
 
diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
index 069845674e159025683e063219431aa20e3a5a3e..8f3963b6316404bfb0c13305d1272cf15002b1f4 100644
--- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
+++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
@@ -314,7 +314,8 @@ SOAuthorizationCoordinator& WebsiteDataStore::soAuthorizationCoordinator(const W
 
 static Ref<NetworkProcessProxy> networkProcessForSession(PAL::SessionID sessionID)
 {
-#if ((PLATFORM(GTK) || PLATFORM(WPE)) && !ENABLE(2022_GLIB_API))
+// Playwright wants to isolate per BrowserContext.
+#if ((PLATFORM(GTK) || PLATFORM(WPE)))
     if (sessionID.isEphemeral()) {
         // Reuse a previous persistent session network process for ephemeral sessions.
         for (auto& dataStore : allDataStores().values()) {
@@ -2343,6 +2344,12 @@ void WebsiteDataStore::originDirectoryForTesting(WebCore::ClientOrigin&& origin,
     protectedNetworkProcess()->websiteDataOriginDirectoryForTesting(m_sessionID, WTFMove(origin), type, WTFMove(completionHandler));
 }
 
+void WebsiteDataStore::setDownloadForAutomation(std::optional<bool> allow, const String& downloadPath)
+{
+    m_allowDownloadForAutomation = allow;
+    m_downloadPathForAutomation = downloadPath;
+}
+
 #if ENABLE(APP_BOUND_DOMAINS)
 void WebsiteDataStore::hasAppBoundSession(CompletionHandler<void(bool)>&& completionHandler) const
 {
diff --git a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
index ca5511eaf8b0af08a20c44fa2350b3a1d94d46cb..9855dc78e84374042d3f28e980475b4dd639a8c6 100644
--- a/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
+++ b/Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.h
@@ -97,6 +97,7 @@ class DeviceIdHashSaltStorage;
 class DownloadProxy;
 class NetworkProcessProxy;
 class SOAuthorizationCoordinator;
+class DownloadProxy;
 class VirtualAuthenticatorManager;
 class WebPageProxy;
 class WebProcessPool;
@@ -112,12 +113,21 @@ enum class UnifiedOriginStorageLevel : uint8_t;
 enum class WebsiteDataFetchOption : uint8_t;
 enum class WebsiteDataType : uint32_t;
 
+struct FrameInfoData;
 struct ITPThirdPartyData;
 struct NetworkProcessConnectionInfo;
 struct WebPushMessage;
 struct WebsiteDataRecord;
 struct WebsiteDataStoreParameters;
 
+class DownloadInstrumentation {
+public:
+    virtual void downloadCreated(const String& uuid, const WebCore::ResourceRequest&, const FrameInfoData& frameInfoData, WebPageProxy* page, RefPtr<DownloadProxy> 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<API::Object::Type::WebsiteDataStore>, public CanMakeWeakPtr<WebsiteDataStore> {
 public:
     static Ref<WebsiteDataStore> defaultDataStore();
@@ -306,11 +316,13 @@ public:
     const WebCore::CurlProxySettings& networkProxySettings() const { return m_proxySettings; }
 #endif
 
-#if USE(SOUP)
+#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN)
     void setPersistentCredentialStorageEnabled(bool);
     bool persistentCredentialStorageEnabled() const { return m_persistentCredentialStorageEnabled && isPersistent(); }
     void setIgnoreTLSErrors(bool);
     bool ignoreTLSErrors() const { return m_ignoreTLSErrors; }
+#endif
+#if USE(SOUP)
     void setNetworkProxySettings(WebCore::SoupNetworkProxySettings&&);
     const WebCore::SoupNetworkProxySettings& networkProxySettings() const { return m_networkProxySettings; }
     void setCookiePersistentStorage(const String&, SoupCookiePersistentStorageType);
@@ -400,6 +412,12 @@ public:
     static const String& defaultBaseDataDirectory();
 #endif
 
+    void setDownloadForAutomation(std::optional<bool> allow, const String& downloadPath);
+    std::optional<bool> allowDownloadForAutomation() { return m_allowDownloadForAutomation; };
+    String downloadPathForAutomation() { return m_downloadPathForAutomation; };
+    void setDownloadInstrumentation(DownloadInstrumentation* instrumentation) { m_downloadInstrumentation = instrumentation; };
+    DownloadInstrumentation* downloadInstrumentation() { return m_downloadInstrumentation; };
+
     void resetQuota(CompletionHandler<void()>&&);
     void resetStoragePersistedState(CompletionHandler<void()>&&);
 #if PLATFORM(IOS_FAMILY)
@@ -576,9 +594,11 @@ private:
     WebCore::CurlProxySettings m_proxySettings;
 #endif
 
-#if USE(SOUP)
+#if USE(SOUP) || PLATFORM(COCOA) || PLATFORM(WIN)
     bool m_persistentCredentialStorageEnabled { true };
     bool m_ignoreTLSErrors { true };
+#endif
+#if USE(SOUP)
     WebCore::SoupNetworkProxySettings m_networkProxySettings;
     String m_cookiePersistentStoragePath;
     SoupCookiePersistentStorageType m_cookiePersistentStorageType { SoupCookiePersistentStorageType::SQLite };
@@ -605,6 +625,10 @@ private:
     RefPtr<API::HTTPCookieStore> m_cookieStore;
     RefPtr<NetworkProcessProxy> m_networkProcess;
 
+    std::optional<bool> m_allowDownloadForAutomation;
+    String m_downloadPathForAutomation;
+    DownloadInstrumentation* m_downloadInstrumentation { nullptr };
+
 #if HAVE(APP_SSO)
     std::unique_ptr<SOAuthorizationCoordinator> m_soAuthorizationCoordinator;
 #endif
diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp
index ac64c2a3cb5d1e8e46ba1835623a5c12825e3ea1..6ad7a5adc5198ae035c5cb815b6db8f033910f3a 100644
--- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp
+++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.cpp
@@ -114,6 +114,14 @@ void GeoclueGeolocationProvider::stop()
     }
 
     m_sourceType = LocationProviderSource::Unknown;
+    stopGeoclueClient();
+    g_cancellable_cancel(m_cancellable_start.get());
+    m_cancellable_start = nullptr;
+    g_cancellable_cancel(m_cancellable_setup.get());
+    m_cancellable_setup = nullptr;
+    g_cancellable_cancel(m_cancellable_create.get());
+    m_cancellable_create = nullptr;
+    destroyStateLater();
 }
 
 void GeoclueGeolocationProvider::setEnableHighAccuracy(bool enabled)
@@ -386,6 +394,8 @@ void GeoclueGeolocationProvider::createGeoclueClient(const char* clientPath)
         return;
     }
 
+    g_cancellable_cancel(m_cancellable_create.get());
+    m_cancellable_create = adoptGRef(g_cancellable_new());
     g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_NONE, nullptr,
         "org.freedesktop.GeoClue2", clientPath, "org.freedesktop.GeoClue2.Client", m_cancellable.get(),
         [](GObject*, GAsyncResult* result, gpointer userData) {
diff --git a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h
index 96bf77411e2e1f4c835f56b409dc179977d197ee..512af5ffce511711b502248e34e49e45e85dbc4e 100644
--- a/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h
+++ b/Source/WebKit/UIProcess/geoclue/GeoclueGeolocationProvider.h
@@ -92,6 +92,9 @@ private:
         unsigned responseSignalId;
     } m_portal;
     GRefPtr<GCancellable> m_cancellable;
+    GRefPtr<GCancellable> m_cancellable_start;
+    GRefPtr<GCancellable> m_cancellable_setup;
+    GRefPtr<GCancellable> m_cancellable_create;
     UpdateNotifyFunction m_updateNotifyFunction;
     LocationProviderSource m_sourceType { LocationProviderSource::Unknown };
     RunLoop::Timer m_destroyLaterTimer;
diff --git a/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac01ad1653b22a0f22c45a196659e68fc22d7f32
--- /dev/null
+++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorPlaywrightAgentClientGLib.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorPlaywrightAgent.h"
+#include "PageClient.h"
+#include "ViewSnapshotStore.h"
+#include "WebAutomationSession.h"
+#include "WebKitBrowserInspectorPrivate.h"
+#include "WebKitWebContextPrivate.h"
+#include "WebKitWebsiteDataManagerPrivate.h"
+#include "WebKitWebViewPrivate.h"
+#include "WebPageProxy.h"
+#if USE(CAIRO)
+#include <WebCore/ImageBufferUtilitiesCairo.h>
+#endif
+#if USE(SKIA)
+#include <WebCore/ImageBufferUtilitiesSkia.h>
+#endif
+#include <wtf/HashMap.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/Base64.h>
+#include <wtf/text/StringView.h>
+#include <wtf/text/WTFString.h>
+
+
+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<char**>(ignoreHosts)));
+    return settings;
+}
+
+static WebCore::SoupNetworkProxySettings parseProxySettings(const String& proxyServer, const String& proxyBypassList)
+{
+    Vector<const char*> ignoreHosts;
+    if (!proxyBypassList.isEmpty()) {
+        Vector<String> tokens = proxyBypassList.split(',');
+        Vector<CString> 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<WebPageProxy> InspectorPlaywrightAgentClientGlib::createPage(WTF::String& error, const BrowserContext& browserContext)
+{
+    auto sessionID = browserContext.dataStore->sessionID();
+    WebKitWebContext* context = m_idToContext.get(sessionID);
+    if (!context && !browserContext.dataStore->isPersistent()) {
+        ASSERT_NOT_REACHED();
+        error = "Context with provided id not found"_s;
+        return nullptr;
+    }
+
+    RefPtr<WebPageProxy> page = webkitBrowserInspectorCreateNewPageInContext(context);
+    if (page == nullptr) {
+        error = "Failed to create new page in the context"_s;
+        return nullptr;
+    }
+
+    if (context == nullptr && sessionID != page->sessionID()) {
+        ASSERT_NOT_REACHED();
+        error = " Failed to create new page in default context"_s;
+        return nullptr;
+    }
+
+    return page;
+}
+
+void InspectorPlaywrightAgentClientGlib::closeBrowser()
+{
+    m_idToContext.clear();
+    webkitBrowserInspectorQuitApplication();
+    if (webkitWebContextExistingCount() > 1)
+        fprintf(stderr, "LEAK: %d contexts are still alive when closing browser\n", webkitWebContextExistingCount());
+}
+
+std::unique_ptr<BrowserContext> InspectorPlaywrightAgentClientGlib::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList)
+{
+#if !ENABLE(2022_GLIB_API)
+    GRefPtr<WebKitWebsiteDataManager> data_manager = adoptGRef(webkit_website_data_manager_new_ephemeral());
+#endif
+    GRefPtr<WebKitWebContext> context = adoptGRef(WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT,
+#if !ENABLE(2022_GLIB_API)
+    "website-data-manager", data_manager.get(),
+#endif
+    // WPE has PSON enabled by default and doesn't have such parameter.
+#if PLATFORM(GTK)
+#if !ENABLE(2022_GLIB_API)
+        "process-swap-on-cross-site-navigation-enabled", true,
+#endif
+#endif
+        nullptr)));
+    if (!context) {
+        error = "Failed to create GLib ephemeral context"_s;
+        return nullptr;
+    }
+
+#if ENABLE(2022_GLIB_API)
+    GRefPtr<WebKitNetworkSession> networkSession = adoptGRef(webkit_network_session_new_ephemeral());
+    webkit_web_context_set_network_session_for_automation(context.get(), networkSession.get());
+    GRefPtr<WebKitWebsiteDataManager> data_manager = webkit_network_session_get_website_data_manager(networkSession.get());
+#endif
+
+    auto browserContext = std::make_unique<BrowserContext>();
+    browserContext->processPool = &webkitWebContextGetProcessPool(context.get());
+    browserContext->dataStore = &webkitWebsiteDataManagerGetDataStore(data_manager.get());
+    PAL::SessionID sessionID = browserContext.get()->dataStore->sessionID();
+    m_idToContext.set(sessionID, WTFMove(context));
+
+    if (!proxyServer.isEmpty()) {
+        WebCore::SoupNetworkProxySettings contextProxySettings = parseProxySettings(proxyServer, proxyBypassList);
+        browserContext->dataStore->setNetworkProxySettings(WTFMove(contextProxySettings));
+    } else {
+        browserContext->dataStore->setNetworkProxySettings(WebCore::SoupNetworkProxySettings(m_proxySettings));
+    }
+    return browserContext;
+}
+
+void InspectorPlaywrightAgentClientGlib::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID)
+{
+    m_idToContext.remove(sessionID);
+}
+
+void InspectorPlaywrightAgentClientGlib::takePageScreenshot(WebPageProxy& page, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler<void(const String&, const String&)>&& completionHandler)
+{
+    page.callAfterNextPresentationUpdate([protectedPage = Ref{ page }, clip = WTFMove(clip), nominalResolution, completionHandler = WTFMove(completionHandler)]() mutable {
+#if PLATFORM(GTK)
+        RefPtr<ViewSnapshot> viewSnapshot = protectedPage->pageClient()->takeViewSnapshot(WTFMove(clip), nominalResolution);
+        if (viewSnapshot) {
+            std::optional<String> data = WebAutomationSession::platformGetBase64EncodedPNGData(*viewSnapshot);
+            if (data) {
+                completionHandler(emptyString(), makeString("data:image/png;base64,"_s, *data));
+                return;
+            }
+        }
+#elif PLATFORM(WPE)
+#if USE(SKIA)
+        sk_sp<SkImage> protectPtr = protectedPage->pageClient()->takeViewSnapshot(WTFMove(clip), nominalResolution);
+        SkImage* surface = protectPtr.get();
+#elif USE(CAIRO)
+        cairo_surface_t* surface = nullptr;
+        RefPtr<cairo_surface_t> protectPtr = protectedPage->pageClient()->takeViewSnapshot(WTFMove(clip), nominalResolution);
+        surface = protectPtr.get();
+#endif
+        if (surface) {
+            Vector<uint8_t> encodeData = WebCore::encodeData(surface, "image/png"_s, std::nullopt);
+            completionHandler(emptyString(), makeString("data:image/png;base64,"_s, base64Encoded(encodeData)));
+            return;
+        }
+#endif
+        completionHandler("Failed to take screenshot"_s, emptyString());
+    });
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h
new file mode 100644
index 0000000000000000000000000000000000000000..441442d899e4088f5c24ae9f70c3e4ffa1e6d340
--- /dev/null
+++ b/Source/WebKit/UIProcess/glib/InspectorPlaywrightAgentClientGLib.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorPlaywrightAgentClient.h"
+#include <WebCore/SoupNetworkProxySettings.h>
+#include "WebKitWebContext.h"
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/text/StringHash.h>
+
+namespace WebKit {
+
+class InspectorPlaywrightAgentClientGlib : public InspectorPlaywrightAgentClient {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    InspectorPlaywrightAgentClientGlib(const WTF::String& proxyURI, const char* const* ignoreHosts);
+    ~InspectorPlaywrightAgentClientGlib() override = default;
+
+    RefPtr<WebPageProxy> createPage(WTF::String& error, const BrowserContext&) override;
+    void closeBrowser() override;
+    std::unique_ptr<BrowserContext> createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override;
+    void deleteBrowserContext(WTF::String& error, PAL::SessionID) override;
+    void takePageScreenshot(WebPageProxy&, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler<void(const String&, const String&)>&& completionHandler) override;
+
+private:
+    WebKitWebContext* findContext(WTF::String& error, PAL::SessionID);
+
+    UncheckedKeyHashMap<PAL::SessionID, GRefPtr<WebKitWebContext>> m_idToContext;
+    WebCore::SoupNetworkProxySettings m_proxySettings;
+};
+
+} // namespace API
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h
index b2e2a636725674a1619f92d67c7846358374b9e3..7bc4914766b3b03e586c6662c6da33ceac466c0b 100644
--- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h
+++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStore.h
@@ -32,6 +32,7 @@
 #include <wtf/WeakPtr.h>
 
 typedef struct _cairo cairo_t;
+typedef struct _cairo_surface cairo_surface_t;
 
 #if USE(GTK4)
 typedef struct _GdkSnapshot GdkSnapshot;
@@ -61,6 +62,8 @@ public:
 #else
     virtual bool paint(cairo_t*, const WebCore::IntRect&) = 0;
 #endif
+    virtual cairo_surface_t* surface() { return nullptr; }
+
     virtual void realize() { };
     virtual void unrealize() { };
     virtual int renderHostFileDescriptor() { return -1; }
diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp
index fc6a465e3518c6d9be65b9cb4677b9734b023741..431337fb8576c41e7a59440b2f867b0bebce9776 100644
--- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp
+++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.cpp
@@ -729,4 +729,30 @@ RendererBufferFormat AcceleratedBackingStoreDMABuf::bufferFormat() const
     return buffer ? buffer->format() : RendererBufferFormat { };
 }
 
+// Playwright begin
+cairo_surface_t* AcceleratedBackingStoreDMABuf::surface()
+{
+    RefPtr<Buffer> buffer = m_committedBuffer.get();
+    if (!buffer)
+        return nullptr;
+
+    RefPtr<cairo_surface_t> surface = buffer->surface();
+    if (!surface)
+        return nullptr;
+
+    // The original surface is upside down, so we flip it to match orientation in other accelerated backing stores.
+    m_flippedSurface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_ARGB32, cairo_image_surface_get_width(surface.get()), cairo_image_surface_get_height(surface.get())));
+    {
+        RefPtr<cairo_t> cr = adoptRef(cairo_create(m_flippedSurface.get()));
+        cairo_matrix_t transform;
+        cairo_matrix_init(&transform, 1, 0, 0, -1, 0, cairo_image_surface_get_height(surface.get()) / buffer->deviceScaleFactor());
+        cairo_transform(cr.get(), &transform);
+        cairo_set_source_surface(cr.get(), surface.get(), 0, 0);
+        cairo_paint(cr.get());
+    }
+    cairo_surface_flush(m_flippedSurface.get());
+    return m_flippedSurface.get();
+}
+// Playwright end
+
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h
index a208bbefafd88a3d95f6c2be35f7f700c86bda90..c603c7eb3501989e79ebc31b1c4eb6e1d2523ffe 100644
--- a/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h
+++ b/Source/WebKit/UIProcess/gtk/AcceleratedBackingStoreDMABuf.h
@@ -98,6 +98,7 @@ private:
 #else
     bool paint(cairo_t*, const WebCore::IntRect&) override;
 #endif
+    cairo_surface_t* surface() override;
     void unrealize() override;
     void update(const LayerTreeContext&) override;
     RendererBufferFormat bufferFormat() const override;
@@ -247,6 +248,9 @@ private:
     RefPtr<Buffer> m_committedBuffer;
     WebCore::Region m_pendingDamageRegion;
     HashMap<uint64_t, RefPtr<Buffer>> m_buffers;
+// Playwright begin
+    RefPtr<cairo_surface_t> m_flippedSurface;
+// Playwright end
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..bf78de1915940c2d3292514cf0fe4e682b636f70
--- /dev/null
+++ b/Source/WebKit/UIProcess/gtk/InspectorTargetProxyGtk.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorTargetProxy.h"
+
+#include "WebPageProxy.h"
+#include <WebCore/GtkUtilities.h>
+#include <gtk/gtk.h>
+
+namespace WebKit {
+
+void InspectorTargetProxy::platformActivate(String& error) const
+{
+#if USE(GTK4)
+    GtkWidget* parent = GTK_WIDGET(gtk_widget_get_root(m_page->viewWidget()));
+#else
+    GtkWidget* parent = gtk_widget_get_toplevel(m_page->viewWidget());
+#endif
+    if (WebCore::widgetIsOnscreenToplevelWindow(parent))
+        gtk_window_present(GTK_WINDOW(parent));
+    else
+        error = "The view is not on screen"_s;
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp
index aa702b018d881739fb464246e7c7d7236adfe97b..f711e1608e6d8b988d2d0bc99893d5b0137a07ae 100644
--- a/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp
+++ b/Source/WebKit/UIProcess/gtk/SystemSettingsManagerProxyGtk.cpp
@@ -117,6 +117,8 @@ int SystemSettingsManagerProxy::xftDPI() const
 
 bool SystemSettingsManagerProxy::followFontSystemSettings() const
 {
+    // Align with WPE's behavior, which always returns false.
+    return false;
 #if USE(GTK4)
 #if GTK_CHECK_VERSION(4, 16, 0)
     GtkFontRendering fontRendering;
diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7d9672b0f831b5b7f6acf14ede26e1e8e9a65389
--- /dev/null
+++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorEmulationAgentGtk.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DrawingAreaProxyCoordinatedGraphics.h"
+#include "WebPageInspectorEmulationAgent.h"
+#include "WebPageProxy.h"
+#include <WebCore/IntSize.h>
+#include <gtk/gtk.h>
+
+namespace WebKit {
+
+#if USE(GTK4)
+bool windowHasManyTabs(GtkWidget* widget) {
+    for (GtkWidget* parent = gtk_widget_get_parent(widget); parent; parent = gtk_widget_get_parent(parent)) {
+        if (GTK_IS_NOTEBOOK(parent)) {
+            int pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(parent));
+            return pages > 1;
+        }
+    }
+    return false;
+}
+#endif
+
+void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function<void (const String& error)>&& callback)
+{
+    WebCore::IntSize viewSize(width, height);
+    GtkWidget* viewWidget = m_page.viewWidget();
+    GtkWidget* window = gtk_widget_get_toplevel(viewWidget);
+    if (!window) {
+        callback("Cannot find parent window"_s);
+        return;
+    }
+    if (!GTK_IS_WINDOW(window)) {
+        callback("Toplevel is not a window"_s);
+        return;
+    }
+    GtkAllocation viewAllocation;
+    gtk_widget_get_allocation(viewWidget, &viewAllocation);
+#if USE(GTK4)
+    // In GTK4 newly added tabs will have allocation size of 0x0, before the tab is shown.
+    // This is a Ctrl+click scenario. We invoke callback righ await to not stall.
+    if (!viewAllocation.width && !viewAllocation.height && windowHasManyTabs(viewWidget)) {
+        callback(String());
+        return;
+    }
+#endif
+    if (viewAllocation.width == width && viewAllocation.height == height) {
+        callback(String());
+        return;
+    }
+
+    GtkAllocation windowAllocation;
+    gtk_widget_get_allocation(window, &windowAllocation);
+
+    width += windowAllocation.width - viewAllocation.width;
+    height += windowAllocation.height - viewAllocation.height;
+
+    if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(m_page.drawingArea())) {
+        bool didNotHaveInitialAllocation = !windowAllocation.width && !windowAllocation.height;
+        // The callback can only be called if the page is still alive, so we can safely capture `this`.
+        drawingArea->waitForSizeUpdate([this, callback = WTFMove(callback), didNotHaveInitialAllocation, viewSize](const DrawingAreaProxyCoordinatedGraphics& drawingArea) mutable {
+#if USE(GTK4)
+            if (viewSize == drawingArea.size()) {
+                callback(String());
+                return;
+            }
+            if (didNotHaveInitialAllocation) {
+                // In gtk4 resize request may be lost (overridden by default one) if the window is not yet
+                // allocated when we are changing the size, so we try again.
+                platformSetSize(viewSize.width(), viewSize.height(), WTFMove(callback));
+                return;
+            }
+            callback("Failed to resize window"_s);
+#else
+            UNUSED_PARAM(this);
+            UNUSED_PARAM(didNotHaveInitialAllocation);
+            UNUSED_PARAM(drawingArea);
+            callback(String());
+#endif
+        });
+    } else {
+        callback("No backing store for window"_s);
+    }
+#if USE(GTK4)
+    // Depending on whether default size has been applied or not, we need to
+    // do one of the calls, so we just do both.
+    gtk_window_set_default_size(GTK_WINDOW(window), width, height);
+    gtk_widget_set_size_request(window, width, height);
+#else
+    gtk_window_resize(GTK_WINDOW(window), width, height);
+#endif
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..36ab6e9aec9f8d79fb13a8a49beadaafb3da58f5
--- /dev/null
+++ b/Source/WebKit/UIProcess/gtk/WebPageInspectorInputAgentGtk.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebPageInspectorInputAgent.h"
+
+#include "KeyBindingTranslator.h"
+#include "NativeWebKeyboardEvent.h"
+#include "WebPageProxy.h"
+#include <WebCore/PlatformKeyboardEvent.h>
+
+namespace WebKit {
+
+static unsigned modifiersToEventState(OptionSet<WebEventModifier> modifiers)
+{
+    unsigned state = 0;
+    if (modifiers.contains(WebEventModifier::ControlKey))
+        state |= GDK_CONTROL_MASK;
+    if (modifiers.contains(WebEventModifier::ShiftKey))
+        state |= GDK_SHIFT_MASK;
+    if (modifiers.contains(WebEventModifier::AltKey))
+        state |= GDK_META_MASK;
+    if (modifiers.contains(WebEventModifier::CapsLockKey))
+        state |= GDK_LOCK_MASK;
+    return state;
+}
+
+void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, Vector<String>& macCommands, WallTime timestamp)
+{
+    Vector<String> commands;
+    const guint keyVal = WebCore::PlatformKeyboardEvent::gdkKeyCodeForWindowsKeyCode(windowsVirtualKeyCode);
+    if (keyVal) {
+        unsigned state = modifiersToEventState(modifiers);
+        commands = KeyBindingTranslator().commandsForKeyval(keyVal, state);
+    }
+    NativeWebKeyboardEvent event(
+        type,
+        text,
+        unmodifiedText,
+        key,
+        code,
+        keyIdentifier,
+        windowsVirtualKeyCode,
+        nativeVirtualKeyCode,
+        isAutoRepeat,
+        isKeypad,
+        isSystemKey,
+        modifiers,
+        timestamp,
+        WTFMove(commands));
+    m_page.handleKeyboardEvent(event);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp
index 2a17b59c9be6ecc76b0ec0a16d9f4866dffa0bf4..0d5c58a88b0e5197254d0eb5bd6eee045d99d299 100644
--- a/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp
+++ b/Source/WebKit/UIProcess/gtk/WebPasteboardProxyGtk.cpp
@@ -78,8 +78,10 @@ void WebPasteboardProxy::setPrimarySelectionOwner(WebFrameProxy* frame)
     if (m_primarySelectionOwner == frame)
         return;
 
-    if (m_primarySelectionOwner)
-        m_primarySelectionOwner->collapseSelection();
+// Playwright begin: do not change selection in another page!
+    // if (m_primarySelectionOwner)
+    //     m_primarySelectionOwner->collapseSelection();
+// Playwright end
 
     m_primarySelectionOwner = frame;
 }
diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h
new file mode 100644
index 0000000000000000000000000000000000000000..2aabc02a4b5432f68a6e85fd9689775608f05a67
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "InspectorPlaywrightAgentClient.h"
+#include <wtf/Forward.h>
+
+OBJC_PROTOCOL(_WKBrowserInspectorDelegate);
+
+namespace WebKit {
+
+class InspectorPlaywrightAgentClientMac : public InspectorPlaywrightAgentClient {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    InspectorPlaywrightAgentClientMac(_WKBrowserInspectorDelegate* delegate, bool headless);
+    ~InspectorPlaywrightAgentClientMac() override = default;
+
+    RefPtr<WebPageProxy> createPage(WTF::String& error, const BrowserContext&) override;
+    void closeBrowser() override;
+    std::unique_ptr<BrowserContext> createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList) override;
+    void deleteBrowserContext(WTF::String& error, PAL::SessionID) override;
+    void takePageScreenshot(WebPageProxy&, WebCore::IntRect&& clip, bool nominalResolution, CompletionHandler<void(const String&, const String&)>&& completionHandler) override;
+
+private:
+    _WKBrowserInspectorDelegate* delegate_;
+    bool headless_;
+};
+
+
+} // namespace API
diff --git a/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..a5c8b963636b24d4bb8ad090e4a19aedecbf56c3
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/InspectorPlaywrightAgentClientMac.mm
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "InspectorPlaywrightAgentClientMac.h"
+
+#import "PageClient.h"
+#import "WebPageProxy.h"
+#import "WebProcessPool.h"
+#import "WebsiteDataStore.h"
+#import "_WKBrowserInspector.h"
+#import "WKProcessPoolInternal.h"
+#import "WKWebsiteDataStoreInternal.h"
+#import "WKWebView.h"
+#import "WKWebViewInternal.h"
+#import <WebCore/ImageBufferUtilitiesCG.h>
+#import <wtf/RefPtr.h>
+#import <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+InspectorPlaywrightAgentClientMac::InspectorPlaywrightAgentClientMac(_WKBrowserInspectorDelegate* delegate, bool headless)
+  : delegate_(delegate),
+    headless_(headless)
+{
+}
+
+RefPtr<WebPageProxy> 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<BrowserContext> 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>();
+    browserContext->processPool = &static_cast<WebProcessPool&>([[wkBrowserContext processPool] _apiObject]);
+    browserContext->dataStore = &static_cast<WebsiteDataStore&>([[wkBrowserContext dataStore] _apiObject]);
+    return browserContext;
+}
+
+void InspectorPlaywrightAgentClientMac::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID)
+{
+    [delegate_ deleteBrowserContext:sessionID.toUInt64()];
+}
+
+void InspectorPlaywrightAgentClientMac::takePageScreenshot(WebPageProxy& page, WebCore::IntRect&& clipRect, bool, CompletionHandler<void(const String&, const String&)>&& completionHandler)
+{
+    int toolbarHeight = headless_ ? 0 : 59;
+    page.callAfterNextPresentationUpdate([protectedPage = Ref { page }, toolbarHeight, clipRect = WTFMove(clipRect), completionHandler = WTFMove(completionHandler)]() mutable {
+        RetainPtr<CGImageRef> imageRef = protectedPage->pageClient()->takeSnapshotForAutomation();
+        if (!imageRef) {
+            completionHandler("Could not take view snapshot"_s, emptyString());
+            return;
+        }
+
+        clipRect.move(0, toolbarHeight);
+        RetainPtr<CGImageRef> transformedImageRef = adoptCF(CGImageCreateWithImageInRect(imageRef.get(), clipRect));
+        completionHandler(emptyString(), WebCore::dataURL(transformedImageRef.get(), "image/png"_s, std::nullopt));
+    });
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm b/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..8adbd51bfecad2a273117588bf50f8f741850d14
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/InspectorTargetProxyMac.mm
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "InspectorTargetProxy.h"
+#import "WebPageProxy.h"
+
+#if PLATFORM(MAC)
+
+namespace WebKit {
+
+void InspectorTargetProxy::platformActivate(String& error) const
+{
+    NSWindow* window = m_page->platformWindow();
+    [window makeKeyAndOrderFront:nil];
+}
+
+} // namespace WebKit
+
+#endif
diff --git a/Source/WebKit/UIProcess/mac/PageClientImplMac.h b/Source/WebKit/UIProcess/mac/PageClientImplMac.h
index 6d9f836ed08eb488e40831e8c93cfe7201ebdd9a..02f75742b4d473b7854e3792c6665c8c93d5687d 100644
--- a/Source/WebKit/UIProcess/mac/PageClientImplMac.h
+++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.h
@@ -60,6 +60,8 @@ class PageClientImpl final : public PageClientImplCocoa
     WTF_OVERRIDE_DELETE_FOR_CHECKED_PTR(PageClientImpl);
 #endif
 public:
+    static void setHeadless(bool headless);
+
     PageClientImpl(NSView *, WKWebView *);
     virtual ~PageClientImpl();
 
@@ -175,6 +177,9 @@ private:
     void updateAcceleratedCompositingMode(const LayerTreeContext&) override;
     void didFirstLayerFlush(const LayerTreeContext&) override;
 
+// Paywright begin
+    RetainPtr<CGImageRef> takeSnapshotForAutomation() override;
+// Paywright end
     RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&) override;
     RefPtr<ViewSnapshot> takeViewSnapshot(std::optional<WebCore::IntRect>&&, ForceSoftwareCapturingViewportSnapshot) override;
     void wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent&) override;
@@ -230,6 +235,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 5f6008cd5d0bd76c7d3731a36f9d3605710c7c19..eac8caf9b5cd8ff2cdd41dd84a07413bab7badc3 100644
--- a/Source/WebKit/UIProcess/mac/PageClientImplMac.mm
+++ b/Source/WebKit/UIProcess/mac/PageClientImplMac.mm
@@ -110,6 +110,13 @@ namespace WebKit {
 
 using namespace WebCore;
 
+static bool _headless = false;
+
+// static
+void PageClientImpl::setHeadless(bool headless) {
+    _headless = headless;
+}
+
 PageClientImpl::PageClientImpl(NSView *view, WKWebView *webView)
     : PageClientImplCocoa(webView)
     , m_view(view)
@@ -163,6 +170,9 @@ NSWindow *PageClientImpl::activeWindow() const
 
 bool PageClientImpl::isViewWindowActive()
 {
+    if (_headless)
+        return true;
+
     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanCommunicateWithWindowServer));
     NSWindow *activeViewWindow = activeWindow();
     return activeViewWindow.isKeyWindow || (activeViewWindow && [NSApp keyWindow] == activeViewWindow);
@@ -170,6 +180,9 @@ bool PageClientImpl::isViewWindowActive()
 
 bool PageClientImpl::isViewFocused()
 {
+    if (_headless)
+        return true;
+
     // FIXME: This is called from the WebPageProxy constructor before we have a WebViewImpl.
     // Once WebViewImpl and PageClient merge, this won't be a problem.
     if (!m_impl)
@@ -193,6 +206,9 @@ void PageClientImpl::makeFirstResponder()
     
 bool PageClientImpl::isViewVisible()
 {
+    if (_headless)
+        return true;
+
     NSView *activeView = this->activeView();
     NSWindow *activeViewWindow = activeWindow();
 
@@ -276,7 +292,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)
@@ -478,6 +495,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);
 }
 
@@ -497,6 +516,8 @@ void PageClientImpl::computeHasVisualSearchResults(const URL& imageURL, Shareabl
 
 RefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy& page)
 {
+    if (_headless)
+        return nullptr;
     return WebPopupMenuProxyMac::create(m_view, page.popupMenuClient());
 }
 
@@ -638,6 +659,12 @@ CALayer *PageClientImpl::footerBannerLayer() const
     return m_impl->footerBannerLayer();
 }
 
+// Paywright begin
+RetainPtr<CGImageRef> PageClientImpl::takeSnapshotForAutomation() {
+    return m_impl->takeSnapshotForAutomation();
+}
+// Paywright begin
+
 RefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot(std::optional<WebCore::IntRect>&&)
 {
     return m_impl->takeViewSnapshot();
@@ -833,6 +860,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);
@@ -1016,6 +1050,9 @@ void PageClientImpl::requestScrollToRect(const WebCore::FloatRect& targetRect, c
 
 bool PageClientImpl::windowIsFrontWindowUnderMouse(const NativeWebMouseEvent& event)
 {
+    // Simulated event.
+    if (!event.nativeEvent())
+        return false;
     return m_impl->windowIsFrontWindowUnderMouse(event.nativeEvent());
 }
 
diff --git a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in
index 5ddabc8529a1d7c8121d834289aa0e70a5dcd7d7..0bec72101447def53facd42881358e4cb34b656e 100644
--- a/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in
+++ b/Source/WebKit/UIProcess/mac/SecItemShimProxy.messages.in
@@ -20,11 +20,11 @@
 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#if ENABLE(SEC_ITEM_SHIM)
 messages -> SecItemShimProxy {
 
-#if ENABLE(SEC_ITEM_SHIM)
     SecItemRequestSync(WebKit::SecItemRequestData request) -> (std::optional<WebKit::SecItemResponseData> response) Synchronous
     SecItemRequest(WebKit::SecItemRequestData request) -> (std::optional<WebKit::SecItemResponseData> response)
-#endif
 
 }
+#endif
diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h
index e34faa8ae2933154efdbf0492a2f17af7a46f83b..54b509837bb767ac3ab28d1d7059462ca7a1170b 100644
--- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h
+++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.h
@@ -78,6 +78,7 @@ private:
     void show() override;
     void showContextMenuWithItems(Vector<Ref<WebContextMenuItem>>&&) override;
     void useContextMenuItems(Vector<Ref<WebContextMenuItem>>&&) override;
+    void hide() override;
 
     bool showAfterPostProcessingContextData();
 
diff --git a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm
index 590e689455e912c35642b9fbafa6cd9a34041eac..27ff44679509d9e82fb4ad556ace0cf7368206e4 100644
--- a/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm
+++ b/Source/WebKit/UIProcess/mac/WebContextMenuProxyMac.mm
@@ -460,6 +460,12 @@ void WebContextMenuProxyMac::getShareMenuItem(CompletionHandler<void(NSMenuItem
 }
 #endif
 
+void WebContextMenuProxyMac::hide()
+{
+    if (m_menu)
+        [m_menu cancelTracking];
+}
+
 void WebContextMenuProxyMac::show()
 {
 #if ENABLE(SERVICE_CONTROLS)
diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..6113f4cd60a5d72b8ead61176cb43200803478ed
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/WebPageInspectorEmulationAgentMac.mm
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "WebPageInspectorEmulationAgent.h"
+
+#import "WebPageProxy.h"
+
+namespace WebKit {
+
+void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function<void (const String& error)>&& callback)
+{
+    NSWindow* window = m_page.platformWindow();
+    NSRect windowRect = [window frame];
+    NSRect viewRect = window.contentLayoutRect;
+    windowRect.size.width += width - viewRect.size.width;
+    windowRect.size.height += height - viewRect.size.height;
+    [window setFrame:windowRect display:YES animate:NO];
+    callback(String());
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm
new file mode 100644
index 0000000000000000000000000000000000000000..dd52991f936aa1c046b404801ee97237d0a55748
--- /dev/null
+++ b/Source/WebKit/UIProcess/mac/WebPageInspectorInputAgentMac.mm
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "NativeWebMouseEvent.h"
+#import "NetworkProcessMessages.h"
+#import "NetworkProcessProxy.h"
+#import "WebPageInspectorInputAgent.h"
+#import "WebPageProxy.h"
+#import "WebPageProxyMessages.h"
+#import "WebsiteDataStore.h"
+#import <WebCore/IntPoint.h>
+#import <WebCore/IntSize.h>
+#import "NativeWebKeyboardEvent.h"
+
+namespace WebKit {
+
+using namespace WebCore;
+
+void WebPageInspectorInputAgent::platformDispatchMouseEvent(const String& type, int x, int y, std::optional<int>&& optionalModifiers, const String& button, std::optional<int>&& optionalClickCount, unsigned short buttons) {
+    IntPoint locationInWindow(x, y);
+
+    NSEventModifierFlags modifiers = 0;
+    if (optionalModifiers) {
+        int inputModifiers = *optionalModifiers;
+        if (inputModifiers & 1)
+            modifiers |= NSEventModifierFlagShift;
+        if (inputModifiers & 2)
+            modifiers |= NSEventModifierFlagControl;
+        if (inputModifiers & 4)
+            modifiers |= NSEventModifierFlagOption;
+        if (inputModifiers & 8)
+            modifiers |= NSEventModifierFlagCommand;
+    }
+    int clickCount = optionalClickCount ? *optionalClickCount : 0;
+
+    NSTimeInterval timestamp = [NSDate timeIntervalSinceReferenceDate];
+    NSWindow *window = m_page.platformWindow();
+    NSInteger windowNumber = window.windowNumber;
+
+    NSEventType downEventType;
+    NSEventType dragEventType;
+    NSEventType upEventType;
+
+    if (!button || button == "none"_s) {
+        downEventType = NSEventTypeMouseMoved;
+        dragEventType = NSEventTypeMouseMoved;
+        upEventType = NSEventTypeMouseMoved;
+    } else if (button == "left"_s) {
+        downEventType = NSEventTypeLeftMouseDown;
+        dragEventType = NSEventTypeLeftMouseDragged;
+        upEventType = NSEventTypeLeftMouseUp;
+    } else if (button == "middle"_s) {
+        downEventType = NSEventTypeOtherMouseDown;
+        dragEventType = NSEventTypeLeftMouseDragged;
+        upEventType = NSEventTypeOtherMouseUp;
+    } else if (button == "right"_s) {
+        downEventType = NSEventTypeRightMouseDown;
+        dragEventType = NSEventTypeRightMouseDragged;
+        upEventType = NSEventTypeRightMouseUp;
+    } else {
+        return;
+    }
+
+    NSInteger eventNumber = 0;
+
+    NSEvent* event;
+    if (type == "move"_s) {
+        event = [NSEvent mouseEventWithType:dragEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:0.0f];
+    } else if (type == "down"_s) {
+        event = [NSEvent mouseEventWithType:downEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:WebCore::ForceAtClick];
+    } else if (type == "up"_s) {
+        event = [NSEvent mouseEventWithType:upEventType location:locationInWindow modifierFlags:modifiers timestamp:timestamp windowNumber:windowNumber context:nil eventNumber:eventNumber clickCount:clickCount pressure:0.0f];
+    } else {
+        return;
+    }
+
+    NativeWebMouseEvent nativeEvent(event, nil, [window contentView]);
+    nativeEvent.playwrightSetButtons(buttons);
+    m_page.handleMouseEvent(nativeEvent);
+}
+
+void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, Vector<String>& commands, WallTime timestamp)
+{
+    Vector<WebCore::KeypressCommand> macCommands;
+    for (const String& command : commands) {
+        m_page.registerKeypressCommandName(command);
+        macCommands.append(WebCore::KeypressCommand(command));
+    }
+    if (text.length() > 0 && macCommands.size() == 0)
+        macCommands.append(WebCore::KeypressCommand("insertText:"_s, text));
+    if (!macCommands.isEmpty())
+        if (auto replyID = m_page.grantAccessToCurrentPasteboardData(NSPasteboardNameGeneral, [] () { }))
+            m_page.websiteDataStore().protectedNetworkProcess()->connection().waitForAsyncReplyAndDispatchImmediately<Messages::NetworkProcess::AllowFilesAccessFromWebProcess>(*replyID, 100_ms);
+    NativeWebKeyboardEvent event(
+        type,
+        text,
+        unmodifiedText,
+        key,
+        code,
+        keyIdentifier,
+        windowsVirtualKeyCode,
+        nativeVirtualKeyCode,
+        isAutoRepeat,
+        isKeypad,
+        isSystemKey,
+        modifiers,
+        timestamp,
+        WTFMove(macCommands));
+    m_page.handleKeyboardEvent(event);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.h b/Source/WebKit/UIProcess/mac/WebViewImpl.h
index 547682903b486e6f4fe814239d445c6ab26243b0..115255726211d7ff82475caf70516677f243afd3 100644
--- a/Source/WebKit/UIProcess/mac/WebViewImpl.h
+++ b/Source/WebKit/UIProcess/mac/WebViewImpl.h
@@ -544,6 +544,9 @@ public:
     void provideDataForPasteboard(NSPasteboard *, NSString *type);
     NSArray *namesOfPromisedFilesDroppedAtDestination(NSURL *dropDestination);
 
+// Paywright begin
+    RetainPtr<CGImageRef> takeSnapshotForAutomation();
+// Paywright end
     RefPtr<ViewSnapshot> takeViewSnapshot();
     RefPtr<ViewSnapshot> takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot);
     void saveBackForwardSnapshotForCurrentItem();
diff --git a/Source/WebKit/UIProcess/mac/WebViewImpl.mm b/Source/WebKit/UIProcess/mac/WebViewImpl.mm
index 926d93ba3cab0bec3396dc044921e2337a331836..3857bfd5d010ce1ee443f10f96730f084f38984e 100644
--- a/Source/WebKit/UIProcess/mac/WebViewImpl.mm
+++ b/Source/WebKit/UIProcess/mac/WebViewImpl.mm
@@ -2390,6 +2390,11 @@ WebCore::DestinationColorSpace WebViewImpl::colorSpace()
         if (!m_colorSpace)
             m_colorSpace = [NSColorSpace sRGBColorSpace];
     }
+    // Playwright begin
+    // window.colorSpace is sometimes null on popup windows in headless mode
+    if (!m_colorSpace)
+        return WebCore::DestinationColorSpace::SRGB();
+    // Playwright end
 
     ASSERT(m_colorSpace);
     return WebCore::DestinationColorSpace { [m_colorSpace CGColorSpace] };
@@ -4528,6 +4533,17 @@ static RetainPtr<CGImageRef> takeWindowSnapshot(CGSWindowID windowID, bool captu
     return WebCore::cgWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions);
 }
 
+// Paywright begin
+RetainPtr<CGImageRef> WebViewImpl::takeSnapshotForAutomation() {
+    NSWindow *window = [m_view window];
+
+    CGSWindowID windowID = (CGSWindowID)window.windowNumber;
+    if (!windowID || !window.isVisible)
+        return nullptr;
+    return takeWindowSnapshot(windowID, true, ForceSoftwareCapturingViewportSnapshot::Yes);
+}
+// Paywright end
+
 RefPtr<ViewSnapshot> WebViewImpl::takeViewSnapshot()
 {
     return takeViewSnapshot(ForceSoftwareCapturingViewportSnapshot::No);
diff --git a/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4f54a9445e5a7ecdb750c5c521da4f397776e633
--- /dev/null
+++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorPlaywrightAgentClientWin.h"
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "APIPageConfiguration.h"
+#include "APIProcessPoolConfiguration.h"
+#include "InspectorPlaywrightAgent.h"
+#include "WebPageProxy.h"
+#include "WebsiteDataStore.h"
+#include "WebPreferences.h"
+#include "WebProcessPool.h"
+#include "WebView.h"
+#include "WKAPICast.h"
+#include <WebCore/CurlProxySettings.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefPtr.h>
+#include <wtf/text/StringView.h>
+#include <wtf/text/WTFString.h>
+
+namespace WebKit {
+
+InspectorPlaywrightAgentClientWin::InspectorPlaywrightAgentClientWin(ConfigureDataStoreCallback configureDataStore, CreatePageCallback createPage, QuitCallback quit)
+    : m_configureDataStore(configureDataStore)
+    , m_createPage(createPage)
+    , m_quit(quit)
+{
+}
+
+RefPtr<WebPageProxy> 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<BrowserContext> InspectorPlaywrightAgentClientWin::createBrowserContext(WTF::String& error, const WTF::String& proxyServer, const WTF::String& proxyBypassList)
+{
+    auto config = API::ProcessPoolConfiguration::create();
+    auto browserContext = std::make_unique<BrowserContext>();
+    browserContext->processPool = WebKit::WebProcessPool::create(config);
+    browserContext->dataStore = WebKit::WebsiteDataStore::createNonPersistent();
+    m_configureDataStore(toAPI(browserContext->dataStore.get()));
+    if (!proxyServer.isEmpty()) {
+        URL proxyURL = URL(URL(), proxyServer);
+        WebCore::CurlProxySettings settings(WTFMove(proxyURL), String(proxyBypassList));
+        browserContext->dataStore->setNetworkProxySettings(WTFMove(settings));
+    }
+    return browserContext;
+}
+
+void InspectorPlaywrightAgentClientWin::deleteBrowserContext(WTF::String& error, PAL::SessionID sessionID)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(REMOTE_INSPECTOR)
diff --git a/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h
new file mode 100644
index 0000000000000000000000000000000000000000..df18883b2b7d22d73540cb084d3dd5291231097d
--- /dev/null
+++ b/Source/WebKit/UIProcess/win/InspectorPlaywrightAgentClientWin.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(REMOTE_INSPECTOR)
+
+#include "InspectorPlaywrightAgentClient.h"
+#include <WebKit/WKInspector.h>
+#include <wtf/Forward.h>
+#include <wtf/text/StringHash.h>
+
+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<WebPageProxy> createPage(WTF::String& error, const BrowserContext&) override;
+    void closeBrowser() override;
+    std::unique_ptr<BrowserContext> 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 3c95132b41b124e49f52e97ba2306614f46d53b9..115cfc4871aef732d5c57bae3b13818b67193cd5 100644
--- a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp
+++ b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.cpp
@@ -114,5 +114,11 @@ WebContextMenuProxyWin::~WebContextMenuProxyWin()
         ::DestroyMenu(m_menu);
 }
 
+void WebContextMenuProxyWin::hide()
+{
+    if (m_menu)
+        ::EndMenu();
+}
+
 } // namespace WebKit
 #endif // ENABLE(CONTEXT_MENUS)
diff --git a/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h b/Source/WebKit/UIProcess/win/WebContextMenuProxyWin.h
index 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<Ref<WebContextMenuItem>>&&) override;
+    void hide() override;
 
     HMENU m_menu;
 };
diff --git a/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..df55ee613ec085cb85ed12b45deff3a1b046861c
--- /dev/null
+++ b/Source/WebKit/UIProcess/win/WebPageInspectorEmulationAgentWin.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebPageInspectorEmulationAgent.h"
+#include "WebPageProxy.h"
+
+namespace WebKit {
+
+void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function<void (const String& error)>&& callback)
+{
+    HWND viewHwnd = reinterpret_cast<HWND>(m_page.viewWidget());
+    HWND windowHwnd = GetAncestor(viewHwnd, GA_ROOT);
+    RECT viewRect;
+    RECT windowRect;
+
+    if (!windowHwnd || !GetWindowRect(windowHwnd, &windowRect)) {
+        callback("Could not retrieve window size"_s);
+        return;
+    }
+    if (!GetWindowRect(viewHwnd, &viewRect)) {
+        callback("Could retrieve view size"_s);
+        return;
+    }
+
+    width += windowRect.right - windowRect.left - viewRect.right + viewRect.left;
+    height += windowRect.bottom - windowRect.top - viewRect.bottom + viewRect.top;
+
+    if (!SetWindowPos(windowHwnd, 0, 0, 0, width, height, SWP_NOCOPYBITS | SWP_NOSENDCHANGING | SWP_NOMOVE)) {
+        callback("Could not resize window"_s);
+        return;
+    }
+    callback(String());
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/win/WebPageInspectorInputAgentWin.cpp b/Source/WebKit/UIProcess/win/WebPageInspectorInputAgentWin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8b474c730139b44a13c9d5b2d13ee20403e3e7f3
--- /dev/null
+++ b/Source/WebKit/UIProcess/win/WebPageInspectorInputAgentWin.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+#include "WebPageInspectorInputAgent.h"
+
+#include "NativeWebKeyboardEvent.h"
+#include "WebPageProxy.h"
+#include <WebCore/PlatformKeyboardEvent.h>
+
+namespace WebKit {
+
+void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, Vector<String>& macCommands, WallTime timestamp)
+{
+    NativeWebKeyboardEvent event(
+        type,
+        text,
+        unmodifiedText,
+        key,
+        code,
+        keyIdentifier,
+        windowsVirtualKeyCode,
+        nativeVirtualKeyCode,
+        isAutoRepeat,
+        isKeypad,
+        isSystemKey,
+        modifiers,
+        timestamp);
+    m_page.handleKeyboardEvent(event);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/win/WebView.cpp b/Source/WebKit/UIProcess/win/WebView.cpp
index 8b521de62266d4a7fad3624b548401a4c8056f9f..c6da98e334fbd090a8c63b690afb25697ac344d7 100644
--- a/Source/WebKit/UIProcess/win/WebView.cpp
+++ b/Source/WebKit/UIProcess/win/WebView.cpp
@@ -556,9 +556,8 @@ LRESULT WebView::onSizeEvent(HWND hwnd, UINT, WPARAM, LPARAM lParam, bool& handl
 {
     if (m_page)
         m_page->setIntrinsicDeviceScaleFactor(deviceScaleFactorForWindow(hwnd));
-    // If there are no m_page, use intrinsic device scale factor.
-    float deviceScaleFactor = m_page ? m_page->deviceScaleFactor() : deviceScaleFactorForWindow(hwnd);
-    m_viewSize = expandedIntSize(FloatSize(LOWORD(lParam), HIWORD(lParam)) / deviceScaleFactor);
+
+    m_viewSize = expandedIntSize(FloatSize(LOWORD(lParam), HIWORD(lParam)));
 
     if (m_page && m_page->drawingArea()) {
         // FIXME specify correctly layerPosition.
diff --git a/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.cpp b/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..24da079059ed4a45131e18d7fbf56a29a54bd513
--- /dev/null
+++ b/Source/WebKit/UIProcess/wpe/InspectorTargetProxyWPE.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "InspectorTargetProxy.h"
+
+#include "WebPageProxy.h"
+#include <wpe/wpe.h>
+
+namespace WebKit {
+
+void InspectorTargetProxy::platformActivate(String& error) const
+{
+    struct wpe_view_backend* backend = m_page->viewBackend();
+    wpe_view_backend_add_activity_state(backend, wpe_view_activity_state_visible | wpe_view_activity_state_focused | wpe_view_activity_state_in_window);
+}
+
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..adec63a0a9d6d67bdbdadb4024005ff97ce79d10
--- /dev/null
+++ b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebColorPickerWPE.h"
+
+#if ENABLE(INPUT_TYPE_COLOR)
+
+#include "WebPageProxy.h"
+
+namespace WebKit {
+using namespace WebCore;
+
+Ref<WebColorPickerWPE> WebColorPickerWPE::create(WebPageProxy& page, const Color& initialColor, const IntRect& rect)
+{
+    return adoptRef(*new WebColorPickerWPE(page, initialColor, rect));
+}
+
+WebColorPickerWPE::WebColorPickerWPE(WebPageProxy& page, const Color& initialColor, const IntRect&)
+    : WebColorPicker(&page.colorPickerClient())
+{
+}
+
+WebColorPickerWPE::~WebColorPickerWPE()
+{
+    endPicker();
+}
+
+void WebColorPickerWPE::endPicker()
+{
+}
+
+void WebColorPickerWPE::showColorPicker(const Color& color)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(INPUT_TYPE_COLOR)
diff --git a/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h
new file mode 100644
index 0000000000000000000000000000000000000000..7edc93b3873dd42a7f877626551ec994395baae9
--- /dev/null
+++ b/Source/WebKit/UIProcess/wpe/WebColorPickerWPE.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WebColorPickerWPE_h
+#define WebColorPickerWPE_h
+
+#if ENABLE(INPUT_TYPE_COLOR)
+
+#include "WebColorPicker.h"
+
+typedef struct _GtkColorChooser GtkColorChooser;
+
+namespace WebCore {
+class Color;
+class IntRect;
+}
+
+namespace WebKit {
+
+class WebColorPickerWPE : public WebColorPicker {
+public:
+    static Ref<WebColorPickerWPE> create(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&);
+    virtual ~WebColorPickerWPE();
+
+    void endPicker() override;
+    void showColorPicker(const WebCore::Color&) override;
+
+protected:
+    WebColorPickerWPE(WebPageProxy&, const WebCore::Color&, const WebCore::IntRect&);
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(INPUT_TYPE_COLOR)
+#endif // WebColorPickerWPE_h
diff --git a/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.cpp b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a44463faf011fbab08f87bb7007a5e71c2a73758
--- /dev/null
+++ b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebDateTimePickerWPE.h"
+
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+
+using namespace WebCore;
+
+namespace WebKit {
+
+Ref<WebDateTimePickerWPE> WebDateTimePickerWPE::create(WebPageProxy& page)
+{
+    return adoptRef(*new WebDateTimePickerWPE(page));
+}
+
+WebDateTimePickerWPE::~WebDateTimePickerWPE()
+{
+}
+
+WebDateTimePickerWPE::WebDateTimePickerWPE(WebPageProxy& page)
+    : WebDateTimePicker(page)
+{
+}
+
+void WebDateTimePickerWPE::showDateTimePicker(WebCore::DateTimeChooserParameters&& params)
+{
+}
+
+} // namespace WebKit
+
+#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
diff --git a/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.h b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.h
new file mode 100644
index 0000000000000000000000000000000000000000..0c0e3fce33b06ee72c4c29d2a4abe9644f4cc895
--- /dev/null
+++ b/Source/WebKit/UIProcess/wpe/WebDateTimePickerWPE.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+
+#include "WebDateTimePicker.h"
+#include <WebCore/DateComponents.h>
+#include <WebCore/DateTimeChooserParameters.h>
+
+namespace WebKit {
+
+class WebDateTimePickerWPE final : public WebDateTimePicker {
+public:
+    static Ref<WebDateTimePickerWPE> create(WebPageProxy&);
+    ~WebDateTimePickerWPE();
+
+private:
+    WebDateTimePickerWPE(WebPageProxy&);
+
+    void showDateTimePicker(WebCore::DateTimeChooserParameters&&) final;
+};
+
+} // namespace WebKit
+
+#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
diff --git a/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPageInspectorEmulationAgentWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..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 <wpe/wpe.h>
+
+namespace WebKit {
+
+void WebPageInspectorEmulationAgent::platformSetSize(int width, int height, Function<void (const String& error)>&& 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..a7d88f8c745f95af21db71dcfce368ba4832a328
--- /dev/null
+++ b/Source/WebKit/UIProcess/wpe/WebPageInspectorInputAgentWPE.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 Microsoft Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebPageInspectorInputAgent.h"
+
+#include "NativeWebKeyboardEvent.h"
+#include "WebPageProxy.h"
+#include <WebCore/PlatformKeyboardEvent.h>
+#include <wpe/wpe.h>
+
+namespace WebKit {
+
+void WebPageInspectorInputAgent::platformDispatchKeyEvent(WebEventType type, const String& text, const String& unmodifiedText, const String& key, const String& code, const String& keyIdentifier, int windowsVirtualKeyCode, int nativeVirtualKeyCode, bool isAutoRepeat, bool isKeypad, bool isSystemKey, OptionSet<WebEventModifier> modifiers, Vector<String>& macCommands, WallTime timestamp)
+{
+    NativeWebKeyboardEvent event(
+        type,
+        text,
+        unmodifiedText,
+        key,
+        code,
+        keyIdentifier,
+        windowsVirtualKeyCode,
+        nativeVirtualKeyCode,
+        isAutoRepeat,
+        isKeypad,
+        isSystemKey,
+        modifiers,
+        timestamp);
+    m_page.handleKeyboardEvent(event);
+}
+ 
+} // namespace WebKit
diff --git a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp b/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp
index 9b688ad328317fea4fd96ce66e9714bad8f0f937..402a36a9c565e13ec298aa7f014f0d9208ebddb7 100644
--- a/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp
+++ b/Source/WebKit/UIProcess/wpe/WebPreferencesWPE.cpp
@@ -33,6 +33,10 @@ void WebPreferences::platformInitializeStore()
     setAcceleratedCompositingEnabled(true);
     setForceCompositingMode(true);
     setThreadedScrollingEnabled(true);
+
+    // Playwright override begin
+    setThreadedScrollingEnabled(false);
+    // Playwright override end
 }
 
 } // namespace WebKit
diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
index cf7270a1be953c9ceea9b62e3c0c1d4b60e3ad42..2500ac12bcfb21dd8f2a4371fd5e9ae76ffc6613 100644
--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj
+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj
@@ -1577,6 +1577,7 @@
 		5CABDC8722C40FED001EDE8E /* APIMessageListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CABDC8322C40FA7001EDE8E /* APIMessageListener.h */; };
 		5CADDE05215046BD0067D309 /* WKWebProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C74300E21500492004BFA17 /* WKWebProcess.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		5CAECB6627465AE400AB78D0 /* UnifiedSource115.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */; };
+		BF2C49ED7AD83CB7BC93CC92 /* UnifiedSource116.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D7178FBC4EDB168CDB0B04D /* UnifiedSource116.cpp */; };
 		5CAF7AA726F93AB00003F19E /* adattributiond.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CAF7AA526F93A950003F19E /* adattributiond.cpp */; };
 		5CAFDE452130846300B1F7E1 /* _WKInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE422130843500B1F7E1 /* _WKInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		5CAFDE472130846A00B1F7E1 /* _WKInspectorInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CAFDE442130843600B1F7E1 /* _WKInspectorInternal.h */; };
@@ -2388,6 +2389,18 @@
 		DF0C5F28252ECB8E00D921DB /* WKDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F24252ECB8D00D921DB /* WKDownload.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		DF0C5F2A252ECB8E00D921DB /* WKDownloadDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		DF0C5F2B252ED44000D921DB /* WKDownloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */; };
+		D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */; };
+		D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */; };
+		D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */; };
+		D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */; };
+		D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */; };
+		D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A94492372290B002C4D9E /* _WKBrowserInspector.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */ = {isa = PBXBuildFile; fileRef = D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */; };
+		D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = D76D6887238DBD80008D314B /* InspectorDialogAgent.h */; };
+		D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */; };
+		D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */; };
+		D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */; };
+		D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */; };
 		DF462E0F23F22F5500EFF35F /* WKHTTPCookieStorePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		DF462E1223F338BE00EFF35F /* WKContentWorldPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		DF7A231C291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DF7A231B291B088D00B98DF3 /* WKSnapshotConfigurationPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2481,6 +2494,8 @@
 		E5BEF6822130C48000F31111 /* WebDataListSuggestionsDropdownIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = E5BEF6802130C47F00F31111 /* WebDataListSuggestionsDropdownIOS.h */; };
 		E5CB07DC20E1678F0022C183 /* WKFormColorControl.h in Headers */ = {isa = PBXBuildFile; fileRef = E5CB07DA20E1678F0022C183 /* WKFormColorControl.h */; };
 		E5CBA76427A318E100DF7858 /* UnifiedSource120.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA75F27A3187800DF7858 /* UnifiedSource120.cpp */; };
+		E5CBA77427A318E100DF7858 /* UnifiedSource121.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76F27A3187800DF7858 /* UnifiedSource121.cpp */; };
+		E5CBA78427A318E100DF7858 /* UnifiedSource122.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA77F27A3187800DF7858 /* UnifiedSource122.cpp */; };
 		E5CBA76527A318E100DF7858 /* UnifiedSource118.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */; };
 		E5CBA76627A318E100DF7858 /* UnifiedSource116.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */; };
 		E5CBA76727A318E100DF7858 /* UnifiedSource119.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E5CBA76027A3187900DF7858 /* UnifiedSource119.cpp */; };
@@ -2504,6 +2519,9 @@
 		EBA8D3B727A5E33F00CB7900 /* PushServiceConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = EBA8D3B127A5E33F00CB7900 /* PushServiceConnection.mm */; };
 		EBDF51D12C8FBC4700EA1376 /* WebsitePushAndNotificationsEnabledPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = EBDF51CF2C8FBC4700EA1376 /* WebsitePushAndNotificationsEnabledPolicy.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 */; };
 		F409BA181E6E64BC009DA28E /* WKDragDestinationAction.h in Headers */ = {isa = PBXBuildFile; fileRef = F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F40C3B712AB401C5007A3567 /* WKDatePickerPopoverController.h in Headers */ = {isa = PBXBuildFile; fileRef = F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */; };
 		F41145682CD939E0004CDBD1 /* _WKTouchEventGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = F41145652CD939E0004CDBD1 /* _WKTouchEventGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -6282,6 +6300,7 @@
 		5CABDC8522C40FCC001EDE8E /* WKMessageListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKMessageListener.h; sourceTree = "<group>"; };
 		5CABE07A28F60E8A00D83FD9 /* WebPushMessage.serialization.in */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebPushMessage.serialization.in; sourceTree = "<group>"; };
 		5CADDE0D2151AA010067D309 /* AuthenticationChallengeDisposition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AuthenticationChallengeDisposition.h; sourceTree = "<group>"; };
+		1D7178FBC4EDB168CDB0B04D /* UnifiedSource116.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource116.cpp; sourceTree = "<group>"; };
 		5CAECB5E27465AE300AB78D0 /* UnifiedSource115.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource115.cpp; sourceTree = "<group>"; };
 		5CAF7AA426F93A750003F19E /* adattributiond */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = adattributiond; sourceTree = BUILT_PRODUCTS_DIR; };
 		5CAF7AA526F93A950003F19E /* adattributiond.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = adattributiond.cpp; sourceTree = "<group>"; };
@@ -7977,6 +7996,19 @@
 		DF0C5F24252ECB8D00D921DB /* WKDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownload.h; sourceTree = "<group>"; };
 		DF0C5F25252ECB8E00D921DB /* WKDownloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadInternal.h; sourceTree = "<group>"; };
 		DF0C5F26252ECB8E00D921DB /* WKDownloadDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDownloadDelegate.h; sourceTree = "<group>"; };
+		D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKBrowserInspector.h; sourceTree = "<group>"; };
+		D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorPlaywrightAgentClientMac.h; sourceTree = "<group>"; };
+		D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorPlaywrightAgentClient.h; sourceTree = "<group>"; };
+		D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteInspectorPipe.h; sourceTree = "<group>"; };
+		D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorEmulationAgent.h; sourceTree = "<group>"; };
+		D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebPageInspectorInputAgent.h; sourceTree = "<group>"; };
+		D71A94492372290B002C4D9E /* _WKBrowserInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _WKBrowserInspector.h; sourceTree = "<group>"; };
+		D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BrowserInspectorPipe.h; sourceTree = "<group>"; };
+		D76D6887238DBD80008D314B /* InspectorDialogAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorDialogAgent.h; sourceTree = "<group>"; };
+		D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorEmulationAgentMac.mm; sourceTree = "<group>"; };
+		D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorTargetProxyMac.mm; sourceTree = "<group>"; };
+		D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebPageInspectorInputAgentMac.mm; sourceTree = "<group>"; };
+		D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InspectorPlaywrightAgentClientMac.mm; sourceTree = "<group>"; };
 		DF462E0E23F22F5300EFF35F /* WKHTTPCookieStorePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKHTTPCookieStorePrivate.h; sourceTree = "<group>"; };
 		DF462E1123F338AD00EFF35F /* WKContentWorldPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKContentWorldPrivate.h; sourceTree = "<group>"; };
 		DF58C6311371AC5800F9A37C /* NativeWebWheelEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeWebWheelEvent.h; sourceTree = "<group>"; };
@@ -8137,6 +8169,8 @@
 		E5CBA76127A3187900DF7858 /* UnifiedSource118.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource118.cpp; sourceTree = "<group>"; };
 		E5CBA76227A3187900DF7858 /* UnifiedSource117.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource117.cpp; sourceTree = "<group>"; };
 		E5CBA76327A3187B00DF7858 /* UnifiedSource116.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = UnifiedSource116.cpp; sourceTree = "<group>"; };
+		E5CBA76F27A3187800DF7858 /* UnifiedSource121.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource121.cpp; sourceTree = "<group>"; };
+		E5CBA77F27A3187800DF7858 /* UnifiedSource122.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = UnifiedSource122.cpp; sourceTree = "<group>"; };
 		E5DEFA6726F8F42600AB68DB /* PhotosUISPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhotosUISPI.h; sourceTree = "<group>"; };
 		EB0D312D275AE13300863D8F /* com.apple.webkit.webpushd.mac.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.webkit.webpushd.mac.plist; sourceTree = "<group>"; };
 		EB0D312E275AE13300863D8F /* com.apple.webkit.webpushd.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.webkit.webpushd.ios.plist; sourceTree = "<group>"; };
@@ -8170,6 +8204,14 @@
 		ECA680D31E6904B500731D20 /* ExtraPrivateSymbolsForTAPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExtraPrivateSymbolsForTAPI.h; sourceTree = "<group>"; };
 		ECBFC1DB1E6A4D66000300C7 /* ExtraPublicSymbolsForTAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExtraPublicSymbolsForTAPI.h; sourceTree = "<group>"; };
 		F036978715F4BF0500C3A80E /* WebColorPicker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebColorPicker.cpp; sourceTree = "<group>"; };
+		F303B847249A8D3A0031DE5C /* ScreencastEncoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScreencastEncoder.cpp; sourceTree = "<group>"; };
+		F303B848249A8D3A0031DE5C /* ScreencastEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScreencastEncoder.h; sourceTree = "<group>"; };
+		F31E2DA424C76E4B004B2775 /* WebMFileWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebMFileWriter.cpp; sourceTree = "<group>"; };
+		F31E2DA524C76E4C004B2775 /* WebMFileWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebMFileWriter.h; sourceTree = "<group>"; };
+		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 = "<group>"; };
+		F3867F0424607D2B008F0F31 /* InspectorScreencastAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorScreencastAgent.h; sourceTree = "<group>"; };
+		F3970344249BD4CE003E1A22 /* ScreencastEncoderMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScreencastEncoderMac.mm; sourceTree = "<group>"; };
 		F409BA171E6E64B3009DA28E /* WKDragDestinationAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKDragDestinationAction.h; sourceTree = "<group>"; };
 		F40C3B6F2AB40167007A3567 /* WKDatePickerPopoverController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKDatePickerPopoverController.h; path = ios/forms/WKDatePickerPopoverController.h; sourceTree = "<group>"; };
 		F40C3B702AB40167007A3567 /* WKDatePickerPopoverController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = WKDatePickerPopoverController.mm; path = ios/forms/WKDatePickerPopoverController.mm; sourceTree = "<group>"; };
@@ -8503,6 +8545,7 @@
 				3766F9EE189A1241003CF19B /* JavaScriptCore.framework in Frameworks */,
 				3766F9F1189A1254003CF19B /* libicucore.dylib in Frameworks */,
 				7B9FC5BB28A5233B007570E7 /* libWebKitPlatform.a in Frameworks */,
+				F33C7AC7249AD79C0018BE41 /* libwebrtc.dylib in Frameworks */,
 				3766F9EF189A1244003CF19B /* QuartzCore.framework in Frameworks */,
 				37694525184FC6B600CDE21F /* Security.framework in Frameworks */,
 				37BEC4DD1948FC6A008B4286 /* WebCore.framework in Frameworks */,
@@ -11507,6 +11550,7 @@
 				99788ACA1F421DCA00C08000 /* _WKAutomationSessionConfiguration.mm */,
 				990D28A81C6404B000986977 /* _WKAutomationSessionDelegate.h */,
 				990D28AF1C65203900986977 /* _WKAutomationSessionInternal.h */,
+				D71A94492372290B002C4D9E /* _WKBrowserInspector.h */,
 				5C4609E222430E4C009943C2 /* _WKContentRuleListAction.h */,
 				5C4609E322430E4D009943C2 /* _WKContentRuleListAction.mm */,
 				5C4609E422430E4D009943C2 /* _WKContentRuleListActionInternal.h */,
@@ -12853,6 +12897,7 @@
 				E34B110C27C46BC6006D2F2E /* libWebCoreTestShim.dylib */,
 				E34B110F27C46D09006D2F2E /* libWebCoreTestSupport.dylib */,
 				DDE992F4278D06D900F60D26 /* libWebKitAdditions.a */,
+				F33C7AC6249AD79C0018BE41 /* libwebrtc.dylib */,
 				57A9FF15252C6AEF006A2040 /* libWTF.a */,
 				5750F32A2032D4E500389347 /* LocalAuthentication.framework */,
 				570DAAB0230273D200E8FC04 /* NearField.framework */,
@@ -13426,6 +13471,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 = "<group>";
@@ -13434,6 +13485,7 @@
 			isa = PBXGroup;
 			children = (
 				A5D3504D1D78F0D2005124A9 /* RemoteWebInspectorUIProxyMac.mm */,
+				F3970344249BD4CE003E1A22 /* ScreencastEncoderMac.mm */,
 				1CA8B935127C774E00576C2B /* WebInspectorUIProxyMac.mm */,
 				99A7ACE326012919006D57FD /* WKInspectorResourceURLSchemeHandler.h */,
 				99A7ACE42601291A006D57FD /* WKInspectorResourceURLSchemeHandler.mm */,
@@ -14151,6 +14203,7 @@
 				E1513C65166EABB200149FCB /* AuxiliaryProcessProxy.h */,
 				46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */,
 				46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */,
+				D71A944B237239FB002C4D9E /* BrowserInspectorPipe.h */,
 				5C6D69352AC3935D0099BDAF /* BrowsingContextGroup.cpp */,
 				5C6D69362AC3935D0099BDAF /* BrowsingContextGroup.h */,
 				5CA98549210BEB5A0057EB6B /* BrowsingWarning.h */,
@@ -14175,6 +14228,8 @@
 				BC06F43912DBCCFB002D78DE /* GeolocationPermissionRequestProxy.cpp */,
 				BC06F43812DBCCFB002D78DE /* GeolocationPermissionRequestProxy.h */,
 				2DD5A72A1EBF09A7009BA597 /* HiddenPageThrottlingAutoIncreasesCounter.h */,
+				D76D6887238DBD80008D314B /* InspectorDialogAgent.h */,
+				D71A94332370E07A002C4D9E /* InspectorPlaywrightAgentClient.h */,
 				5CEABA2B2333251400797797 /* LegacyGlobalSettings.cpp */,
 				5CEABA2A2333247700797797 /* LegacyGlobalSettings.h */,
 				31607F3819627002009B87DA /* LegacySessionStateCoding.h */,
@@ -14208,6 +14263,7 @@
 				1A0C227D2451130A00ED614D /* QuickLookThumbnailingSoftLink.mm */,
 				1AEE57232409F142002005D6 /* QuickLookThumbnailLoader.h */,
 				1AEE57242409F142002005D6 /* QuickLookThumbnailLoader.mm */,
+				D71A94392370F060002C4D9E /* RemoteInspectorPipe.h */,
 				5CCB54DC2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.cpp */,
 				5CCB54DB2A4FEA6A0005FAA8 /* RemotePageDrawingAreaProxy.h */,
 				5C907E9A294D507100B3402D /* RemotePageProxy.cpp */,
@@ -14308,6 +14364,8 @@
 				BC7B6204129A0A6700D174A4 /* WebPageGroup.h */,
 				2D9EA3101A96D9EB002D2807 /* WebPageInjectedBundleClient.cpp */,
 				2D9EA30E1A96CBFF002D2807 /* WebPageInjectedBundleClient.h */,
+				D71A943F2371F67E002C4D9E /* WebPageInspectorEmulationAgent.h */,
+				D71A94402371F67E002C4D9E /* WebPageInspectorInputAgent.h */,
 				9B7F8A502C785725000057F3 /* WebPageLoadTiming.h */,
 				BC111B0B112F5E4F00337BAB /* WebPageProxy.cpp */,
 				BC032DCB10F4389F0058C15A /* WebPageProxy.h */,
@@ -14486,6 +14544,7 @@
 				BC646C1911DD399F006455B0 /* WKBackForwardListItemRef.h */,
 				BC646C1611DD399F006455B0 /* WKBackForwardListRef.cpp */,
 				BC646C1711DD399F006455B0 /* WKBackForwardListRef.h */,
+				D71A942C2370DF81002C4D9E /* WKBrowserInspector.h */,
 				BCB9E24A1120E15C00A137E0 /* WKContext.cpp */,
 				BCB9E2491120E15C00A137E0 /* WKContext.h */,
 				1AE52F9319201F6B00A1FA37 /* WKContextConfigurationRef.cpp */,
@@ -15060,6 +15119,9 @@
 				07EF07592745A8160066EA04 /* DisplayCaptureSessionManager.h */,
 				07EF07582745A8160066EA04 /* DisplayCaptureSessionManager.mm */,
 				7AFA6F682A9F57C50055322A /* DisplayLinkMac.cpp */,
+				D71A94302370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h */,
+				D7EB04E62372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm */,
+				D79902AF236E9404005D6F7E /* InspectorTargetProxyMac.mm */,
 				1AFDE65B1954E8D500C48FFA /* LegacySessionStateCoding.cpp */,
 				0FCB4E5818BBE3D9000FCFC9 /* PageClientImplMac.h */,
 				0FCB4E5918BBE3D9000FCFC9 /* PageClientImplMac.mm */,
@@ -15083,6 +15145,8 @@
 				E568B92120A3AC6A00E3C856 /* WebDataListSuggestionsDropdownMac.mm */,
 				E55CD20124D09F1F0042DB9C /* WebDateTimePickerMac.h */,
 				E55CD20224D09F1F0042DB9C /* WebDateTimePickerMac.mm */,
+				D79902AE236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm */,
+				D79902B0236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm */,
 				BC857E8512B71EBB00EDEB2E /* WebPageProxyMac.mm */,
 				BC5750951268F3C6006F0F12 /* WebPopupMenuProxyMac.h */,
 				BC5750961268F3C6006F0F12 /* WebPopupMenuProxyMac.mm */,
@@ -16142,6 +16206,7 @@
 				99788ACB1F421DDA00C08000 /* _WKAutomationSessionConfiguration.h in Headers */,
 				990D28AC1C6420CF00986977 /* _WKAutomationSessionDelegate.h in Headers */,
 				990D28B11C65208D00986977 /* _WKAutomationSessionInternal.h in Headers */,
+				D71A944A2372290B002C4D9E /* _WKBrowserInspector.h in Headers */,
 				5C4609E7224317B4009943C2 /* _WKContentRuleListAction.h in Headers */,
 				5C4609E8224317BB009943C2 /* _WKContentRuleListActionInternal.h in Headers */,
 				9B4CE9512CD99B7C00351173 /* _WKContentWorldConfiguration.h in Headers */,
@@ -16451,6 +16516,7 @@
 				E170876C16D6CA6900F99226 /* BlobRegistryProxy.h in Headers */,
 				4F601432155C5AA2001FBDE0 /* BlockingResponseMap.h in Headers */,
 				1A5705111BE410E600874AF1 /* BlockSPI.h in Headers */,
+				D71A944C237239FB002C4D9E /* BrowserInspectorPipe.h in Headers */,
 				5CA9854A210BEB640057EB6B /* BrowsingWarning.h in Headers */,
 				A7E69BCC2B2117A100D43D3F /* BufferAndBackendInfo.h in Headers */,
 				BC3065FA1259344E00E71278 /* CacheModel.h in Headers */,
@@ -16634,7 +16700,11 @@
 				BC14DF77120B5B7900826C0C /* InjectedBundleScriptWorld.h in Headers */,
 				CE550E152283752200D28791 /* InsertTextOptions.h in Headers */,
 				9197940523DBC4BB00257892 /* InspectorBrowserAgent.h in Headers */,
+				D76D6888238DBD81008D314B /* InspectorDialogAgent.h in Headers */,
 				996B2B9D25E257FF00719379 /* InspectorExtensionDelegate.h in Headers */,
+				D71A94342370E07A002C4D9E /* InspectorPlaywrightAgentClient.h in Headers */,
+				D71A94322370E025002C4D9E /* InspectorPlaywrightAgentClientMac.h in Headers */,
+				F3867F0A24607D4E008F0F31 /* InspectorScreencastAgent.h in Headers */,
 				A5E391FD2183C1F800C8FB31 /* InspectorTargetProxy.h in Headers */,
 				C5BCE5DF1C50766A00CDE3FA /* InteractionInformationAtPosition.h in Headers */,
 				2D4D2C811DF60BF3002EB10C /* InteractionInformationRequest.h in Headers */,
@@ -16894,6 +16964,7 @@
 				0F6E7C532C4C386800F1DB85 /* RemoteDisplayListRecorderMessages.h in Headers */,
 				F451C0FE2703B263002BA03B /* RemoteDisplayListRecorderProxy.h in Headers */,
 				A78A5FE42B0EB39E005036D3 /* RemoteImageBufferSetIdentifier.h in Headers */,
+				D71A943A2370F061002C4D9E /* RemoteInspectorPipe.h in Headers */,
 				2D47B56D1810714E003A3AEE /* RemoteLayerBackingStore.h in Headers */,
 				2DDF731518E95060004F5A66 /* RemoteLayerBackingStoreCollection.h in Headers */,
 				1AB16AEA164B3A8800290D62 /* RemoteLayerTreeContext.h in Headers */,
@@ -16947,6 +17018,7 @@
 				E1E552C516AE065F004ED653 /* SandboxInitializationParameters.h in Headers */,
 				E36FF00327F36FBD004BE21A /* SandboxStateVariables.h in Headers */,
 				7BAB111025DD02B3008FC479 /* ScopedActiveMessageReceiveQueue.h in Headers */,
+				F303B849249A8D640031DE5C /* ScreencastEncoder.h in Headers */,
 				463BB93A2B9D08D80098C5C3 /* ScriptMessageHandlerIdentifier.h in Headers */,
 				F4E28A362C923814008120DD /* ScriptTelemetry.h in Headers */,
 				E4D54D0421F1D72D007E3C36 /* ScrollingTreeFrameScrollingNodeRemoteIOS.h in Headers */,
@@ -17299,6 +17371,8 @@
 				939EF87029D112EE00F23AEE /* WebPageInlines.h in Headers */,
 				9197940823DBC4CB00257892 /* WebPageInspectorAgentBase.h in Headers */,
 				A513F5402154A5D700662841 /* WebPageInspectorController.h in Headers */,
+				D71A94422371F67E002C4D9E /* WebPageInspectorEmulationAgent.h in Headers */,
+				D71A94432371F67E002C4D9E /* WebPageInspectorInputAgent.h in Headers */,
 				A543E30C215C8A8D00279CD9 /* WebPageInspectorTarget.h in Headers */,
 				A543E30D215C8A9000279CD9 /* WebPageInspectorTargetController.h in Headers */,
 				A543E307215AD13700279CD9 /* WebPageInspectorTargetFrontendChannel.h in Headers */,
@@ -19739,7 +19813,43 @@
 				522F792928D50EBB0069B45B /* HidService.mm in Sources */,
 				2749F6442146561B008380BF /* InjectedBundleNodeHandle.cpp in Sources */,
 				2749F6452146561E008380BF /* InjectedBundleRangeHandle.cpp in Sources */,
+				D7EB04E72372A73B00F744CE /* InspectorPlaywrightAgentClientMac.mm in Sources */,
+				D79902B2236E9404005D6F7E /* InspectorTargetProxyMac.mm in Sources */,
+				1CC94E532AC92F190045F269 /* JSWebExtensionAPIAction.mm in Sources */,
+				1C2B4D4B2A819D0D00C528A1 /* JSWebExtensionAPIAlarms.mm in Sources */,
+				1C8ECFEA2AFC7DCB007BAA62 /* JSWebExtensionAPICommands.mm in Sources */,
+				1C40052C2B2B953D00F2D9EE /* JSWebExtensionAPICookies.mm in Sources */,
+				331102402B17B99800B21C8C /* JSWebExtensionAPIDeclarativeNetRequest.mm in Sources */,
+				1C517F452B74393C00C46EDC /* JSWebExtensionAPIDevTools.mm in Sources */,
+				1C517F432B74393C00C46EDC /* JSWebExtensionAPIDevToolsExtensionPanel.mm in Sources */,
+				1C517F472B74393C00C46EDC /* JSWebExtensionAPIDevToolsInspectedWindow.mm in Sources */,
+				1C517F462B74393C00C46EDC /* JSWebExtensionAPIDevToolsNetwork.mm in Sources */,
+				1C517F412B74393C00C46EDC /* JSWebExtensionAPIDevToolsPanels.mm in Sources */,
+				B6114A7F29394A1600380B1B /* JSWebExtensionAPIEvent.mm in Sources */,
+				1C5DC471290B33A20061EC62 /* JSWebExtensionAPIExtension.mm in Sources */,
+				B6CCAAB929A445E90092E846 /* JSWebExtensionAPILocalization.mm in Sources */,
+				1CCEE4532B0989FC0034E059 /* JSWebExtensionAPIMenus.mm in Sources */,
+				1C5DC4552908AC900061EC62 /* JSWebExtensionAPINamespace.mm in Sources */,
+				1C386F362AF409F9004108F0 /* JSWebExtensionAPINotifications.mm in Sources */,
+				B61AFA4929510D0F008220B1 /* JSWebExtensionAPIPermissions.mm in Sources */,
+				1C9A15CF2ABDF1E2002CC12A /* JSWebExtensionAPIPort.mm in Sources */,
+				1C5DC472290B33A60061EC62 /* JSWebExtensionAPIRuntime.mm in Sources */,
+				B63E9A6F2AAF2B2D005F4561 /* JSWebExtensionAPIScripting.mm in Sources */,
+				029D6BB22C407AA30068CF99 /* JSWebExtensionAPISidebarAction.mm in Sources */,
+				029D6BB12C407AA30068CF99 /* JSWebExtensionAPISidePanel.mm in Sources */,
+				B63C10342B51C0B6004A69B8 /* JSWebExtensionAPIStorage.mm in Sources */,
+				B63C10372B51C102004A69B8 /* JSWebExtensionAPIStorageArea.mm in Sources */,
+				1C5ACFAB2A96F8D500C041C0 /* JSWebExtensionAPITabs.mm in Sources */,
+				1C15497F2926C073001B9E5B /* JSWebExtensionAPITest.mm in Sources */,
 				1C0F05BE2CFA5D2E007D1F62 /* JSWebExtensionAPIUnified.mm in Sources */,
+				3375A3772942A19D0028536D /* JSWebExtensionAPIWebNavigation.mm in Sources */,
+				33F68338293FF6F5005C63C0 /* JSWebExtensionAPIWebNavigationEvent.mm in Sources */,
+				B63A99772B7EA002004611FD /* JSWebExtensionAPIWebPageNamespace.mm in Sources */,
+				B63A99782B7EA002004611FD /* JSWebExtensionAPIWebPageRuntime.mm in Sources */,
+				3399E1532B59EFD7008BFB60 /* JSWebExtensionAPIWebRequest.mm in Sources */,
+				337042022B58A0B70077FF78 /* JSWebExtensionAPIWebRequestEvent.mm in Sources */,
+				1C5ACFA62A96F8C400C041C0 /* JSWebExtensionAPIWindows.mm in Sources */,
+				1C5ACFA72A96F8C400C041C0 /* JSWebExtensionAPIWindowsEvent.mm in Sources */,
 				1C5DC45F2909B05A0061EC62 /* JSWebExtensionWrapperCocoa.mm in Sources */,
 				C14D37FE24ACE086007FF014 /* LaunchServicesDatabaseManager.mm in Sources */,
 				C1710CF724AA643200D7C112 /* LaunchServicesDatabaseObserver.mm in Sources */,
@@ -20162,6 +20272,8 @@
 				074E87E12CF8EA3D0059E469 /* WebPage+NavigationDeciding.swift in Sources */,
 				078B04A02CF18EAB00B453A6 /* WebPage+NavigationPreferences.swift in Sources */,
 				07CB79962CE9435700199C49 /* WebPage.swift in Sources */,
+				D79902B1236E9404005D6F7E /* WebPageInspectorEmulationAgentMac.mm in Sources */,
+				D79902B3236E9404005D6F7E /* WebPageInspectorInputAgentMac.mm in Sources */,
 				C0CE72A01247E71D00BC0EC4 /* WebPageMessageReceiver.cpp in Sources */,
 				BCBD3914125BB1A800D2C29F /* WebPageProxyMessageReceiver.cpp in Sources */,
 				C0CE72A01B47E71D00BC0EC4 /* WebPageTestingMessageReceiver.cpp in Sources */,
diff --git a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
index cd28fa2f67ccd957ae04d59a86506f1c83659112..e66d60a8bf55b96c16a5582cd19939f3baa80a97 100644
--- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
+++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp
@@ -245,6 +245,11 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou
     }
 #endif
 
+    if (m_emulateOfflineState) {
+        scheduleInternallyFailedLoad(resourceLoader);
+        return;
+    }
+
 #if ENABLE(PDFJS)
     if (tryLoadingUsingPDFJSHandler(resourceLoader, trackingParameters))
         return;
@@ -254,12 +259,16 @@ void WebLoaderStrategy::scheduleLoad(ResourceLoader& resourceLoader, CachedResou
         return;
 
     if (InspectorInstrumentationWebKit::shouldInterceptRequest(resourceLoader)) {
-        InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource](const ResourceRequest& request) {
-            auto& resourceLoader = protectedResourceLoader.get();
-            WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: intercepted URL will be scheduled with the NetworkProcess");
-            scheduleLoadFromNetworkProcess(resourceLoader, request, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource));
-        });
-        return;
+        bool isMainFrameNavigation = resourceLoader.frame() && resourceLoader.frame()->isMainFrame() && resourceLoader.options().mode == FetchOptions::Mode::Navigate;
+        // Do not intercept navigation request which could already have been intercepted and resumed.
+        if (!(isMainFrameNavigation && m_existingNetworkResourceLoadIdentifierToResume)) {
+            InspectorInstrumentationWebKit::interceptRequest(resourceLoader, [this, protectedResourceLoader = Ref { resourceLoader }, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, resource](const ResourceRequest& request) {
+                auto& resourceLoader = protectedResourceLoader.get();
+                WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: intercepted URL will be scheduled with the NetworkProcess");
+                scheduleLoadFromNetworkProcess(resourceLoader, request, trackingParameters, shouldClearReferrerOnHTTPSToHTTPRedirect, maximumBufferingTime(resource));
+            });
+            return;
+        }
     }
 
     WEBLOADERSTRATEGY_RELEASE_LOG("scheduleLoad: URL will be scheduled with the NetworkProcess");
@@ -379,7 +388,8 @@ static void addParametersShared(const LocalFrame* frame, NetworkResourceLoadPara
         parameters.linkPreconnectEarlyHintsEnabled = mainFrame->settings().linkPreconnectEarlyHintsEnabled();
 }
 
-void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime)
+// static
+bool WebLoaderStrategy::fillParametersForNetworkProcessLoad(ResourceLoader& resourceLoader, const ResourceRequest& request, const WebResourceLoader::TrackingParameters& trackingParameters, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime, NetworkResourceLoadParameters& loadParameters)
 {
     auto identifier = *resourceLoader.identifier();
 
@@ -394,7 +404,7 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
             RunLoop::main().dispatch([resourceLoader = Ref { resourceLoader }, error = blockedError(request)] {
                 resourceLoader->didFail(error);
             });
-            return;
+            return false;
         }
     }
 
@@ -404,7 +414,6 @@ void WebLoaderStrategy::scheduleLoadFromNetworkProcess(ResourceLoader& resourceL
 
     LOG(NetworkScheduling, "(WebProcess) WebLoaderStrategy::scheduleLoad, url '%s' will be scheduled with the NetworkProcess with priority %d, storedCredentialsPolicy %i", resourceLoader.url().string().latin1().data(), static_cast<int>(resourceLoader.request().priority()), (int)storedCredentialsPolicy);
 
-    NetworkResourceLoadParameters loadParameters;
     loadParameters.identifier = identifier;
     loadParameters.webPageProxyID = trackingParameters.webPageProxyID;
     loadParameters.webPageID = trackingParameters.pageID;
@@ -494,14 +503,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<int>(resourceLoader.request().priority()));
-            scheduleInternallyFailedLoad(resourceLoader);
-            return;
-        }
+        if (!loadParameters.sourceOrigin)
+            return false;
     }
 
-    loadParameters.shouldRestrictHTTPResponseAccess = shouldPerformSecurityChecks();
+    loadParameters.shouldRestrictHTTPResponseAccess = DeprecatedGlobalSettings::restrictedHTTPResponseAccess();
 
     loadParameters.isMainFrameNavigation = isMainFrameNavigation;
     if (loadParameters.isMainFrameNavigation && document)
@@ -542,6 +548,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<int>(resourceLoader.request().priority()));
+        scheduleInternallyFailedLoad(resourceLoader);
+        return;
+    }
 
     std::optional<NetworkResourceLoadIdentifier> existingNetworkResourceLoadIdentifierToResume;
     if (loadParameters.isMainFrameNavigation)
@@ -557,7 +574,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)
@@ -967,7 +984,7 @@ void WebLoaderStrategy::didFinishPreconnection(WebCore::ResourceLoaderIdentifier
 
 bool WebLoaderStrategy::isOnLine() const
 {
-    return m_isOnLine;
+    return m_emulateOfflineState ? false : m_isOnLine;
 }
 
 void WebLoaderStrategy::addOnlineStateChangeListener(Function<void(bool)>&& listener)
@@ -994,6 +1011,11 @@ void WebLoaderStrategy::isResourceLoadFinished(CachedResource& resource, Complet
 
 void WebLoaderStrategy::setOnLineState(bool isOnLine)
 {
+    if (m_emulateOfflineState) {
+        m_isOnLine = isOnLine;
+        return;
+    }
+
     if (m_isOnLine == isOnLine)
         return;
 
@@ -1002,6 +1024,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 a835521fae8043c1c3d6202288b0c3a9f92aa81b..0c8bee6c0a02e6adb1b9e56d77613253111fffd2 100644
--- a/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h
+++ b/Source/WebKit/WebProcess/Network/WebLoaderStrategy.h
@@ -44,6 +44,7 @@ struct FetchOptions;
 namespace WebKit {
 
 class NetworkProcessConnection;
+class NetworkResourceLoadParameters;
 class WebFrame;
 class WebPage;
 class WebProcess;
@@ -96,6 +97,9 @@ public:
     bool isOnLine() const final;
     void addOnlineStateChangeListener(Function<void(bool)>&&) final;
     void setOnLineState(bool);
+    void setEmulateOfflineState(bool) final;
+
+    static bool fillParametersForNetworkProcessLoad(WebCore::ResourceLoader&, const WebCore::ResourceRequest&, const WebResourceLoader::TrackingParameters&, bool shouldClearReferrerOnHTTPSToHTTPRedirect, Seconds maximumBufferingTime, NetworkResourceLoadParameters&);
 
     void setExistingNetworkResourceLoadIdentifierToResume(std::optional<NetworkResourceLoadIdentifier> existingNetworkResourceLoadIdentifierToResume) { m_existingNetworkResourceLoadIdentifierToResume = existingNetworkResourceLoadIdentifierToResume; }
 
@@ -149,6 +153,7 @@ private:
     Vector<Function<void(bool)>> m_onlineStateChangeListeners;
     std::optional<NetworkResourceLoadIdentifier> m_existingNetworkResourceLoadIdentifierToResume;
     bool m_isOnLine { true };
+    bool m_emulateOfflineState { false };
 };
 
 } // namespace WebKit
diff --git a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp
index 752ac70125786e40d4976059f2f9c55982e746d7..adcbfb36714703e202f7e11a9113a2df03e399dc 100644
--- a/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp
+++ b/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp
@@ -188,9 +188,6 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR
             }
 
             m_coreLoader->didReceiveResponse(inspectorResponse, [this, protectedThis = WTFMove(protectedThis), interceptedRequestIdentifier, policyDecisionCompletionHandler = WTFMove(policyDecisionCompletionHandler), overrideData = WTFMove(overrideData)]() mutable {
-                if (policyDecisionCompletionHandler)
-                    policyDecisionCompletionHandler();
-
                 if (!m_coreLoader || !m_coreLoader->identifier()) {
                     m_interceptController.continueResponse(interceptedRequestIdentifier);
                     return;
@@ -208,6 +205,8 @@ void WebResourceLoader::didReceiveResponse(ResourceResponse&& response, PrivateR
                 }
             });
         });
+        if (policyDecisionCompletionHandler)
+          policyDecisionCompletionHandler();
         return;
     }
 
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
index b2f4f1e2978f3bcd72a2c7af6705028af47e9300..f334bfa826c49ee7bc09a9042329dbe27479b27c 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.cpp
@@ -481,6 +481,8 @@ void WebChromeClient::addMessageToConsole(MessageSource source, MessageLevel lev
 {
     // Notify the bundle client.
     auto page = protectedPage();
+    if (level == MessageLevel::Error)
+        page->send(Messages::WebPageProxy::LogToStderr(message));
     page->injectedBundleUIClient().willAddMessageToConsole(page.ptr(), source, level, message, lineNumber, columnNumber, sourceID);
 }
 
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp
index dd03326b1ad54e1d363d722cfe86bb779fbeead1..f54d631dc4034c995cbd74ec6b545c3c7dd25990 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp
+++ b/Source/WebKit/WebProcess/WebCoreSupport/WebDragClient.cpp
@@ -53,7 +53,7 @@ OptionSet<DragSourceAction> WebDragClient::dragSourceActionMaskForPoint(const In
     return m_page->allowedDragSourceActions();
 }
 
-#if !PLATFORM(COCOA) && !PLATFORM(GTK)
+#if !PLATFORM(COCOA) && !PLATFORM(GTK) && !PLATFORM(WPE) && !PLATFORM(WIN)
 void WebDragClient::startDrag(DragItem, DataTransfer&, Frame&)
 {
 }
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
index 2713e431893efd17c95d163f14aec45b27e0d6fc..b96b1d9cba20af611837915412fa4202667e800d 100644
--- a/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
+++ b/Source/WebKit/WebProcess/WebCoreSupport/mac/WebDragClientMac.mm
@@ -128,7 +128,8 @@ static WebCore::CachedImage* cachedImage(Element& element)
 
 void WebDragClient::declareAndWriteDragImage(const String& pasteboardName, Element& element, const URL& url, const String& label, LocalFrame*)
 {
-    ASSERT(pasteboardName == String(NSPasteboardNameDrag));
+    if (pasteboardName != String(NSPasteboardNameDrag))
+        return;
 
     WebCore::CachedImage* image = cachedImage(element);
 
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..66972b66094050b2429a927861ff7d0d30925ef0
--- /dev/null
+++ b/Source/WebKit/WebProcess/WebCoreSupport/win/WebDragClientWin.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebDragClient.h"
+
+#if ENABLE(DRAG_SUPPORT)
+
+//#include "ArgumentCodersWPE.h"
+#include "MessageSenderInlines.h"
+#include "WebPage.h"
+#include "WebPageProxyMessages.h"
+#include <WebCore/DataTransfer.h>
+#include <WebCore/DragData.h>
+#include <WebCore/Pasteboard.h>
+#include <WebCore/ShareableBitmap.h>
+#include <wtf/win/GDIObject.h>
+
+//#include <WebCore/SelectionData.h>
+
+namespace WebKit {
+using namespace WebCore;
+
+void WebDragClient::didConcludeEditDrag()
+{
+}
+
+void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame& frame)
+{
+    m_page->willStartDrag();
+    m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().createDragDataMap()));
+}
+
+}; // namespace WebKit.
+
+#endif // ENABLE(DRAG_SUPPORT)
diff --git a/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp b/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..226b3bf6bd83d2606a0aeb627ae9302fd3bcf874
--- /dev/null
+++ b/Source/WebKit/WebProcess/WebCoreSupport/wpe/WebDragClientWPE.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebDragClient.h"
+
+#if ENABLE(DRAG_SUPPORT)
+
+#include "WebPage.h"
+#include "WebPageProxyMessages.h"
+#include <WebCore/DataTransfer.h>
+#include <WebCore/DragData.h>
+#include <WebCore/Pasteboard.h>
+#include <WebCore/SelectionData.h>
+#include <WebCore/ShareableBitmap.h>
+
+namespace WebKit {
+using namespace WebCore;
+
+void WebDragClient::didConcludeEditDrag()
+{
+}
+
+void WebDragClient::startDrag(DragItem, DataTransfer& dataTransfer, Frame&)
+{
+    m_page->willStartDrag();
+
+    std::optional<ShareableBitmap::Handle> handle;
+    m_page->send(Messages::WebPageProxy::StartDrag(dataTransfer.pasteboard().selectionData(), dataTransfer.sourceOperationMask(), WTFMove(handle), dataTransfer.dragLocation()));
+}
+
+}; // namespace WebKit.
+
+#endif // ENABLE(DRAG_SUPPORT)
diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp
index ac4b96234c1c2a32dbeae20431c83152dcede91c..6a3c70a9fd2d2f4f413f0e3e925280fb261c4d2c 100644
--- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp
+++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp
@@ -39,6 +39,7 @@
 #include "WebPreferencesKeys.h"
 #include "WebProcess.h"
 #include <WebCore/GraphicsContext.h>
+#include <WebCore/InspectorController.h>
 #include <WebCore/LocalFrame.h>
 #include <WebCore/LocalFrameView.h>
 #include <WebCore/Page.h>
@@ -557,6 +558,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::sendEnterAcceleratedCompositingModeIfNeeded()
@@ -614,6 +620,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(0, WTFMove(updateInfo)));
     }
+// Playwright begin
+#if PLATFORM(WIN)
+    didChangeAcceleratedCompositingMode(false);
+#endif
+// Playwright end
 }
 
 void DrawingAreaCoordinatedGraphics::scheduleDisplay()
diff --git a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h
index 1d62e85762b73fa351384ba79ae5f48df02193b3..e8f8c2186a2dd87d01dcff19ebbb0fd74f500fb4 100644
--- a/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h
+++ b/Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/LayerTreeHost.h
@@ -138,6 +138,7 @@ public:
 #if PLATFORM(WPE) && USE(GBM) && ENABLE(WPE_PLATFORM)
     void preferredBufferFormatsDidChange();
 #endif
+
 private:
     void layerFlushTimerFired();
     void flushLayers();
diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp
index 428e10e8311dfb3201439688f5ad35a4d609b95c..b03ccee5c7057875092607d01b72265d63a2cfd9 100644
--- a/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp
+++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.cpp
@@ -27,6 +27,7 @@
 #include "DrawingArea.h"
 
 #include "DrawingAreaMessages.h"
+#include "DrawingAreaProxyMessages.h"
 #include "Logging.h"
 #include "WebPage.h"
 #include "WebPageCreationParameters.h"
@@ -115,6 +116,13 @@ void DrawingArea::tryMarkLayersVolatile(CompletionHandler<void(bool)>&& completi
     completionFunction(true);
 }
 
+#if PLATFORM(WIN)
+void DrawingArea::didChangeAcceleratedCompositingMode(bool enabled)
+{
+    send(Messages::DrawingAreaProxy::DidChangeAcceleratedCompositingMode(enabled));
+}
+#endif
+
 void DrawingArea::removeMessageReceiverIfNeeded()
 {
     if (m_hasRemovedMessageReceiver)
diff --git a/Source/WebKit/WebProcess/WebPage/DrawingArea.h b/Source/WebKit/WebProcess/WebPage/DrawingArea.h
index c641cf97ccc4b954ac699c0b1bdda10444abbe5c..a4f9198d9dd588cc872473b5502405d131bfe6be 100644
--- a/Source/WebKit/WebProcess/WebPage/DrawingArea.h
+++ b/Source/WebKit/WebProcess/WebPage/DrawingArea.h
@@ -166,6 +166,9 @@ public:
     virtual bool enterAcceleratedCompositingModeIfNeeded() = 0;
     virtual void backgroundColorDidChange() { };
 #endif
+#if PLATFORM(WIN)
+    void didChangeAcceleratedCompositingMode(bool enabled);
+#endif
 
 #if PLATFORM(WPE) && USE(GBM) && ENABLE(WPE_PLATFORM)
     virtual void preferredBufferFormatsDidChange() { }
diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp
index a31872554bb37f3335ea48866461107b32556ba3..d7bbe179a3b16db259062eac7cb65de2aac8afa9 100644
--- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp
+++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.cpp
@@ -44,6 +44,7 @@
 #include <WebCore/LocalFrame.h>
 #include <WebCore/LocalFrameLoaderClient.h>
 #include <WebCore/Page.h>
+#include <WebCore/ResourceLoader.h>
 #include <WebCore/ScriptTelemetryCategory.h>
 #include <WebCore/Settings.h>
 #include <WebCore/StorageSessionProvider.h>
@@ -455,6 +456,12 @@ void WebCookieJar::removeChangeListener(const String& host, const WebCore::Cooki
 }
 #endif
 
+void WebCookieJar::setCookieFromResponse(ResourceLoader& loader, const String& setCookieValue)
+{
+    const auto& request = loader.request();
+    WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::SetCookieFromResponse(request.firstPartyForCookies(), SameSiteInfo::create(request), request.url(), setCookieValue), 0);
+}
+
 #if !PLATFORM(COCOA)
 
 String WebCookieJar::cookiesInPartitionedCookieStorage(const WebCore::Document&, const URL&, const WebCore::SameSiteInfo&) const
diff --git a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h
index c25dbee9c0202246efaaedd9f3206d246cfc734c..94da3d92a2b6b1ec468c7db3bb19cae79ec29bd6 100644
--- a/Source/WebKit/WebProcess/WebPage/WebCookieJar.h
+++ b/Source/WebKit/WebProcess/WebPage/WebCookieJar.h
@@ -75,6 +75,8 @@ public:
 
     void clearCache() final;
 
+    void setCookieFromResponse(WebCore::ResourceLoader&, const String& setCookieValue);
+
 private:
     WebCookieJar();
 
diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp
index a3cef9a9f48791fdd86c039ef76b0a23e1301d8a..9a79ae8681499c0ff76b856add6d5efd084f3b62 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp
@@ -237,6 +237,7 @@
 #include <WebCore/ImageAnalysisQueue.h>
 #include <WebCore/ImageOverlay.h>
 #include <WebCore/InspectorController.h>
+#include <WebCore/InspectorInstrumentationWebKit.h>
 #include <WebCore/JSDOMExceptionHandling.h>
 #include <WebCore/KeyboardEvent.h>
 #include <WebCore/LegacySchemeRegistry.h>
@@ -1117,6 +1118,12 @@ WebPage::WebPage(PageIdentifier pageID, WebPageCreationParameters&& parameters)
     setLinkDecorationFilteringData(WTFMove(parameters.linkDecorationFilteringData));
     setAllowedQueryParametersForAdvancedPrivacyProtections(WTFMove(parameters.allowedQueryParametersForAdvancedPrivacyProtections));
 #endif
+    // For popup windows WebPage::Show() maybe called in the next lines from the constructor,
+    // at which point the page is not in the WebProcess's map yet and it is not safe to
+    // dispatch nested message loop and receive IPC messages. To mitigate that, the actual
+    // pause is postponed until the page is added to the map.
+    if (parameters.shouldPauseInInspectorWhenShown)
+        m_page->inspectorController().pauseOnStart(parameters.windowFeatures ? InspectorController::PauseCondition::WHEN_CREATION_FINISHED : InspectorController::PauseCondition::WHEN_SHOWN);
     if (parameters.windowFeatures) {
         m_page->applyWindowFeatures(*parameters.windowFeatures);
         m_page->chrome().show();
@@ -2074,6 +2081,22 @@ void WebPage::loadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, st
     frame->loadDidCommitInAnotherProcess(layerHostingContextIdentifier);
 }
 
+void WebPage::loadRequestInFrameForInspector(LoadParameters&& loadParameters, WebCore::FrameIdentifier frameID)
+{
+    WebFrame* frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame) {
+        send(Messages::WebPageProxy::DidDestroyNavigation(*loadParameters.navigationID));
+        return;
+    }
+
+    // FIXME: use m_pendingNavigationID instead?
+    m_pendingFrameNavigationID = loadParameters.navigationID;
+
+    FrameLoadRequest frameLoadRequest { *frame->coreLocalFrame(), loadParameters.request };
+    frame->coreLocalFrame()->loader().load(WTFMove(frameLoadRequest));
+    ASSERT(!m_pendingFrameNavigationID);
+}
+
 void WebPage::loadRequest(LoadParameters&& loadParameters)
 {
     WEBPAGE_RELEASE_LOG(Loading, "loadRequest: navigationID=%" PRIu64 ", shouldTreatAsContinuingLoad=%u, lastNavigationWasAppInitiated=%d, existingNetworkResourceLoadIdentifierToResume=%" PRIu64, loadParameters.navigationID ? loadParameters.navigationID->toUInt64() : 0, static_cast<unsigned>(loadParameters.shouldTreatAsContinuingLoad), loadParameters.request.isAppInitiated(), loadParameters.existingNetworkResourceLoadIdentifierToResume ? loadParameters.existingNetworkResourceLoadIdentifierToResume->toUInt64() : 0);
@@ -2269,7 +2292,9 @@ void WebPage::stopLoading()
 void WebPage::stopLoadingDueToProcessSwap()
 {
     SetForScope isStoppingLoadingDueToProcessSwap(m_isStoppingLoadingDueToProcessSwap, true);
+    InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(m_page.get(), true);
     stopLoading();
+    InspectorInstrumentationWebKit::setStoppingLoadingDueToProcessSwap(m_page.get(), false);
 }
 
 bool WebPage::defersLoading() const
@@ -2860,6 +2885,22 @@ void WebPage::viewportPropertiesDidChange(const ViewportArguments& viewportArgum
 #else
     UNUSED_PARAM(viewportArguments);
 #endif
+
+    // Playwright begin
+    RefPtr localMainFrame = dynamicDowncast<LocalFrame>(m_page->mainFrame());
+    RefPtr view = localMainFrame ? localMainFrame->view() : nullptr;
+    if (view && view->useFixedLayout()) {
+        if (m_viewSize.isEmpty())
+            return;
+        Settings& settings = m_page->settings();
+        int deviceWidth = (settings.deviceWidth() > 0) ? settings.deviceWidth() : m_viewSize.width();
+        int deviceHeight = (settings.deviceHeight() > 0) ? settings.deviceHeight() : m_viewSize.height();
+        int minimumLayoutFallbackWidth = std::max<int>(settings.layoutFallbackWidth(), m_viewSize.width());
+        ViewportAttributes attr = computeViewportAttributes(viewportArguments, minimumLayoutFallbackWidth, deviceWidth, deviceHeight, 1, m_viewSize);
+        setFixedLayoutSize(roundedIntSize(attr.layoutSize));
+        scaleView(deviceWidth / attr.layoutSize.width());
+    }
+    // Playwright end
 }
 
 #if !PLATFORM(IOS_FAMILY)
@@ -3617,6 +3658,13 @@ void WebPage::flushDeferredScrollEvents()
     corePage()->flushDeferredScrollEvents();
 }
 
+#if ENABLE(ORIENTATION_EVENTS)
+void WebPage::setDeviceOrientation(WebCore::IntDegrees deviceOrientation)
+{
+    m_page->setOverrideOrientation(deviceOrientation);
+}
+#endif
+
 void WebPage::flushDeferredDidReceiveMouseEvent()
 {
     if (auto info = std::exchange(m_deferredDidReceiveMouseEvent, std::nullopt))
@@ -3876,6 +3924,97 @@ void WebPage::touchEvent(const WebTouchEvent& touchEvent, CompletionHandler<void
 
     completionHandler(touchEvent.type(), handled);
 }
+
+void WebPage::fakeTouchTap(const WebCore::IntPoint& position, uint8_t modifiers, CompletionHandler<void()>&& completionHandler)
+{
+    SetForScope<bool> 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<WebEventModifier> eventModifiers;
+    eventModifiers = eventModifiers.fromRaw(modifiers);
+
+    {
+        Vector<WebPlatformTouchPoint> touchPoints;
+        WebPlatformTouchPoint::State state = WebPlatformTouchPoint::State::Pressed;
+        touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force));
+
+        WebTouchEvent touchEvent({WebEventType::TouchStart, eventModifiers, WallTime::now()}, WTFMove(touchPoints), {}, {});
+
+        CurrentEvent currentEvent(touchEvent);
+        handled = handleTouchEvent(m_page->mainFrame().frameID(), touchEvent, m_page.get()).wasHandled();
+    }
+    {
+        Vector<WebPlatformTouchPoint> touchPoints;
+        WebPlatformTouchPoint::State state = WebPlatformTouchPoint::State::Released;
+        touchPoints.append(WebPlatformTouchPoint(id, state, screenPosition, position, radius, rotationAngle, force));
+
+        WebTouchEvent touchEvent({WebEventType::TouchEnd, eventModifiers, WallTime::now()}, WTFMove(touchPoints), {}, {});
+
+        CurrentEvent currentEvent(touchEvent);
+        handled = handleTouchEvent(m_page->mainFrame().frameID(), touchEvent, m_page.get()).wasHandled() || handled;
+    }
+    if (!handled) {
+        FloatPoint adjustedPoint;
+
+        auto* localMainFrame = dynamicDowncast<LocalFrame>(m_page->mainFrame());
+        if (!localMainFrame)
+            return;
+
+        Node* nodeRespondingToClick = localMainFrame->nodeRespondingToClickEvents(position, adjustedPoint);
+        Frame* frameRespondingToClick = nodeRespondingToClick ? nodeRespondingToClick->document().frame() : nullptr;
+        IntPoint adjustedIntPoint = roundedIntPoint(adjustedPoint);
+        if (!frameRespondingToClick) {
+            completionHandler();
+            return;
+        }
+        double force = 0.0;
+        SyntheticClickType syntheticClickType = SyntheticClickType::OneFingerTap;
+
+        auto modifiers = PlatformKeyboardEvent::currentStateOfModifierKeys();
+        localMainFrame->eventHandler().mouseMoved(PlatformMouseEvent(
+            adjustedIntPoint,
+            adjustedIntPoint,
+            MouseButton::None,
+            PlatformEvent::Type::MouseMoved,
+            0,
+            modifiers,
+            WallTime::now(),
+            force,
+            syntheticClickType
+        ));
+        localMainFrame->eventHandler().handleMousePressEvent(PlatformMouseEvent(
+            adjustedIntPoint,
+            adjustedIntPoint,
+            MouseButton::Left,
+            PlatformEvent::Type::MousePressed,
+            1,
+            modifiers,
+            WallTime::now(),
+            force,
+            syntheticClickType
+        ));
+        localMainFrame->eventHandler().handleMouseReleaseEvent(PlatformMouseEvent(
+            adjustedIntPoint,
+            adjustedIntPoint,
+            MouseButton::Left,
+            PlatformEvent::Type::MouseReleased,
+            1,
+            modifiers,
+            WallTime::now(),
+            force,
+            syntheticClickType
+        ));
+    }
+    completionHandler();
+}
 #endif
 
 void WebPage::cancelPointer(WebCore::PointerID pointerId, const WebCore::IntPoint& documentPoint)
@@ -3964,6 +4103,16 @@ void WebPage::sendMessageToTargetBackend(const String& targetId, const String& m
     m_inspectorTargetController->sendMessageToTargetBackend(targetId, message);
 }
 
+void WebPage::resumeInspectorIfPausedInNewWindow()
+{
+    m_page->inspectorController().resumeIfPausedInNewWindow();
+}
+
+void WebPage::didAddWebPageToWebProcess()
+{
+    m_page->inspectorController().didFinishPageCreation();
+}
+
 void WebPage::insertNewlineInQuotedContent()
 {
     RefPtr frame = m_page->checkedFocusController()->focusedOrMainFrame();
@@ -4205,6 +4354,7 @@ void WebPage::didCompletePageTransition()
 void WebPage::show()
 {
     send(Messages::WebPageProxy::ShowPage());
+    m_page->inspectorController().didShowPage();
 }
 
 void WebPage::setIsTakingSnapshotsForApplicationSuspension(bool isTakingSnapshotsForApplicationSuspension)
@@ -5365,7 +5515,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<DragOperation> draggingSourceOperationMask, SelectionData&& selectionData, OptionSet<DragApplicationFlags> flags, CompletionHandler<void(std::optional<DragOperation>, DragHandlingMethod, bool, unsigned, IntRect, IntRect, std::optional<RemoteUserInputEventData>)>&& completionHandler)
 {
     if (!m_page)
@@ -7788,6 +7938,10 @@ void WebPage::didCommitLoad(WebFrame* frame)
 #endif
 
     flushDeferredDidReceiveMouseEvent();
+// Playwright begin
+    if (frame->isMainFrame())
+        send(Messages::WebPageProxy::ViewScaleFactorDidChange(viewScaleFactor()));
+// Playwright end
 }
 
 void WebPage::didFinishDocumentLoad(WebFrame& frame)
@@ -8090,6 +8244,9 @@ Ref<DocumentLoader> WebPage::createDocumentLoader(LocalFrame& frame, const Resou
             WebsitePoliciesData::applyToDocumentLoader(WTFMove(*m_pendingWebsitePolicies), documentLoader);
             m_pendingWebsitePolicies = std::nullopt;
         }
+    } else if (m_pendingFrameNavigationID) {
+        documentLoader->setNavigationID(*m_pendingFrameNavigationID);
+        m_pendingFrameNavigationID = std::nullopt;
     }
 
     return documentLoader;
diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h
index 06525fa5fec204ac72bb3c2f4b7f37d83ab17105..ef1ed29cb9d74b7f4293ed3f498d13a8a343ffd6 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.h
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.h
@@ -65,6 +65,7 @@
 #include <WebCore/MediaKeySystemRequest.h>
 #include <WebCore/NowPlayingMetadataObserver.h>
 #include <WebCore/OwnerPermissionsPolicyData.h>
+#include <WebCore/Page.h>
 #include <WebCore/PageIdentifier.h>
 #include <WebCore/PageOverlay.h>
 #include <WebCore/PlatformLayerIdentifier.h>
@@ -1234,11 +1235,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<WebCore::DragOperation> draggingSourceOperationMask, WebCore::SelectionData&&, OptionSet<WebCore::DragApplicationFlags>, CompletionHandler<void(std::optional<WebCore::DragOperation>, WebCore::DragHandlingMethod, bool, unsigned, WebCore::IntRect, WebCore::IntRect, std::optional<WebCore::RemoteUserInputEventData>)>&&);
 #endif
 
-#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK)
+#if ENABLE(DRAG_SUPPORT) && !PLATFORM(GTK) && !PLATFORM(WPE)
     void performDragControllerAction(std::optional<WebCore::FrameIdentifier>, DragControllerAction, WebCore::DragData&&, CompletionHandler<void(std::optional<WebCore::DragOperation>, WebCore::DragHandlingMethod, bool, unsigned, WebCore::IntRect, WebCore::IntRect, std::optional<WebCore::RemoteUserInputEventData>)>&&);
     void performDragOperation(WebCore::DragData&&, SandboxExtensionHandle&&, Vector<SandboxExtensionHandle>&&, CompletionHandler<void(bool)>&&);
 #endif
@@ -1253,6 +1254,9 @@ public:
     void didStartDrag();
     void dragCancelled();
     OptionSet<WebCore::DragSourceAction> 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&);
@@ -1328,8 +1332,11 @@ public:
     void gestureEvent(WebCore::FrameIdentifier, const WebGestureEvent&);
 #endif
 
-#if PLATFORM(IOS_FAMILY)
+#if ENABLE(ORIENTATION_EVENTS)
     void setDeviceOrientation(WebCore::IntDegrees);
+#endif
+
+#if PLATFORM(IOS_FAMILY)
     void dynamicViewportSizeUpdate(const DynamicViewportSizeUpdate&);
     bool scaleWasSetByUIProcess() const { return m_scaleWasSetByUIProcess; }
     void willStartUserTriggeredZooming();
@@ -1479,6 +1486,8 @@ public:
     void connectInspector(const String& targetId, Inspector::FrontendChannel::ConnectionType);
     void disconnectInspector(const String& targetId);
     void sendMessageToTargetBackend(const String& targetId, const String& message);
+    void resumeInspectorIfPausedInNewWindow();
+    void didAddWebPageToWebProcess();
 
     void insertNewlineInQuotedContent();
 
@@ -1889,6 +1898,7 @@ public:
     void showContextMenuFromFrame(const WebCore::FrameIdentifier&, const ContextMenuContextData&, const UserData&);
 #endif
     void loadRequest(LoadParameters&&);
+    void loadRequestInFrameForInspector(LoadParameters&&, WebCore::FrameIdentifier);
 
     void setTopContentInset(float);
 
@@ -2065,6 +2075,7 @@ private:
     void updatePotentialTapSecurityOrigin(const WebTouchEvent&, bool wasHandled);
 #elif ENABLE(TOUCH_EVENTS)
     void touchEvent(const WebTouchEvent&, CompletionHandler<void(std::optional<WebEventType>, bool)>&&);
+    void fakeTouchTap(const WebCore::IntPoint& position, uint8_t modifiers, CompletionHandler<void()>&& completionHandler);
 #endif
 
     void cancelPointer(WebCore::PointerID, const WebCore::IntPoint&);
@@ -2829,6 +2840,7 @@ private:
     UserActivity m_userActivity;
 
     Markable<WebCore::NavigationIdentifier> m_pendingNavigationID;
+    Markable<WebCore::NavigationIdentifier> m_pendingFrameNavigationID;
     std::optional<WebsitePoliciesData> 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 5840247c1e8c94462c5106d385a7674ff023dbf3..02147c2cf05c35fdef280b08bceee1bd35cda79d 100644
--- a/Source/WebKit/WebProcess/WebPage/WebPage.messages.in
+++ b/Source/WebKit/WebProcess/WebPage/WebPage.messages.in
@@ -53,10 +53,13 @@ messages -> WebPage WantsAsyncDispatchMessage {
     MouseEvent(WebCore::FrameIdentifier frameID, WebKit::WebMouseEvent event, std::optional<Vector<WebKit::SandboxExtensionHandle>> sandboxExtensions)
     SetLastKnownMousePosition(WebCore::FrameIdentifier frameID, WebCore::IntPoint eventPoint, WebCore::IntPoint globalPoint);
 
+#if ENABLE(ORIENTATION_EVENTS)
+    SetDeviceOrientation(WebCore::IntDegrees deviceOrientation)
+#endif
+
 #if PLATFORM(IOS_FAMILY)
     SetSceneIdentifier(String sceneIdentifier)
     SetViewportConfigurationViewLayoutSize(WebCore::FloatSize size, double scaleFactor, double minimumEffectiveDeviceWidth)
-    SetDeviceOrientation(WebCore::IntDegrees deviceOrientation)
     SetOverrideViewportArguments(std::optional<WebCore::ViewportArguments> arguments)
     DynamicViewportSizeUpdate(struct WebKit::DynamicViewportSizeUpdate target)
     
@@ -147,6 +150,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);
@@ -157,6 +161,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType
 #endif
 #if !ENABLE(IOS_TOUCH_EVENTS) && ENABLE(TOUCH_EVENTS)
     TouchEvent(WebKit::WebTouchEvent event) -> (std::optional<WebKit::WebEventType> eventType, bool handled)
+    FakeTouchTap(WebCore::IntPoint position, uint8_t modifiers) -> () Async
 #endif
 
     CancelPointer(WebCore::PointerID pointerId, WebCore::IntPoint documentPoint)
@@ -190,6 +195,7 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType
     CreateProvisionalFrame(struct WebKit::ProvisionalFrameCreationParameters creationParameters, WebCore::FrameIdentifier frameID)
     DestroyProvisionalFrame(WebCore::FrameIdentifier frameID);
     LoadDidCommitInAnotherProcess(WebCore::FrameIdentifier frameID, std::optional<WebCore::LayerHostingContextIdentifier> layerHostingContextIdentifier)
+    LoadRequestInFrameForInspector(struct WebKit::LoadParameters loadParameters, WebCore::FrameIdentifier frameID)
     LoadRequestWaitingForProcessLaunch(struct WebKit::LoadParameters loadParameters, URL resourceDirectoryURL, WebKit::WebPageProxyIdentifier pageID, bool checkAssumedReadAccessToResourceURL)
     LoadData(struct WebKit::LoadParameters loadParameters)
     LoadSimulatedRequestAndResponse(struct WebKit::LoadParameters loadParameters, WebCore::ResourceResponse simulatedResponse)
@@ -355,10 +361,10 @@ GenerateSyntheticEditingCommand(enum:uint8_t WebKit::SyntheticEditingCommandType
     RemoveLayerForFindOverlay() -> ()
 
     # Drag and drop.
-#if PLATFORM(GTK) && ENABLE(DRAG_SUPPORT)
+#if (PLATFORM(GTK) || PLATFORM(WPE)) && ENABLE(DRAG_SUPPORT)
     PerformDragControllerAction(enum:uint8_t WebKit::DragControllerAction action, WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet<WebCore::DragOperation> draggingSourceOperationMask, WebCore::SelectionData selection, OptionSet<WebCore::DragApplicationFlags> flags) -> (std::optional<WebCore::DragOperation> dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect, WebCore::IntRect editableElementRect, struct std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData)
 #endif
-#if !PLATFORM(GTK) && ENABLE(DRAG_SUPPORT)
+#if !PLATFORM(GTK) && !PLATFORM(WPE) && ENABLE(DRAG_SUPPORT)
     PerformDragControllerAction(std::optional<WebCore::FrameIdentifier> frameID, enum:uint8_t WebKit::DragControllerAction action, WebCore::DragData dragData) -> (std::optional<WebCore::DragOperation> dragOperation, enum:uint8_t WebCore::DragHandlingMethod dragHandlingMethod, bool mouseIsOverFileInput, unsigned numberOfItemsToBeAccepted, WebCore::IntRect insertionRect, WebCore::IntRect editableElementRect, struct std::optional<WebCore::RemoteUserInputEventData> remoteUserInputEventData)
     PerformDragOperation(WebCore::DragData dragData, WebKit::SandboxExtensionHandle sandboxExtensionHandle, Vector<WebKit::SandboxExtensionHandle> sandboxExtensionsForUpload) -> (bool handled)
 #endif
@@ -368,6 +374,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<WebCore::DragSourceAction> allowedActionsMask)
     RequestAdditionalItemsForDragSession(WebCore::IntPoint clientPosition, WebCore::IntPoint globalPosition, OptionSet<WebCore::DragSourceAction> allowedActionsMask)
diff --git a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
index 6aac070297286654160c9cc5a5cf7de58dd1db87..4eddcc5c72784ca51ea87f2a9abb2504edfdbca7 100644
--- a/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
+++ b/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm
@@ -800,21 +800,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<PointerCharacteristics> WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const
 {
+#if ENABLE(TOUCH_EVENTS)
+    if (screenIsTouchPrimaryInputDevice())
+        return PointerCharacteristics::Coarse;
+#endif
     return PointerCharacteristics::Fine;
 }
 
 OptionSet<PointerCharacteristics> WebPage::pointerCharacteristicsOfAllAvailablePointingDevices() const
 {
+#if ENABLE(TOUCH_EVENTS)
+    if (screenHasTouchDevice())
+        return PointerCharacteristics::Coarse;
+#endif
     return PointerCharacteristics::Fine;
 }
 
diff --git a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp
index f17f5d719d892309ed9c7093384945866b5117b9..1dba47bbf0dbd0362548423a74b380346dbea147 100644
--- a/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp
+++ b/Source/WebKit/WebProcess/WebPage/win/WebPageWin.cpp
@@ -43,6 +43,7 @@
 #include <WebCore/NotImplemented.h>
 #include <WebCore/Page.h>
 #include <WebCore/PlatformKeyboardEvent.h>
+#include <WebCore/PlatformScreen.h>
 #include <WebCore/PointerCharacteristics.h>
 #include <WebCore/Settings.h>
 #include <WebCore/SharedBuffer.h>
@@ -81,21 +82,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<PointerCharacteristics> WebPage::pointerCharacteristicsOfPrimaryPointingDevice() const
 {
+#if ENABLE(TOUCH_EVENTS)
+    if (screenIsTouchPrimaryInputDevice())
+        return PointerCharacteristics::Coarse;
+#endif
     return PointerCharacteristics::Fine;
 }
 
 OptionSet<PointerCharacteristics> 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 94ec05dfede5cdb951323424a7776048ceb20921..4982962fd12f9bab1df21f855289b110b9aa8511 100644
--- a/Source/WebKit/WebProcess/WebProcess.cpp
+++ b/Source/WebKit/WebProcess/WebProcess.cpp
@@ -90,6 +90,7 @@
 #include "WebsiteData.h"
 #include "WebsiteDataStoreParameters.h"
 #include "WebsiteDataType.h"
+#include <JavaScriptCore/IdentifiersFactory.h>
 #include <JavaScriptCore/JSLock.h>
 #include <JavaScriptCore/MemoryStatistics.h>
 #include <JavaScriptCore/WasmFaultSignalHandler.h>
@@ -370,6 +371,14 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter
     {
         JSC::Options::AllowUnfinalizedAccessScope scope;
         JSC::Options::allowNonSPTagging() = false;
+        // Playwright begin
+        // SharedBufferArray is enabled only on Mac via XPC sercvice "enable-shared-array-buffer" option.
+        // For other platforms, enable it here.
+#if !PLATFORM(COCOA)
+        if (parameters.shouldEnableSharedArrayBuffer)
+            JSC::Options::useSharedArrayBuffer() = true;
+#endif
+        // Playwright end
         JSC::Options::notifyOptionsChanged();
     }
 
@@ -377,6 +386,8 @@ void WebProcess::initializeProcess(const AuxiliaryProcessInitializationParameter
     
     platformInitializeProcess(parameters);
     updateCPULimit();
+
+    Inspector::IdentifiersFactory::initializeWithProcessID(parameters.processIdentifier->toUInt64());
 }
 
 void WebProcess::initializeConnection(IPC::Connection* connection)
@@ -931,6 +942,7 @@ void WebProcess::createWebPage(PageIdentifier pageID, WebPageCreationParameters&
         accessibilityRelayProcessSuspended(false);
     }
     ASSERT(result.iterator->value);
+    result.iterator->value->didAddWebPageToWebProcess();
 }
 
 void WebProcess::removeWebPage(PageIdentifier pageID)
diff --git a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
index 64e9b56bbc644c8ed1583cdbf41878738860292d..fe83a85ccf53ee33f5a6a7461b40078d77928b61 100644
--- a/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
+++ b/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm
@@ -4223,7 +4223,7 @@ ALLOW_DEPRECATED_DECLARATIONS_END
     _private->handlingMouseDownEvent = NO;
 }
 
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(IOS_TOUCH_EVENTS)
 
 - (void)touch:(WebEvent *)event
 {
diff --git a/Source/WebKitLegacy/mac/WebView/WebView.mm b/Source/WebKitLegacy/mac/WebView/WebView.mm
index e1ecaa50847e76f2a02c62f5534a2e07f3df4fcd..2e79ce45b739517a03a464f223850aa0690d56d3 100644
--- a/Source/WebKitLegacy/mac/WebView/WebView.mm
+++ b/Source/WebKitLegacy/mac/WebView/WebView.mm
@@ -3986,7 +3986,7 @@ + (void)_doNotStartObservingNetworkReachability
 }
 #endif // PLATFORM(IOS_FAMILY)
 
-#if ENABLE(TOUCH_EVENTS)
+#if ENABLE(IOS_TOUCH_EVENTS)
 
 - (NSArray *)_touchEventRegions
 {
@@ -4028,7 +4028,7 @@ - (NSArray *)_touchEventRegions
     }).autorelease();
 }
 
-#endif // ENABLE(TOUCH_EVENTS)
+#endif // ENABLE(IOS_TOUCH_EVENTS)
 
 // For backwards compatibility with the WebBackForwardList API, we honor both
 // a per-WebView and a per-preferences setting for whether to use the back/forward cache.
diff --git a/Source/cmake/FindLibVPX.cmake b/Source/cmake/FindLibVPX.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..dd6a53e2d57318489b7e49dd7373706d5d9dc387
--- /dev/null
+++ b/Source/cmake/FindLibVPX.cmake
@@ -0,0 +1,25 @@
+# Find LibVPX
+
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_LIBVPX REQUIRED vpx)
+
+find_path(LIBVPX_INCLUDE_DIRS
+    NAMES vpx/vp8.h
+    HINTS ${PC_LIBVPX_INCLUDEDIR}
+          ${PC_LIBVPX_INCLUDE_DIRS}
+)
+
+find_library(LIBVPX_LIBRARIES
+    NAMES vpx
+    HINTS ${PC_LIBVPX_LIBDIR}
+          ${PC_LIBVPX_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibVPX REQUIRED_VARS LIBVPX_INCLUDE_DIRS LIBVPX_LIBRARIES
+                                         VERSION_VAR   PC_LIBVPX_VERSION)
+
+mark_as_advanced(
+    LIBVPX_INCLUDE_DIRS
+    LIBVPX_LIBRARIES
+)
diff --git a/Source/cmake/OptionsGTK.cmake b/Source/cmake/OptionsGTK.cmake
index 55aa3aea78f8286b04421f052f9e422e05f676a0..98ffe458294436b4c9224c412275e32fb61cd4ae 100644
--- a/Source/cmake/OptionsGTK.cmake
+++ b/Source/cmake/OptionsGTK.cmake
@@ -7,6 +7,9 @@ SET_PROJECT_VERSION(2 47 2)
 
 set(USER_AGENT_BRANDING "" CACHE STRING "Branding to add to user agent string")
 
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+
 find_package(Cairo 1.16.0 REQUIRED)
 find_package(LibGcrypt 1.7.0 REQUIRED)
 find_package(Libtasn1 REQUIRED)
@@ -22,6 +25,10 @@ find_package(ZLIB REQUIRED)
 find_package(WebP REQUIRED COMPONENTS demux)
 find_package(ATSPI 2.5.3)
 
+# Playwright begin
+find_package(LibVPX REQUIRED)
+# Playwright end
+
 include(GStreamerDefinitions)
 include(FindGLibCompileResources)
 
@@ -67,6 +74,10 @@ WEBKIT_OPTION_DEFINE(USE_SYSTEM_UNIFDEF "Whether to use a system-provided unifde
 
 WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE)
 
+# Playwright begin.
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SYSTEM_SYSPROF_CAPTURE PRIVATE OFF)
+# Playwright end.
+
 SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE})
 if (DEVELOPER_MODE)
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_API_TESTS PRIVATE ON)
@@ -153,6 +164,20 @@ endif ()
 
 WEBKIT_OPTION_DEPEND(ENABLE_GPU_PROCESS USE_GBM)
 
+# Playwright begin.
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_PDFJS PUBLIC OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_RECORDER PRIVATE OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_THUNDER PRIVATE OFF)
+
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_APPLICATION_MANIFEST PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CURSOR_VISIBILITY PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPEECH_SYNTHESIS PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_LOCK PRIVATE ON)
+# Playwright end.
+
 include(GStreamerDependencies)
 
 # Finalize the value for all options. Do not attempt to use an option before
diff --git a/Source/cmake/OptionsWPE.cmake b/Source/cmake/OptionsWPE.cmake
index 18252cd9598ad7554ece3a8a3f02435aa75e7737..311430134a2f44deaaf19e40b0f7ab393c898ccb 100644
--- a/Source/cmake/OptionsWPE.cmake
+++ b/Source/cmake/OptionsWPE.cmake
@@ -21,6 +21,9 @@ find_package(WebP REQUIRED COMPONENTS demux)
 find_package(WPE REQUIRED)
 find_package(ZLIB REQUIRED)
 
+set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+
 WEBKIT_OPTION_BEGIN()
 
 SET_AND_EXPOSE_TO_BUILD(ENABLE_DEVELOPER_MODE ${DEVELOPER_MODE})
@@ -83,6 +86,29 @@ if (WPE_VERSION VERSION_GREATER_EQUAL 1.13.90)
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_GAMEPAD PUBLIC ON)
 endif ()
 
+# Playwright begin.
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MINIBROWSER PUBLIC ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_PDFJS PUBLIC OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEDIA_RECORDER PRIVATE OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_THUNDER PRIVATE OFF)
+
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_APPLICATION_MANIFEST PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_CURSOR_VISIBILITY PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DARK_MODE_CSS PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DATALIST_ELEMENT 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_INPUT_TYPE_COLOR PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INPUT_TYPE_DATE PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_INPUT_TYPE_DATETIMELOCAL PRIVATE ON)
+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_DATE_AND_TIME_INPUT_TYPES PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_SPEECH_SYNTHESIS PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_LOCK PRIVATE ON)
+# Playwright end.
+
 # Public options specific to the WPE port. Do not add any options here unless
 # there is a strong reason we should support changing the value of the option,
 # and the option is not relevant to other WebKit ports.
@@ -116,6 +142,11 @@ WEBKIT_OPTION_DEPEND(ENABLE_DOCUMENTATION ENABLE_INTROSPECTION)
 WEBKIT_OPTION_DEPEND(USE_QT6 ENABLE_WPE_PLATFORM)
 WEBKIT_OPTION_DEPEND(USE_SYSTEM_SYSPROF_CAPTURE USE_SYSPROF_CAPTURE)
 
+# Playwright begin.
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_WPE_QT_API PUBLIC OFF)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(USE_SYSTEM_SYSPROF_CAPTURE PRIVATE OFF)
+# Playwright end.
+
 if (CMAKE_SYSTEM_NAME MATCHES "Linux")
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_BUBBLEWRAP_SANDBOX PUBLIC ON)
     WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_MEMORY_SAMPLER PRIVATE ON)
diff --git a/Source/cmake/OptionsWin.cmake b/Source/cmake/OptionsWin.cmake
index a61f5b5b7c2a193365eadc1996179e2b6f845c0f..94d6772b86429ef5c66f7b7f69fa04bbfc20eebe 100644
--- a/Source/cmake/OptionsWin.cmake
+++ b/Source/cmake/OptionsWin.cmake
@@ -76,6 +76,27 @@ find_package(ZLIB 1.2.11 REQUIRED)
 find_package(LibPSL 0.20.2 REQUIRED)
 find_package(WebP REQUIRED COMPONENTS demux)
 
+# Playwright begin
+set(LIBVPX_PACKAGE_PATH "C:\\vcpkg\\packages\\libvpx_x64-windows")
+file(TO_CMAKE_PATH "${LIBVPX_PACKAGE_PATH}" LIBVPX_PACKAGE_PATH)
+message(STATUS "Using LIBVPX_PACKAGE_PATH = ${LIBVPX_PACKAGE_PATH}")
+
+find_library(LIBVPX_CUSTOM_LIBRARY vpx.lib
+    HINTS ${LIBVPX_PACKAGE_PATH}/lib
+    REQUIRED
+    NO_DEFAULT_PATH
+)
+message(STATUS "Found LIBVPX_CUSTOM_LIBRARY = ${LIBVPX_CUSTOM_LIBRARY}")
+
+find_path(LIBVPX_CUSTOM_INCLUDE_DIR
+    NAMES vpx/vp8.h
+    HINTS ${LIBVPX_PACKAGE_PATH}/include
+    REQUIRED
+    NO_DEFAULT_PATH
+)
+message(STATUS "Found LIBVPX_CUSTOM_INCLUDE_DIR = ${LIBVPX_CUSTOM_INCLUDE_DIR}")
+# Playwright end
+
 WEBKIT_OPTION_BEGIN()
 
 # FIXME: Most of these options should not be public.
@@ -141,6 +162,14 @@ WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_FTPDIR PRIVATE OFF)
 SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_KEYBOARD_INTERACTIONS ON)
 SET_AND_EXPOSE_TO_BUILD(ENABLE_WEBDRIVER_MOUSE_INTERACTIONS ON)
 
+# Plawright begin
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DARK_MODE_CSS PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_DEVICE_ORIENTATION PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_NOTIFICATIONS PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_POINTER_LOCK PRIVATE ON)
+WEBKIT_OPTION_DEFAULT_PORT_VALUE(ENABLE_TOUCH_EVENTS PRIVATE ON)
+# Playwright end
+
 WEBKIT_OPTION_END()
 
 set(USE_ANGLE_EGL ON)
diff --git a/Source/cmake/WebKitCompilerFlags.cmake b/Source/cmake/WebKitCompilerFlags.cmake
index 4882f3de3d9cb011a666563f0bc0e142a705518f..d3f674bf78792088a60a631c245a1fa86dca4d53 100644
--- a/Source/cmake/WebKitCompilerFlags.cmake
+++ b/Source/cmake/WebKitCompilerFlags.cmake
@@ -122,7 +122,7 @@ macro(WEBKIT_ADD_TARGET_CXX_FLAGS _target)
 endmacro()
 
 
-option(DEVELOPER_MODE_FATAL_WARNINGS "Build with warnings as errors if DEVELOPER_MODE is also enabled" ON)
+option(DEVELOPER_MODE_FATAL_WARNINGS "Build with warnings as errors if DEVELOPER_MODE is also enabled" OFF)
 if (DEVELOPER_MODE AND DEVELOPER_MODE_FATAL_WARNINGS)
     if (MSVC)
         set(FATAL_WARNINGS_FLAG /WX)
diff --git a/Tools/DumpRenderTree/DerivedSources.make b/Tools/DumpRenderTree/DerivedSources.make
index 576835410df6deac60f0158f1d2d1ef1e5f4c78d..9b492cfe5fef8de340a80f2af70a7d68672ef2e4 100644
--- a/Tools/DumpRenderTree/DerivedSources.make
+++ b/Tools/DumpRenderTree/DerivedSources.make
@@ -73,8 +73,8 @@ $(IDL_FILE_NAMES_LIST) : $(UICONTEXT_INTERFACES:%=%.idl)
 JS%.h JS%.cpp : %.idl $(SCRIPTS) $(IDL_ATTRIBUTES_FILE) $(IDL_FILE_NAMES_LIST) $(FEATURE_AND_PLATFORM_DEFINE_DEPENDENCIES)
 	@echo Generating bindings for $*...
 	$(PERL) -I $(WebCoreScripts) -I $(UISCRIPTCONTEXT_DIR) -I $(DumpRenderTree)/Bindings $(WebCoreScripts)/generate-bindings.pl --defines "$(FEATURE_AND_PLATFORM_DEFINES)" --idlFileNamesList $(IDL_FILE_NAMES_LIST) --outputDir . --generator DumpRenderTree --idlAttributesFile $(IDL_ATTRIBUTES_FILE) $<
-#
 
+#
 
 WEB_PREFERENCES_GENERATED_FILES = \
     TestOptionsGeneratedWebKitLegacyKeyMapping.cpp \
diff --git a/Tools/MiniBrowser/gtk/BrowserTab.c b/Tools/MiniBrowser/gtk/BrowserTab.c
index 6d48c378699e87f55bbd2550d4971a295b831a24..efb0d8e1e0f7db5d4ce81bc58a97e6c4034ff0b3 100644
--- a/Tools/MiniBrowser/gtk/BrowserTab.c
+++ b/Tools/MiniBrowser/gtk/BrowserTab.c
@@ -117,19 +117,38 @@ static void isLoadingChanged(WebKitWebView *webView, GParamSpec *paramSpec, Brow
     }
 }
 
+static gboolean response_policy_decision_can_show(WebKitResponsePolicyDecision *responseDecision)
+{
+    if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
+        return TRUE;
+    WebKitURIResponse* response = webkit_response_policy_decision_get_response(responseDecision);
+    const guint statusCode = webkit_uri_response_get_status_code(response);
+    if (statusCode == 205 || statusCode == 204)
+        return TRUE;
+    const gchar* mimeType = webkit_uri_response_get_mime_type(response);
+    if (!mimeType || mimeType[0] == '\0')
+        return FALSE;
+    // https://bugs.webkit.org/show_bug.cgi?id=277204 / Ubuntu 24.04 / glib 2.76+ or higher
+    if (g_ascii_strcasecmp(mimeType, "application/x-zerosize") == 0)
+        return TRUE;
+    return FALSE;
+}
+
 static gboolean decidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, BrowserTab *tab)
 {
     if (decisionType != WEBKIT_POLICY_DECISION_TYPE_RESPONSE)
         return FALSE;
 
     WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
-    if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
-        return FALSE;
-
     if (!webkit_response_policy_decision_is_main_frame_main_resource(responseDecision))
         return FALSE;
 
-    webkit_policy_decision_download(decision);
+    if (!response_policy_decision_can_show(responseDecision)) {
+        webkit_policy_decision_download(decision);
+        return TRUE;
+    }
+
+    webkit_policy_decision_use(decision);
     return TRUE;
 }
 
@@ -180,6 +199,11 @@ static void loadChanged(WebKitWebView *webView, WebKitLoadEvent loadEvent, Brows
 #endif
 }
 
+static gboolean loadFailed()
+{
+    return TRUE;
+}
+
 static GtkWidget *createInfoBarQuestionMessage(const char *title, const char *text)
 {
     GtkWidget *dialog = gtk_info_bar_new_with_buttons("No", GTK_RESPONSE_NO, "Yes", GTK_RESPONSE_YES, NULL);
@@ -746,6 +770,7 @@ static void browserTabConstructed(GObject *gObject)
     g_signal_connect(tab->webView, "notify::is-loading", G_CALLBACK(isLoadingChanged), tab);
     g_signal_connect(tab->webView, "decide-policy", G_CALLBACK(decidePolicy), tab);
     g_signal_connect(tab->webView, "load-changed", G_CALLBACK(loadChanged), tab);
+    g_signal_connect(tab->webView, "load-failed", G_CALLBACK(loadFailed), tab);
     g_signal_connect(tab->webView, "load-failed-with-tls-errors", G_CALLBACK(loadFailedWithTLSerrors), tab);
     g_signal_connect(tab->webView, "permission-request", G_CALLBACK(decidePermissionRequest), tab);
     g_signal_connect(tab->webView, "run-color-chooser", G_CALLBACK(runColorChooserCallback), tab);
@@ -798,6 +823,9 @@ static char *getInternalURI(const char *uri)
     if (g_str_has_prefix(uri, "about:") && !g_str_equal(uri, "about:blank"))
         return g_strconcat(BROWSER_ABOUT_SCHEME, uri + strlen ("about"), NULL);
 
+    if (!g_str_has_prefix(uri, "http://") && !g_str_has_prefix(uri, "https://") && !g_str_has_prefix(uri, "file://"))
+        return g_strconcat("http://", uri, NULL);
+
     return g_strdup(uri);
 }
 
diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.c b/Tools/MiniBrowser/gtk/BrowserWindow.c
index d39b809a879babcdbbf4b5f7687204df5ccc43f3..2862876cb515da09db653e71659d64215a636758 100644
--- a/Tools/MiniBrowser/gtk/BrowserWindow.c
+++ b/Tools/MiniBrowser/gtk/BrowserWindow.c
@@ -73,7 +73,7 @@ struct _BrowserWindowClass {
     GtkApplicationWindowClass parent;
 };
 
-static const char *defaultWindowTitle = "WebKitGTK MiniBrowser";
+static const char *defaultWindowTitle = "🎭 Playwright";
 static const gdouble minimumZoomLevel = 0.5;
 static const gdouble maximumZoomLevel = 3;
 static const gdouble defaultZoomLevel = 1;
@@ -157,17 +157,11 @@ static void webViewURIChanged(WebKitWebView *webView, GParamSpec *pspec, Browser
 static void webViewTitleChanged(WebKitWebView *webView, GParamSpec *pspec, BrowserWindow *window)
 {
     const char *title = webkit_web_view_get_title(webView);
+    char *privateTitle = NULL;
     if (!title)
         title = defaultWindowTitle;
-    char *privateTitle = NULL;
-    if (webkit_web_view_is_controlled_by_automation(webView))
-        privateTitle = g_strdup_printf("[Automation] %s", title);
-#if GTK_CHECK_VERSION(3, 98, 0)
-    else if (webkit_network_session_is_ephemeral(webkit_web_view_get_network_session(webView)))
-#else
-    else if (webkit_web_view_is_ephemeral(webView))
-#endif
-        privateTitle = g_strdup_printf("[Private] %s", title);
+    else
+        privateTitle = g_strdup_printf("🎭 Playwright: %s", title);
     gtk_window_set_title(GTK_WINDOW(window), privateTitle ? privateTitle : title);
     g_free(privateTitle);
 }
@@ -524,8 +518,12 @@ static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision
         return FALSE;
 
     WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision));
-    if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED
-        || webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE)
+    if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED)
+        return FALSE;
+
+    guint modifiers = webkit_navigation_action_get_modifiers(navigationAction);
+    if (webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_MIDDLE &&
+        (webkit_navigation_action_get_mouse_button(navigationAction) != GDK_BUTTON_PRIMARY || (modifiers & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == 0))
         return FALSE;
 
     /* Multiple tabs are not allowed in editor mode. */
@@ -1502,6 +1500,28 @@ static gboolean browserWindowDeleteEvent(GtkWidget *widget, GdkEventAny* event)
 }
 #endif
 
+#if GTK_CHECK_VERSION(3, 98, 0)
+static void zero_widget_measure (GtkWidget      *widget,
+                    GtkOrientation  orientation,
+                    int             for_size,
+                    int            *minimum_size,
+                    int            *natural_size,
+                    int            *minimum_baseline,
+                    int            *natural_baseline)
+{
+    *minimum_size = 10;
+    *natural_size = 10;
+    // *minimum_baseline = 10;
+    // *natural_baseline = 10;
+}
+#else
+static void zeroPreferredSize(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
+{
+    *minimumSize = 10;
+    *naturalSize = 10;
+}
+#endif
+
 static void browser_window_class_init(BrowserWindowClass *klass)
 {
     GObjectClass *gobjectClass = G_OBJECT_CLASS(klass);
@@ -1515,6 +1535,19 @@ static void browser_window_class_init(BrowserWindowClass *klass)
     GtkWidgetClass *widgetClass = GTK_WIDGET_CLASS(klass);
     widgetClass->delete_event = browserWindowDeleteEvent;
 #endif
+
+// Playwrigth begin
+// Override preferred (which is minimum :-) size to 0 so that we can
+// emulate arbitrary resolution.
+#if GTK_CHECK_VERSION(3, 98, 0)
+    GtkWidgetClass* browserWidgetClass = GTK_WIDGET_CLASS(klass);
+    browserWidgetClass->measure = zero_widget_measure;
+#else
+    GtkWidgetClass* browserWidgetClass = GTK_WIDGET_CLASS(klass);
+    browserWidgetClass->get_preferred_width = zeroPreferredSize;
+    browserWidgetClass->get_preferred_height = zeroPreferredSize;
+#endif
+// Playwrigth end
 }
 
 /* Public API. */
diff --git a/Tools/MiniBrowser/gtk/BrowserWindow.h b/Tools/MiniBrowser/gtk/BrowserWindow.h
index 1fd07efb828b85b6d8def6c6cd92a0c11debfe1b..da9fac7975d477857ead2adb1d67108d51716d15 100644
--- a/Tools/MiniBrowser/gtk/BrowserWindow.h
+++ b/Tools/MiniBrowser/gtk/BrowserWindow.h
@@ -42,7 +42,7 @@ G_BEGIN_DECLS
 #define BROWSER_IS_WINDOW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), BROWSER_TYPE_WINDOW))
 #define BROWSER_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),  BROWSER_TYPE_WINDOW))
 #define BROWSER_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj),  BROWSER_TYPE_WINDOW, BrowserWindowClass))
-#define BROWSER_DEFAULT_URL            "http://www.webkitgtk.org/"
+#define BROWSER_DEFAULT_URL            "about:blank"
 #define BROWSER_ABOUT_SCHEME           "minibrowser-about"
 
 typedef struct _BrowserWindow        BrowserWindow;
diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c
index 8433f5360dc4a5f43b68b67192fb3d9bf5064cf1..9fa8f53e90fe5a32be1c8e7a9daa64047640e9f6 100644
--- a/Tools/MiniBrowser/gtk/main.c
+++ b/Tools/MiniBrowser/gtk/main.c
@@ -75,9 +75,14 @@ static char* timeZone;
 static gboolean enableITP;
 static gboolean exitAfterLoad;
 static gboolean webProcessCrashed;
+static gboolean inspectorPipe;
+static gboolean headless;
+static gboolean noStartupWindow;
+static const char *userDataDir;
 static gboolean printVersion;
 static char *configFile;
 static GSettings *interfaceSettings;
+static GtkApplication *browserApplication = NULL;
 
 #if !GTK_CHECK_VERSION(3, 98, 0)
 static gboolean enableSandbox;
@@ -182,6 +187,10 @@ static const GOptionEntry commandLineOptions[] =
     { "time-zone", 't', 0, G_OPTION_ARG_STRING, &timeZone, "Set time zone", "TIMEZONE" },
     { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WebKitGTK version", NULL },
     { "config", 'C', 0, G_OPTION_ARG_FILENAME, &configFile, "Path to a configuration file", "PATH" },
+    { "inspector-pipe", 0, 0, G_OPTION_ARG_NONE, &inspectorPipe, "Open pipe connection to the remote inspector", NULL },
+    { "user-data-dir", 0, 0, G_OPTION_ARG_STRING, &userDataDir, "Default profile persistence folder location", NULL },
+    { "headless", 0, 0, G_OPTION_ARG_NONE, &headless, "Noop headless operation", NULL },
+    { "no-startup-window", 0, 0, G_OPTION_ARG_NONE, &noStartupWindow, "Do not open default page", NULL },
     { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" },
     { 0, 0, 0, 0, 0, 0, 0 }
 };
@@ -739,6 +748,70 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul
     g_main_loop_quit(data->mainLoop);
 }
 
+static WebKitSettings* createPlaywrightSettings() {
+    WebKitSettings* webkitSettings = webkit_settings_new();
+#if GTK_CHECK_VERSION(3, 98, 0)
+    // FIXME(Playwright): in GTK4, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS is the default, but the page content is just black in that case.
+    webkit_settings_set_hardware_acceleration_policy(webkitSettings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER);
+#else
+    // Playwright: revert to the default state before https://github.com/WebKit/WebKit/commit/a73a25b9ea9229987c8fa7b2e092e6324cb17913
+    webkit_settings_set_hardware_acceleration_policy(webkitSettings, WEBKIT_HARDWARE_ACCELERATION_POLICY_NEVER);
+    webkit_settings_set_hardware_acceleration_policy(webkitSettings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND);
+#endif
+    return webkitSettings;
+}
+
+static WebKitWebContext *persistentWebContext = NULL;
+
+static WebKitWebView *createNewPage(WebKitBrowserInspector *browser_inspector, WebKitWebContext *context)
+{
+    if (context == NULL)
+        context = persistentWebContext;
+
+    WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+        "web-context", context,
+        "settings", createPlaywrightSettings(),
+#if GTK_CHECK_VERSION(3, 98, 0)
+        "network-session", webkit_web_context_get_network_session_for_automation(context),
+#else
+        "is-ephemeral", webkit_web_context_is_ephemeral(context),
+#endif
+        "is-controlled-by-automation", TRUE,
+        NULL));
+#if GTK_CHECK_VERSION(3, 98, 0)
+    GtkWidget *newWindow = browser_window_new(NULL, context, webkit_web_context_get_network_session_for_automation(context));
+#else
+    GtkWidget *newWindow = browser_window_new(NULL, context);
+#endif
+    gtk_window_set_application(GTK_WINDOW(newWindow), browserApplication);
+    browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView);
+    gtk_widget_grab_focus(GTK_WIDGET(newWebView));
+    gtk_widget_show(GTK_WIDGET(newWindow));
+    webkit_web_view_load_uri(newWebView, "about:blank");
+    return newWebView;
+}
+
+static void quitBroserApplication(WebKitBrowserInspector* browser_inspector)
+{
+    g_application_release(G_APPLICATION(browserApplication));
+}
+
+static void keepApplicationAliveUntilQuit(GApplication *application)
+{
+    // Reference the application, it will be released in quitBroserApplication.
+    g_application_hold(application);
+    WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default();
+    g_signal_connect(browserInspector, "quit-application", G_CALLBACK(quitBroserApplication), NULL);
+}
+
+static void configureBrowserInspectorPipe()
+{
+    WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default();
+    g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL);
+ 
+    webkit_browser_inspector_initialize_pipe(proxy, ignoreHosts);
+}
+
 static void startup(GApplication *application)
 {
     const char *actionAccels[] = {
@@ -797,17 +870,30 @@ static void setupDarkMode(GtkSettings *settings)
 
 static void activate(GApplication *application, WebKitSettings *webkitSettings)
 {
+    if (inspectorPipe)
+        configureBrowserInspectorPipe();
+
+    if (noStartupWindow) {
+        keepApplicationAliveUntilQuit(application);
+        g_clear_object(&webkitSettings);
+        return;
+    }
 #if GTK_CHECK_VERSION(3, 98, 0)
     WebKitWebContext *webContext = g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "time-zone-override", timeZone, NULL);
     webkit_web_context_set_automation_allowed(webContext, automationMode);
     g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), application);
 
     WebKitNetworkSession *networkSession;
-    if (automationMode)
-        networkSession = g_object_ref(webkit_web_context_get_network_session_for_automation(webContext));
-    else if (privateMode)
+    if (userDataDir) {
+        char *dataDirectory = g_build_filename(userDataDir, "data", NULL);
+        char *cacheDirectory = g_build_filename(userDataDir, "cache", NULL);
+        networkSession = webkit_network_session_new(dataDirectory, cacheDirectory);
+        g_free(dataDirectory);
+        g_free(cacheDirectory);
+        cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL);
+    } else if (inspectorPipe || privateMode || automationMode) {
         networkSession = webkit_network_session_new_ephemeral();
-    else {
+    } else {
         char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL);
         char *cacheDirectory = g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL);
         networkSession = webkit_network_session_new(dataDirectory, cacheDirectory);
@@ -815,6 +901,8 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings)
         g_free(cacheDirectory);
     }
 
+    webkit_web_context_set_network_session_for_automation(webContext, networkSession);
+
     webkit_network_session_set_itp_enabled(networkSession, enableITP);
 
     if (!automationMode) {
@@ -849,9 +937,12 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings)
     }
 #else
     WebKitWebsiteDataManager *manager;
-    if (privateMode || automationMode)
+    if (userDataDir) {
+        manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL);
+        cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL);
+    } else if (inspectorPipe || privateMode || automationMode) {
         manager = webkit_website_data_manager_new_ephemeral();
-    else {
+    } else {
         char *dataDirectory = g_build_filename(g_get_user_data_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL);
         char *cacheDirectory = g_build_filename(g_get_user_cache_dir(), "webkitgtk-" WEBKITGTK_API_VERSION, "MiniBrowser", NULL);
         manager = webkit_website_data_manager_new("base-data-directory", dataDirectory, "base-cache-directory", cacheDirectory, NULL);
@@ -901,6 +992,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings)
     // Enable the favicon database.
     webkit_web_context_set_favicon_database_directory(webContext, NULL);
 #endif
+    persistentWebContext = webContext;
 
     webkit_web_context_register_uri_scheme(webContext, BROWSER_ABOUT_SCHEME, (WebKitURISchemeRequestCallback)aboutURISchemeRequestCallback, NULL, NULL);
 
@@ -965,9 +1057,7 @@ static void activate(GApplication *application, WebKitSettings *webkitSettings)
                 if (exitAfterLoad)
                     exitAfterWebViewLoadFinishes(webView, application);
             }
-            gchar *url = argumentToURL(uriArguments[i]);
-            webkit_web_view_load_uri(webView, url);
-            g_free(url);
+            webkit_web_view_load_uri(webView, uriArguments[i]);
         }
     } else {
         WebKitWebView *webView = createBrowserTab(mainWindow, webkitSettings, userContentManager, defaultWebsitePolicies);
@@ -1017,7 +1107,7 @@ int main(int argc, char *argv[])
     g_option_context_add_group(context, gst_init_get_option_group());
 #endif
 
-    WebKitSettings *webkitSettings = webkit_settings_new();
+    WebKitSettings *webkitSettings = createPlaywrightSettings();
     webkit_settings_set_enable_developer_extras(webkitSettings, TRUE);
     webkit_settings_set_enable_webgl(webkitSettings, TRUE);
     webkit_settings_set_enable_media_stream(webkitSettings, TRUE);
@@ -1069,9 +1159,11 @@ int main(int argc, char *argv[])
     }
 
     GtkApplication *application = gtk_application_new("org.webkitgtk.MiniBrowser", G_APPLICATION_NON_UNIQUE);
+    browserApplication = application;
     g_signal_connect(application, "startup", G_CALLBACK(startup), NULL);
     g_signal_connect(application, "activate", G_CALLBACK(activate), webkitSettings);
     g_application_run(G_APPLICATION(application), 0, NULL);
+    browserApplication = NULL;
     g_object_unref(application);
 
     g_clear_object(&interfaceSettings);
diff --git a/Tools/MiniBrowser/wpe/main.cpp b/Tools/MiniBrowser/wpe/main.cpp
index f5403031c914d7fedeb4649c4891beb7d681007e..eb1fe97ebb4e55eb1d4443e5f66566471ad9733f 100644
--- a/Tools/MiniBrowser/wpe/main.cpp
+++ b/Tools/MiniBrowser/wpe/main.cpp
@@ -49,6 +49,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;
@@ -127,6 +130,9 @@ static const GOptionEntry commandLineOptions[] =
 #endif
     { "size", 's', 0, G_OPTION_ARG_CALLBACK, reinterpret_cast<gpointer>(parseWindowSize), "Specify the window size to use, e.g. --size=\"800x600\"", nullptr },
     { "version", 'v', 0, G_OPTION_ARG_NONE, &printVersion, "Print the WPE version", nullptr },
+    { "inspector-pipe", 'v', 0, G_OPTION_ARG_NONE, &inspectorPipe, "Expose remote debugging protocol over pipe", nullptr },
+    { "user-data-dir", 0, 0, G_OPTION_ARG_STRING, &userDataDir, "Default profile persistence folder location", "FILE" },
+    { "no-startup-window", 0, 0, G_OPTION_ARG_NONE, &noStartupWindow, "Do not open default page", nullptr },
     { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, nullptr, "[URL]" },
     { nullptr, 0, 0, G_OPTION_ARG_NONE, nullptr, nullptr, nullptr }
 };
@@ -285,15 +291,38 @@ static void filterSavedCallback(WebKitUserContentFilterStore *store, GAsyncResul
     g_main_loop_quit(data->mainLoop);
 }
 
+static gboolean webViewLoadFailed()
+{
+    return TRUE;
+}
+
 static void webViewClose(WebKitWebView* webView, gpointer user_data)
 {
     // Hash table key delete func takes care of unref'ing the view
     g_hash_table_remove(openViews, webView);
-    if (!g_hash_table_size(openViews))
+    if (!g_hash_table_size(openViews) && user_data)
         g_application_quit(G_APPLICATION(user_data));
 }
 
-static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data)
+static gboolean scriptDialog(WebKitWebView*, WebKitScriptDialog* dialog, gpointer)
+{
+    if (inspectorPipe)
+        webkit_script_dialog_ref(dialog);
+    return TRUE;
+}
+
+static gboolean scriptDialogHandled(WebKitWebView*, WebKitScriptDialog* dialog, gpointer)
+{
+    if (inspectorPipe)
+        webkit_script_dialog_unref(dialog);
+    return TRUE;
+}
+
+static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, gpointer);
+
+static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data);
+
+static WebKitWebView* createWebViewImpl(WebKitWebView* webView, WebKitWebContext *webContext, gpointer user_data)
 {
     auto backend = createViewBackend(defaultWindowWidthLegacyAPI, defaultWindowHeightLegacyAPI);
     WebKitWebViewBackend* viewBackend = nullptr;
@@ -308,12 +337,27 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi
             }, backend.release());
     }
 
-    auto* newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
-        "backend", viewBackend,
-        "related-view", webView,
-        "settings", webkit_web_view_get_settings(webView),
-        "user-content-manager", webkit_web_view_get_user_content_manager(webView),
-        nullptr));
+// Playwright begin
+    if (headlessMode) {
+        webkit_web_view_backend_set_screenshot_callback(viewBackend,
+            [](gpointer data) {
+                return static_cast<WPEToolingBackends::HeadlessViewBackend*>(data)->snapshot();
+            });
+    }
+// Playwright end
+    WebKitWebView* newWebView;
+    if (webView) {
+        newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+            "backend", viewBackend,
+            "related-view", webView,
+            nullptr));
+    } else {
+        newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+            "backend", viewBackend,
+            "web-context", webContext,
+            "is-controlled-by-automation", TRUE,
+            nullptr));
+    }
 
 #if ENABLE_WPE_PLATFORM
     if (auto* wpeView = webkit_web_view_get_wpe_view(newWebView)) {
@@ -328,6 +372,10 @@ static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationActi
 
     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, "decide-policy", G_CALLBACK(webViewDecidePolicy), nullptr);
     return newWebView;
 }
 
@@ -415,13 +463,105 @@ void loadConfigFile(WPESettings* settings)
 }
 #endif
 
+static WebKitWebView* createWebView(WebKitWebView* webView, WebKitNavigationAction*, gpointer user_data)
+{
+    return createWebViewImpl(webView, nullptr, user_data);
+}
+
+inline bool response_policy_decision_can_show(WebKitResponsePolicyDecision* responseDecision)
+{
+    if (webkit_response_policy_decision_is_mime_type_supported(responseDecision))
+        return true;
+    auto response = webkit_response_policy_decision_get_response(responseDecision);
+    const auto statusCode = webkit_uri_response_get_status_code(response);
+    if (statusCode == 205 || statusCode == 204)
+        return true;
+    const gchar* mimeType = webkit_uri_response_get_mime_type(response);
+    if (!mimeType || mimeType[0] == '\0')
+        return false;
+    // https://bugs.webkit.org/show_bug.cgi?id=277204 / Ubuntu 24.04 / glib 2.76+ or higher
+    if (g_ascii_strcasecmp(mimeType, "application/x-zerosize") == 0)
+        return true;
+    return false;
+}
+
+static gboolean webViewDecidePolicy(WebKitWebView *webView, WebKitPolicyDecision *decision, WebKitPolicyDecisionType decisionType, gpointer user_data)
+{
+    if (decisionType == WEBKIT_POLICY_DECISION_TYPE_RESPONSE) {
+        WebKitResponsePolicyDecision *responseDecision = WEBKIT_RESPONSE_POLICY_DECISION(decision);
+        if (!webkit_response_policy_decision_is_main_frame_main_resource(responseDecision))
+            return FALSE;
+
+        if (!response_policy_decision_can_show(responseDecision)) {
+            webkit_policy_decision_download(decision);
+            return TRUE;
+        }
+
+        webkit_policy_decision_use(decision);
+        return TRUE;
+    }
+
+    if (decisionType != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
+        return FALSE;
+
+    WebKitNavigationAction *navigationAction = webkit_navigation_policy_decision_get_navigation_action(WEBKIT_NAVIGATION_POLICY_DECISION(decision));
+    if (webkit_navigation_action_get_navigation_type(navigationAction) != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED)
+        return FALSE;
+
+    guint modifiers = webkit_navigation_action_get_modifiers(navigationAction);
+    if (webkit_navigation_action_get_mouse_button(navigationAction) != 2 /* GDK_BUTTON_MIDDLE */ &&
+        (webkit_navigation_action_get_mouse_button(navigationAction) != 1 /* GDK_BUTTON_PRIMARY */ || (modifiers & (wpe_input_keyboard_modifier_control | wpe_input_keyboard_modifier_shift)) == 0))
+        return FALSE;
+
+    /* Open a new tab if link clicked with the middle button, shift+click or ctrl+click. */
+    WebKitWebView* newWebView = createWebViewImpl(nullptr, webkit_web_view_get_context(webView), user_data);
+    webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction));
+
+    webkit_policy_decision_ignore(decision);
+    return TRUE;
+}
+
+static WebKitWebContext *persistentWebContext = NULL;
+
+static WebKitWebView* createNewPage(WebKitBrowserInspector*, WebKitWebContext *webContext)
+{
+    if (!webContext)
+        webContext = persistentWebContext;
+    WebKitWebView* webView = createWebViewImpl(nullptr, webContext, nullptr);
+    webkit_web_view_load_uri(webView, "about:blank");
+    return webView;
+}
+
+static void quitBroserApplication(WebKitBrowserInspector*, gpointer data)
+{
+    GApplication* application = static_cast<GApplication*>(data);
+    g_application_quit(application);
+}
+
+static void configureBrowserInspector(GApplication* application)
+{
+    WebKitBrowserInspector* browserInspector = webkit_browser_inspector_get_default();
+    g_signal_connect(browserInspector, "create-new-page", G_CALLBACK(createNewPage), NULL);
+    g_signal_connect(browserInspector, "quit-application", G_CALLBACK(quitBroserApplication), application);
+    webkit_browser_inspector_initialize_pipe(proxy, ignoreHosts);
+}
+
 static void activate(GApplication* application, WPEToolingBackends::ViewBackend* backend)
 {
     g_application_hold(application);
+    if (noStartupWindow)
+        return;
 #if ENABLE_2022_GLIB_API
     WebKitNetworkSession* networkSession = nullptr;
     if (!automationMode) {
-        networkSession = privateMode ? webkit_network_session_new_ephemeral() : webkit_network_session_new(nullptr, nullptr);
+        if (userDataDir) {
+            networkSession = webkit_network_session_new(userDataDir, userDataDir);
+            cookiesFile = g_build_filename(userDataDir, "cookies.txt", nullptr);
+        } else if (inspectorPipe || privateMode || automationMode) {
+            networkSession = webkit_network_session_new_ephemeral();
+        } else {
+            networkSession = webkit_network_session_new(nullptr, nullptr);
+        }        
         webkit_network_session_set_itp_enabled(networkSession, enableITP);
 
         if (proxy) {
@@ -448,10 +588,18 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend*
             webkit_cookie_manager_set_persistent_storage(cookieManager, cookiesFile, storageType);
         }
     }
-
     auto* webContext = WEBKIT_WEB_CONTEXT(g_object_new(WEBKIT_TYPE_WEB_CONTEXT, "time-zone-override", timeZone, nullptr));
+    webkit_web_context_set_network_session_for_automation(webContext, networkSession);
 #else
-    auto* manager = (privateMode || automationMode) ? webkit_website_data_manager_new_ephemeral() : webkit_website_data_manager_new(nullptr);
+    WebKitWebsiteDataManager *manager;
+    if (userDataDir) {
+        manager = webkit_website_data_manager_new("base-data-directory", userDataDir, "base-cache-directory", userDataDir, NULL);
+        cookiesFile = g_build_filename(userDataDir, "cookies.txt", NULL);
+    } else if (inspectorPipe || privateMode || automationMode) {
+        manager = webkit_website_data_manager_new_ephemeral();
+    } else {
+        manager = webkit_website_data_manager_new(NULL);
+    }
     webkit_website_data_manager_set_itp_enabled(manager, enableITP);
 
     if (proxy) {
@@ -482,6 +630,7 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend*
     }
 #endif
 
+    persistentWebContext = webContext;
     WebKitUserContentManager* userContentManager = nullptr;
     if (contentFilter) {
         GFile* contentFilterFile = g_file_new_for_commandline_arg(contentFilter);
@@ -560,6 +709,15 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend*
         "autoplay", WEBKIT_AUTOPLAY_ALLOW,
         nullptr);
 
+// Playwright begin
+    if (headlessMode) {
+        webkit_web_view_backend_set_screenshot_callback(viewBackend,
+            [](gpointer data) {
+                return static_cast<WPEToolingBackends::HeadlessViewBackend*>(data)->snapshot();
+            });
+    }
+// Playwright end
+
     auto* webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
         "backend", viewBackend,
         "web-context", webContext,
@@ -606,8 +764,6 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend*
     }
 #endif
 
-    openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr);
-
     g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), webView);
     g_signal_connect(webView, "permission-request", G_CALLBACK(decidePermissionRequest), nullptr);
     g_signal_connect(webView, "create", G_CALLBACK(createWebView), application);
@@ -619,16 +775,11 @@ static void activate(GApplication* application, WPEToolingBackends::ViewBackend*
         webkit_web_view_set_background_color(webView, &color);
 
     if (uriArguments) {
-        const char* uri = uriArguments[0];
-        if (g_str_equal(uri, "about:gpu"))
-            uri = "webkit://gpu";
-
-        GFile* file = g_file_new_for_commandline_arg(uri);
-        char* url = g_file_get_uri(file);
-        g_object_unref(file);
-        webkit_web_view_load_uri(webView, url);
-        g_free(url);
-    } else if (!automationMode)
+        // Playwright: avoid weird url transformation like http://trac.webkit.org/r240840
+        webkit_web_view_load_uri(webView, uriArguments[0]);
+    } else if (automationMode || inspectorPipe)
+        webkit_web_view_load_uri(webView, "about:blank");
+    else
         webkit_web_view_load_uri(webView, "https://wpewebkit.org");
 
     g_object_unref(webContext);
@@ -725,8 +876,14 @@ int main(int argc, char *argv[])
         }
     }
 
+    openViews = g_hash_table_new_full(nullptr, nullptr, g_object_unref, nullptr);
+
     GApplication* application = g_application_new("org.wpewebkit.MiniBrowser", G_APPLICATION_NON_UNIQUE);
     g_signal_connect(application, "activate", G_CALLBACK(activate), backend.release());
+
+    if (inspectorPipe)
+        configureBrowserInspector(application);
+
     g_application_run(application, 0, nullptr);
     g_object_unref(application);
 
diff --git a/Tools/PlatformWin.cmake b/Tools/PlatformWin.cmake
index 1067b31bc989748dfcc5502209d36d001b9b239e..7629263fb8bc93dca6dfc01c75eed8d2921fce1f 100644
--- a/Tools/PlatformWin.cmake
+++ b/Tools/PlatformWin.cmake
@@ -1,3 +1,7 @@
 if (ENABLE_MINIBROWSER)
     add_subdirectory(MiniBrowser/win)
 endif ()
+
+if (ENABLE_WEBKIT)
+    add_subdirectory(Playwright/win)
+endif ()
diff --git a/Tools/Scripts/build-webkit b/Tools/Scripts/build-webkit
index 470dcf1f4440f3db350fc416150a2e792a2777c7..31cbc0d22e63d054cf6edcc220a1c6b407cc1f24 100755
--- a/Tools/Scripts/build-webkit
+++ b/Tools/Scripts/build-webkit
@@ -273,7 +273,7 @@ if (isAppleCocoaWebKit()) {
         push @projects, ("Source/WebKit");
 
         if (!isEmbeddedWebKit()) {
-            push @projects, ("Tools/MiniBrowser");
+            push @projects, ("Tools/Playwright");
 
             # WebInspectorUI must come after JavaScriptCore and WebCore but before WebKit and WebKit2
             my $webKitIndex = first { $projects[$_] eq "Source/WebKitLegacy" } 0..$#projects;
diff --git a/Tools/WebKitTestRunner/CMakeLists.txt b/Tools/WebKitTestRunner/CMakeLists.txt
index 9e53f459e444b9c10fc5248f0e8059df6c1e0041..c17c875a7dd3ca05c4489578ab32378bca45a7c9 100644
--- a/Tools/WebKitTestRunner/CMakeLists.txt
+++ b/Tools/WebKitTestRunner/CMakeLists.txt
@@ -95,6 +95,10 @@ set(TestRunnerInjectedBundle_PRIVATE_LIBRARIES
 )
 set(TestRunnerInjectedBundle_FRAMEWORKS ${WebKitTestRunner_FRAMEWORKS})
 
+if (NOT USE_SYSTEM_MALLOC)
+    list(APPEND WebKitTestRunnerInjectedBundle_LIBRARIES bmalloc)
+endif ()
+
 set(TestRunnerInjectedBundle_IDL_FILES
     "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityController.idl"
     "${WebKitTestRunner_DIR}/InjectedBundle/Bindings/AccessibilityTextMarker.idl"
diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp
index 1e020026255e1904c5b80d5232de7c1899f894bc..3a74de8ff4f615b86755e18c3414b24f185c17c8 100644
--- a/Tools/WebKitTestRunner/TestController.cpp
+++ b/Tools/WebKitTestRunner/TestController.cpp
@@ -984,6 +984,7 @@ void TestController::createWebViewWithOptions(const TestOptions& options)
         0, // requestStorageAccessConfirm
         shouldAllowDeviceOrientationAndMotionAccess,
         runWebAuthenticationPanel,
+        0, // handleJavaScriptDialog
         0,
         decidePolicyForMediaKeySystemPermissionRequest,
         queryPermission,
diff --git a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm
index c1381b06b378a5121be926b1dfda3e5509bcd051..773e5882b6f2269201ca49433d0b69866493118d 100644
--- a/Tools/WebKitTestRunner/mac/EventSenderProxy.mm
+++ b/Tools/WebKitTestRunner/mac/EventSenderProxy.mm
@@ -961,4 +961,51 @@ void EventSenderProxy::waitForPendingMouseEvents()
     }
 }
 
+#if ENABLE(TOUCH_EVENTS)
+void EventSenderProxy::addTouchPoint(int, int)
+{
+}
+
+void EventSenderProxy::updateTouchPoint(int, int, int)
+{
+}
+
+void EventSenderProxy::touchStart()
+{
+}
+
+void EventSenderProxy::touchMove()
+{
+}
+
+void EventSenderProxy::touchEnd()
+{
+}
+
+void EventSenderProxy::touchCancel()
+{
+}
+
+void EventSenderProxy::clearTouchPoints()
+{
+}
+
+void EventSenderProxy::releaseTouchPoint(int)
+{
+}
+
+void EventSenderProxy::cancelTouchPoint(int)
+{
+}
+
+void EventSenderProxy::setTouchPointRadius(int, int)
+{
+}
+
+void EventSenderProxy::setTouchModifier(WKEventModifiers, bool)
+{
+}
+#endif // ENABLE(TOUCH_EVENTS)
+
+
 } // namespace WTR
diff --git a/Tools/jhbuild/jhbuild-minimal.modules b/Tools/jhbuild/jhbuild-minimal.modules
index 3a0b7425900b14ce2aa0d48aa914cd69bff1f332..918dc2a3ac6716708ee372278f74877324abee3d 100644
--- a/Tools/jhbuild/jhbuild-minimal.modules
+++ b/Tools/jhbuild/jhbuild-minimal.modules
@@ -186,7 +186,6 @@
   </meson>
 
   <meson id="libsoup" mesonargs="-Dgssapi=disabled -Dvapi=disabled -Dntlm=disabled -Dsysprof=disabled -Dautobahn=disabled -Dpkcs11_tests=disabled">
-    <pkg-config>libsoup-3.0.pc</pkg-config>
     <dependencies>
       <dep package="glib"/>
       <dep package="glib-networking"/>
diff --git a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp
index df22308266c6f69d24a60905f8d05e4e80f21b9b..2d0838070dc10793418cbb648b095a5ffa76f1b8 100644
--- a/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp
+++ b/Tools/wpe/backends/fdo/HeadlessViewBackendFdo.cpp
@@ -210,32 +210,30 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer)
             return;
     }
 
+uint32_t width = std::max(0, wl_shm_buffer_get_width(shmBuffer));
+uint32_t height = std::max(0, wl_shm_buffer_get_height(shmBuffer));
+if (!width || !height) {
+    fprintf(stderr, "HeadlessViewBackend::updateSnapshot shmBuffer is empty: %ux%u\n", width, height);
+    return;
+}
+
 #if defined(USE_CAIRO) && USE_CAIRO
-    uint32_t bufferStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_width);
+    uint32_t bufferStride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
 #elif defined(USE_SKIA) && USE_SKIA
-    auto info = SkImageInfo::MakeN32Premul(m_width, m_height, SkColorSpace::MakeSRGB());
+    auto info = SkImageInfo::MakeN32Premul(width, height, SkColorSpace::MakeSRGB());
     uint32_t bufferStride = info.minRowBytes();
 #endif
-    uint8_t* buffer = new uint8_t[bufferStride * m_height];
-    memset(buffer, 0, bufferStride * m_height);
-
+    uint32_t stride = std::max(0, wl_shm_buffer_get_stride(shmBuffer));
+    if (bufferStride != stride) {
+        fprintf(stderr, "bufferStride != stride: %u != %u\n", bufferStride, stride);
+        return;
+    }
+    uint8_t* buffer = new uint8_t[bufferStride * height];
     {
-        uint32_t width = std::min<uint32_t>(m_width, std::max(0, wl_shm_buffer_get_width(shmBuffer)));
-        uint32_t height = std::min<uint32_t>(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<uint8_t*>(wl_shm_buffer_get_data(shmBuffer));
 
-        for (uint32_t y = 0; y < height; ++y) {
-            for (uint32_t x = 0; x < width; ++x) {
-                buffer[bufferStride * y + 4 * x + 0] = data[stride * y + 4 * x + 0];
-                buffer[bufferStride * y + 4 * x + 1] = data[stride * y + 4 * x + 1];
-                buffer[bufferStride * y + 4 * x + 2] = data[stride * y + 4 * x + 2];
-                buffer[bufferStride * y + 4 * x + 3] = data[stride * y + 4 * x + 3];
-            }
-        }
-
+        memcpy(buffer, data, bufferStride * height);
         wl_shm_buffer_end_access(shmBuffer);
     }
 
@@ -244,7 +242,7 @@ void HeadlessViewBackend::updateSnapshot(PlatformBuffer exportedBuffer)
         cairo_surface_destroy(m_snapshot);
 
     m_snapshot = cairo_image_surface_create_for_data(buffer, CAIRO_FORMAT_ARGB32,
-        m_width, m_height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, m_width));
+        width, height, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
 
     static cairo_user_data_key_t bufferKey;
     cairo_surface_set_user_data(m_snapshot, &bufferKey, buffer,
diff --git a/WebKit.xcworkspace/contents.xcworkspacedata b/WebKit.xcworkspace/contents.xcworkspacedata
index a0f02e61be7e667c6ba164ca578109af36ac28d9..8f5af2e82c167ba6798fb7fde24a9f641f6554a5 100644
--- a/WebKit.xcworkspace/contents.xcworkspacedata
+++ b/WebKit.xcworkspace/contents.xcworkspacedata
@@ -4,6 +4,9 @@
    <FileRef
       location = "group:Configurations">
    </FileRef>
+   <FileRef
+      location = "group:Tools/Playwright/Playwright.xcodeproj">
+   </FileRef>
    <FileRef
       location = "group:Source/bmalloc/bmalloc.xcodeproj">
    </FileRef>
diff --git a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme
index ded307890926eaf0ca169aaef39ea08bd982a47a..2db0c0abdda702fdff9314ba341b63c5d09289bc 100644
--- a/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme	
+++ b/WebKit.xcworkspace/xcshareddata/xcschemes/Everything up to WebKit + Tools.xcscheme	
@@ -188,6 +188,20 @@
                ReferencedContainer = "container:Tools/MobileMiniBrowser/MobileMiniBrowser.xcodeproj">
             </BuildableReference>
          </BuildActionEntry>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "8D1107260486CEB800E47091"
+               BuildableName = "Playwright.app"
+               BlueprintName = "Playwright"
+               ReferencedContainer = "container:Tools/Playwright/Playwright.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
          <BuildActionEntry
             buildForTesting = "YES"
             buildForRunning = "YES"
