Title: [230764] trunk
Revision
230764
Author
[email protected]
Date
2018-04-18 09:50:36 -0700 (Wed, 18 Apr 2018)

Log Message

Add support for converting a local window to a remote window
https://bugs.webkit.org/show_bug.cgi?id=184515
<rdar://problem/39011318>

Reviewed by Ryosuke Niwa.

Source/WebCore:

Add initial support for process-swapping when navigating cross-origin as a result
of a window.open(). The window object returned by window.open() is initially same
origin and is for about:blank. The navigation cross-origin then happens and the
JS wrappers for the window then point to a cross-origin window which is remote (i.e.
hosted in another WebProcess).

The RemoteDOMWindow exposed to JS looks like a regular cross-origin Window with a few
exceptions due to our incomplete implementation (e.g. w.location returns null) and
most of its API is currently not functional. The RemoteDOMWindow API will be implemented
in a follow-up by relying on IPC.

Test: http/tests/navigation/process-swap-window-open.html

* bindings/js/JSDOMGlobalObject.cpp:
(WebCore::JSDOMGlobalObject::scriptExecutionContext const):
* bindings/js/JSDOMPromiseDeferred.h:
* bindings/js/JSDOMWindowProperties.cpp:
(WebCore::JSDOMWindowProperties::getOwnPropertySlot):
* bindings/js/JSDOMWindowProxy.cpp:
(WebCore::JSDOMWindowProxy::finishCreation):
(WebCore::JSDOMWindowProxy::create):
* bindings/js/JSDOMWindowProxy.h:
* bindings/js/JSDOMWrapper.cpp:
(WebCore::JSDOMObject::JSDOMObject):
* bindings/js/JSDOMWrapper.h:
* bindings/js/WindowProxyController.cpp:
(WebCore::WindowProxyController::createWindowProxy):
(WebCore::WindowProxyController::setDOMWindowForWindowProxy):
* bridge/objc/WebScriptObject.mm:
(-[WebScriptObject _isSafeScript]):
Teach more of our bindings code about RemoteDOMWindows.

* dom/Document.cpp:
(WebCore::Document::createDOMWindow):
* loader/FrameLoaderClient.h:
Add FrameLoaderClient function to notify the client when a DOMWindow is constructed in
the frame. This is needed for WebKit2 to link the old window to its new representation
in the new WebProcess.

Source/WebKit:

Add initial support for process-swapping when navigating cross-origin as a result
of a window.open(). The window object returned by window.open() is initially same
origin and is for about:blank. The navigation cross-origin then happens and the
JS wrappers for the window then point to a cross-origin window which is remote (i.e.
hosted in another WebProcess).

The RemoteDOMWindow exposed to JS looks like a regular cross-origin Window with a few
exceptions due to our incomplete implementation (e.g. w.location returns null) and
most of its API is currently not functional. The RemoteDOMWindow API will be implemented
in a follow-up by relying on IPC.

* UIProcess/API/APIProcessPoolConfiguration.cpp:
(API::ProcessPoolConfiguration::copy):
* UIProcess/API/APIProcessPoolConfiguration.h:
* UIProcess/API/C/WKContextConfigurationRef.cpp:
(WKContextConfigurationProcessSwapsOnWindowOpenWithOpener):
(WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener):
* UIProcess/API/C/WKContextConfigurationRef.h:
* UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
* UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
(-[_WKProcessPoolConfiguration setProcessSwapsOnWindowOpenWithOpener:]):
(-[_WKProcessPoolConfiguration processSwapsOnWindowOpenWithOpener]):
Add ProcessPool configuration flag to turn on processSwap on window.open(), even
if there is an opener.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::continueNavigationInNewProcess):
If the navigation was triggered via window.open(), then set up on handler for when
a DOMWindow is constructed for the main frame in the new process.

(WebKit::WebPageProxy::didCreateWindow):
When a Window is constructed for the main frame in a new process on process swap,
notify the old process that its representation of the window should become remote
and provide it with the Frame / Window identifiers it needs.

* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:

* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigation):
Do process swapping on cross-origin window.open() if the corresponding setting is
enabled.

* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::didCreateWindow):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.h:

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::frameBecameRemote):
This is called when process swapping has happened due to a window.open() navigation
cross-origin, when a Frame / Window has been constructed in the new process. We do
the following:
- Construct a RemoteFrame / RemoteWindow using the provided global identifiers to
  represent the Frame / Window in the new process.
- We transfer the WindowProxies from the old Frame's WindowProxyController to the
  new RemoteFrame's WindowProxyController.
- We update the window proxied by those WindowProxies to be the new RemoteWindow.
- We detach the old Frame as it is now remote and represented by the new RemoteFrame
  object we constructed.
- If the old frame was the main frame (always the case currently), we close the page
  as it is no longer needed. The new RemoteFrame is currently owned by the RemoteWindow
  which is kept alive by its JS wrappers.

* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:

Tools:

* MiniBrowser/mac/AppDelegate.m:
(defaultConfiguration):
* MiniBrowser/mac/SettingsController.h:
* MiniBrowser/mac/SettingsController.m:
(-[SettingsController _populateMenu]):
(-[SettingsController validateMenuItem:]):
(-[SettingsController processSwapOnWindowOpenWithOpenerEnabled]):
(-[SettingsController toggleProcessSwapOnWindowOpenWithOpener:]):
Add menu entry in minibrowser to turn on process swap on cross-origin window.open().

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
Turn on process swap on cross-origin window.open() for corresponding test and update
test to expect that a new WebProcess is created.

* WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
(WTR::InjectedBundlePage::decidePolicyForResponse):
Add null checks for injectedBundle.testRunner(). When we swap process on navigation,
the InjectedBundlePage::decidePolicyForResponse() gets called in the new process.
In this new process, we have constructed a InjectedBundlePage for the page but we
have not initialized the InjectedBundle members such as testRunner.

* WebKitTestRunner/TestController.cpp:
(WTR::TestController::createWebViewWithOptions):
(WTR::updateTestOptionsFromTestHeader):
* WebKitTestRunner/TestOptions.h:
(WTR::TestOptions::hasSameInitializationOptions const):
Add a way for layout tests to turn on process swap on navigation via a test header.

LayoutTests:

Add layout test coverage a cross-origin window.open() to check that the
returned window looks like a regular cross-origin window after being
navigated cross-origin. We are still failing some of the checks because
our implementation is still incomplete. However, it mostly works as
expected.

* TestExpectations:
* http/tests/navigation/process-swap-window-open-expected.txt: Added.
* http/tests/navigation/process-swap-window-open.html: Added.
* platform/wk2/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (230763 => 230764)


--- trunk/LayoutTests/ChangeLog	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/LayoutTests/ChangeLog	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1,3 +1,22 @@
+2018-04-18  Chris Dumez  <[email protected]>
+
+        Add support for converting a local window to a remote window
+        https://bugs.webkit.org/show_bug.cgi?id=184515
+        <rdar://problem/39011318>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add layout test coverage a cross-origin window.open() to check that the
+        returned window looks like a regular cross-origin window after being
+        navigated cross-origin. We are still failing some of the checks because
+        our implementation is still incomplete. However, it mostly works as
+        expected.
+
+        * TestExpectations:
+        * http/tests/navigation/process-swap-window-open-expected.txt: Added.
+        * http/tests/navigation/process-swap-window-open.html: Added.
+        * platform/wk2/TestExpectations:
+
 2018-04-18  Ms2ger  <[email protected]>
 
         Test gardening.

Modified: trunk/LayoutTests/TestExpectations (230763 => 230764)


--- trunk/LayoutTests/TestExpectations	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/LayoutTests/TestExpectations	2018-04-18 16:50:36 UTC (rev 230764)
@@ -109,6 +109,7 @@
 http/tests/loading/resourceLoadStatistics/ [ Skip ]
 http/tests/resourceLoadStatistics/ [ Skip ]
 http/tests/storageAccess/ [ Skip ]
+http/tests/navigation/process-swap-window-open.html [ Skip ]
 
 # Only Mac and iOS have an implementation of UIScriptController::doAsyncTask().
 fast/harness/uiscriptcontroller [ Skip ]

Added: trunk/LayoutTests/http/tests/navigation/process-swap-window-open-expected.txt (0 => 230764)


--- trunk/LayoutTests/http/tests/navigation/process-swap-window-open-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/process-swap-window-open-expected.txt	2018-04-18 16:50:36 UTC (rev 230764)
@@ -0,0 +1,44 @@
+Basic testing for the window returning window.open() becoming remote when navigating cross-origin.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS w.location.href is "about:blank"
+PASS w.name threw exception SecurityError: The operation is insecure..
+FAIL w.location.href should throw a SecurityError. Threw a TypeError.
+PASS w.document threw exception SecurityError: The operation is insecure..
+PASS w.history threw exception SecurityError: The operation is insecure..
+PASS w.locationbar threw exception SecurityError: The operation is insecure..
+PASS w.status threw exception SecurityError: The operation is insecure..
+PASS w.frameElement threw exception SecurityError: The operation is insecure..
+PASS w.navigator threw exception SecurityError: The operation is insecure..
+PASS w.alert threw exception SecurityError: The operation is insecure..
+PASS w.localStorage threw exception SecurityError: The operation is insecure..
+PASS w.sessionStorage threw exception SecurityError: The operation is insecure..
+PASS w.event threw exception SecurityError: The operation is insecure..
+PASS w.window is w
+PASS w.self is w
+PASS w.top is w
+PASS w.parent is w
+PASS w.frames is w
+PASS w.closed is false
+PASS w.length is 0
+FAIL w.opener should be [object Window]. Was null.
+PASS w.close is an instance of Function
+PASS w.focus is an instance of Function
+PASS w.blur is an instance of Function
+PASS w.postMessage is an instance of Function
+PASS w.location did not throw exception.
+FAIL w.location should not be null.
+PASS areArraysEqual(actual_properties, expected_property_names) is true
+PASS Object.getPrototype(w) threw exception TypeError: Object.getPrototype is not a function. (In 'Object.getPrototype(w)', 'Object.getPrototype' is undefined).
+PASS Object.setPrototype(w, {}) threw exception TypeError: Object.setPrototype is not a function. (In 'Object.setPrototype(w, {})', 'Object.setPrototype' is undefined).
+PASS Object.preventExtensions(w) threw exception TypeError: Cannot prevent extensions on this object.
+PASS Object.defineProperty(w, 'foo', {value: 1}) threw exception SecurityError: The operation is insecure..
+PASS delete w.closed threw exception SecurityError: The operation is insecure..
+PASS w.foo = 1 threw exception SecurityError: The operation is insecure..
+PASS successfullyParsed is true
+Some tests failed.
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/http/tests/navigation/process-swap-window-open.html (0 => 230764)


--- trunk/LayoutTests/http/tests/navigation/process-swap-window-open.html	                        (rev 0)
+++ trunk/LayoutTests/http/tests/navigation/process-swap-window-open.html	2018-04-18 16:50:36 UTC (rev 230764)
@@ -0,0 +1,71 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableProcessSwapOnNavigation=true ] -->
+<html>
+<body>
+<script src=""
+<script>
+description("Basic testing for the window returning window.open() becoming remote when navigating cross-origin.");
+jsTestIsAsync = true;
+
+if (window.testRunner)
+    testRunner.setCanOpenWindows(true);
+
+function wasWindowNavigatedCrossOrigin()
+{
+    try {
+        w.name;
+        return false;
+    } catch (e) {
+        return true;
+    }
+}
+
+function runTest() {
+    forbiddenProperties = ["name", "location.href", "document", "history", "locationbar", "status", "frameElement", "navigator", "alert", "localStorage", "sessionStorage", "event"];
+    for (forbiddenProperty of forbiddenProperties)
+        shouldThrowErrorName("w." + forbiddenProperty, "SecurityError");
+
+    shouldBe("w.window", "w");
+    shouldBe("w.self", "w");
+    shouldBe("w.top", "w");
+    shouldBe("w.parent", "w");
+    shouldBe("w.frames", "w");
+    shouldBeFalse("w.closed");
+    shouldBe("w.length", "0");
+    shouldBe("w.opener", "window");
+    shouldBeType("w.close", "Function");
+    shouldBeType("w.focus", "Function");
+    shouldBeType("w.blur", "Function");
+    shouldBeType("w.postMessage", "Function");
+
+    shouldNotThrow("w.location");
+    shouldNotBe("w.location", "null");
+
+    expected_property_names = ["blur", "close", "closed", "focus", "frames", "length", "location", "opener", "parent", "postMessage", "self", "top", "window"];
+    actual_properties = Object.getOwnPropertyNames(w);
+    shouldBeTrue("areArraysEqual(actual_properties, expected_property_names)");
+
+    shouldThrowErrorName("Object.getPrototype(w)", "TypeError");
+    shouldThrowErrorName("Object.setPrototype(w, {})", "TypeError");
+    shouldThrowErrorName("Object.preventExtensions(w)", "TypeError");
+    shouldThrowErrorName("Object.defineProperty(w, 'foo', {value: 1})", "SecurityError");
+    shouldThrowErrorName("delete w.closed", "SecurityError");
+
+    shouldThrowErrorName("w.foo = 1", "SecurityError");
+
+    finishJSTest();
+}
+
+_onload_ = function() {
+    w = window.open("http://localhost:8000/navigation/resources/success.html");
+    shouldBeEqualToString("w.location.href", "about:blank");
+
+    handle = setInterval(function() {
+        if (wasWindowNavigatedCrossOrigin()) {
+            clearInterval(handle);
+            runTest();
+        }
+    }, 5);
+}
+</script>
+</body>
+</html>

Modified: trunk/LayoutTests/platform/wk2/TestExpectations (230763 => 230764)


--- trunk/LayoutTests/platform/wk2/TestExpectations	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/LayoutTests/platform/wk2/TestExpectations	2018-04-18 16:50:36 UTC (rev 230764)
@@ -707,6 +707,9 @@
 http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subresource-redirects.html [ Skip ]
 http/tests/resourceLoadStatistics/strip-referrer-to-origin-for-prevalent-subresource-requests.html [ Skip ]
 
+# Process swapping is only implemented on WebKit2.
+http/tests/navigation/process-swap-window-open.html [ Pass ]
+
 ### END OF (5) Progressions, expected successes that are expected failures in WebKit1.
 ########################################
 

Modified: trunk/Source/WebCore/ChangeLog (230763 => 230764)


--- trunk/Source/WebCore/ChangeLog	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/ChangeLog	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1,3 +1,50 @@
+2018-04-18  Chris Dumez  <[email protected]>
+
+        Add support for converting a local window to a remote window
+        https://bugs.webkit.org/show_bug.cgi?id=184515
+        <rdar://problem/39011318>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add initial support for process-swapping when navigating cross-origin as a result
+        of a window.open(). The window object returned by window.open() is initially same
+        origin and is for about:blank. The navigation cross-origin then happens and the
+        JS wrappers for the window then point to a cross-origin window which is remote (i.e.
+        hosted in another WebProcess).
+
+        The RemoteDOMWindow exposed to JS looks like a regular cross-origin Window with a few
+        exceptions due to our incomplete implementation (e.g. w.location returns null) and 
+        most of its API is currently not functional. The RemoteDOMWindow API will be implemented
+        in a follow-up by relying on IPC.
+
+        Test: http/tests/navigation/process-swap-window-open.html
+
+        * bindings/js/JSDOMGlobalObject.cpp:
+        (WebCore::JSDOMGlobalObject::scriptExecutionContext const):
+        * bindings/js/JSDOMPromiseDeferred.h:
+        * bindings/js/JSDOMWindowProperties.cpp:
+        (WebCore::JSDOMWindowProperties::getOwnPropertySlot):
+        * bindings/js/JSDOMWindowProxy.cpp:
+        (WebCore::JSDOMWindowProxy::finishCreation):
+        (WebCore::JSDOMWindowProxy::create):
+        * bindings/js/JSDOMWindowProxy.h:
+        * bindings/js/JSDOMWrapper.cpp:
+        (WebCore::JSDOMObject::JSDOMObject):
+        * bindings/js/JSDOMWrapper.h:
+        * bindings/js/WindowProxyController.cpp:
+        (WebCore::WindowProxyController::createWindowProxy):
+        (WebCore::WindowProxyController::setDOMWindowForWindowProxy):
+        * bridge/objc/WebScriptObject.mm:
+        (-[WebScriptObject _isSafeScript]):
+        Teach more of our bindings code about RemoteDOMWindows.
+
+        * dom/Document.cpp:
+        (WebCore::Document::createDOMWindow):
+        * loader/FrameLoaderClient.h:
+        Add FrameLoaderClient function to notify the client when a DOMWindow is constructed in
+        the frame. This is needed for WebKit2 to link the old window to its new representation
+        in the new WebProcess.
+
 2018-04-17  Zan Dobersek  <[email protected]>
 
         [CMake] Add and enable the ENABLE_CSS_ANIMATIONS_LEVEL_2 feature define

Modified: trunk/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMGlobalObject.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -38,6 +38,7 @@
 #include "JSRTCSessionDescription.h"
 #include "JSReadableStream.h"
 #include "JSReadableStreamPrivateConstructors.h"
+#include "JSRemoteDOMWindow.h"
 #include "JSWorkerGlobalScope.h"
 #include "RuntimeEnabledFeatures.h"
 #include "StructuredClone.h"
@@ -197,11 +198,13 @@
 {
     if (inherits<JSDOMWindowBase>(vm()))
         return jsCast<const JSDOMWindowBase*>(this)->scriptExecutionContext();
+    if (inherits<JSRemoteDOMWindowBase>(vm()))
+        return nullptr;
     if (inherits<JSWorkerGlobalScopeBase>(vm()))
         return jsCast<const JSWorkerGlobalScopeBase*>(this)->scriptExecutionContext();
     dataLog("Unexpected global object: ", JSValue(this), "\n");
     RELEASE_ASSERT_NOT_REACHED();
-    return 0;
+    return nullptr;
 }
 
 void JSDOMGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)

Modified: trunk/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMPromiseDeferred.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -33,6 +33,8 @@
 
 namespace WebCore {
 
+class JSDOMWindow;
+
 class DeferredPromise : public DOMGuarded<JSC::JSPromiseDeferred> {
 public:
     enum class Mode {

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowProperties.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -89,7 +89,15 @@
     if (proto.isObject() && jsCast<JSObject*>(proto)->hasProperty(state, propertyName))
         return false;
 
-    auto& window = jsCast<JSDOMWindowBase*>(thisObject->globalObject())->wrapped();
+    auto& vm = state->vm();
+
+    // FIXME: We should probably add support for JSRemoteDOMWindowBase too.
+    auto* jsWindow = jsDynamicCast<JSDOMWindowBase*>(vm, thisObject->globalObject());
+    if (!jsWindow)
+        return false;
+
+    auto& window = jsWindow->wrapped();
+
     if (auto* frame = window.frame())
         return jsDOMWindowPropertiesGetOwnPropertySlotNamedItemGetter(thisObject, *frame, state, propertyName, slot);
 

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowProxy.cpp (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowProxy.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowProxy.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -29,8 +29,8 @@
 #include "config.h"
 #include "JSDOMWindowProxy.h"
 
+#include "AbstractFrame.h"
 #include "CommonVM.h"
-#include "Frame.h"
 #include "GCController.h"
 #include "JSDOMWindow.h"
 #include "JSDOMWindowProperties.h"
@@ -49,7 +49,7 @@
 {
 }
 
-void JSDOMWindowProxy::finishCreation(VM& vm, DOMWindow& window)
+void JSDOMWindowProxy::finishCreation(VM& vm, AbstractDOMWindow& window)
 {
     Base::finishCreation(vm);
     ASSERT(inherits(vm, info()));
@@ -56,7 +56,7 @@
     setWindow(window);
 }
 
-JSDOMWindowProxy& JSDOMWindowProxy::create(JSC::VM& vm, DOMWindow& window, DOMWrapperWorld& world)
+JSDOMWindowProxy& JSDOMWindowProxy::create(JSC::VM& vm, AbstractDOMWindow& window, DOMWrapperWorld& world)
 {
     auto& structure = *JSC::Structure::create(vm, 0, jsNull(), JSC::TypeInfo(JSC::PureForwardingProxyType, StructureFlags), info());
     auto& proxy = *new (NotNull, JSC::allocateCell<JSDOMWindowProxy>(vm.heap)) JSDOMWindowProxy(vm, structure, world);

Modified: trunk/Source/WebCore/bindings/js/JSDOMWindowProxy.h (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMWindowProxy.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMWindowProxy.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -43,7 +43,7 @@
 class JSDOMWindowProxy final : public JSC::JSProxy {
     using Base = JSC::JSProxy;
 public:
-    static JSDOMWindowProxy& create(JSC::VM&, DOMWindow&, DOMWrapperWorld&);
+    static JSDOMWindowProxy& create(JSC::VM&, AbstractDOMWindow&, DOMWrapperWorld&);
     static void destroy(JSCell*);
 
     DECLARE_INFO;
@@ -61,7 +61,7 @@
 
 private:
     JSDOMWindowProxy(JSC::VM&, JSC::Structure&, DOMWrapperWorld&);
-    void finishCreation(JSC::VM&, DOMWindow&);
+    void finishCreation(JSC::VM&, AbstractDOMWindow&);
 
     Ref<DOMWrapperWorld> m_world;
 };

Modified: trunk/Source/WebCore/bindings/js/JSDOMWrapper.cpp (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMWrapper.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMWrapper.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -29,6 +29,7 @@
 #include "DOMWindow.h"
 #include "DOMWrapperWorld.h"
 #include "JSDOMWindow.h"
+#include "JSRemoteDOMWindow.h"
 #include "SerializedScriptValue.h"
 #include "WebCoreJSClientData.h"
 #include <_javascript_Core/Error.h>
@@ -37,11 +38,10 @@
 
 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSDOMObject);
 
-JSDOMWindow& JSDOMObject::domWindow() const
+JSDOMObject::JSDOMObject(JSC::Structure* structure, JSC::JSGlobalObject& globalObject)
+    : Base(globalObject.vm(), structure)
 {
-    auto* domWindow = JSC::jsCast<JSDOMWindow*>(JSC::JSNonFinalObject::globalObject());
-    ASSERT(domWindow);
-    return *domWindow;
+    ASSERT(scriptExecutionContext() || globalObject.classInfo() == JSRemoteDOMWindow::info());
 }
 
 CompleteSubspace* outputConstraintSubspaceFor(VM& vm)

Modified: trunk/Source/WebCore/bindings/js/JSDOMWrapper.h (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/JSDOMWrapper.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/JSDOMWrapper.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -27,7 +27,6 @@
 
 namespace WebCore {
 
-class JSDOMWindow;
 class ScriptExecutionContext;
 
 // JSC allows us to extend JSType. If the highest bit is set, we can add any Object types and they are
@@ -63,14 +62,8 @@
     JSDOMGlobalObject* globalObject() const { return JSC::jsCast<JSDOMGlobalObject*>(JSC::JSNonFinalObject::globalObject()); }
     ScriptExecutionContext* scriptExecutionContext() const { return globalObject()->scriptExecutionContext(); }
 
-    JSDOMWindow& domWindow() const;
-
 protected:
-    JSDOMObject(JSC::Structure* structure, JSC::JSGlobalObject& globalObject)
-        : Base(globalObject.vm(), structure)
-    {
-        ASSERT(scriptExecutionContext());
-    }
+    WEBCORE_EXPORT JSDOMObject(JSC::Structure*, JSC::JSGlobalObject&);
 };
 
 WEBCORE_EXPORT JSC::CompleteSubspace* outputConstraintSubspaceFor(JSC::VM&);

Modified: trunk/Source/WebCore/bindings/js/WindowProxyController.cpp (230763 => 230764)


--- trunk/Source/WebCore/bindings/js/WindowProxyController.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bindings/js/WindowProxyController.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -79,10 +79,7 @@
 
     VM& vm = world.vm();
 
-    // FIXME: We do not support constructing a JSDOMWindowProxy for a RemoteDOMWindow yet.
-    RELEASE_ASSERT(is<DOMWindow>(m_frame.window()));
-
-    Strong<JSDOMWindowProxy> windowProxy(vm, &JSDOMWindowProxy::create(vm, *downcast<DOMWindow>(m_frame.window()), world));
+    Strong<JSDOMWindowProxy> windowProxy(vm, &JSDOMWindowProxy::create(vm, *m_frame.window(), world));
     Strong<JSDOMWindowProxy> windowProxy2(windowProxy);
     m_windowProxies.add(&world, windowProxy);
     world.didCreateWindowProxy(this);
@@ -140,11 +137,8 @@
         if (&windowProxy->wrapped() == newDOMWindow)
             continue;
 
-        // FIXME: We do not support setting a RemoteDOMWindow yet.
-        ASSERT(is<DOMWindow>(newDOMWindow));
+        windowProxy->setWindow(*newDOMWindow);
 
-        windowProxy->setWindow(*downcast<DOMWindow>(newDOMWindow));
-
         ScriptController* scriptController = nullptr;
         Page* page = nullptr;
         if (is<Frame>(m_frame)) {

Modified: trunk/Source/WebCore/bridge/objc/WebScriptObject.mm (230763 => 230764)


--- trunk/Source/WebCore/bridge/objc/WebScriptObject.mm	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/bridge/objc/WebScriptObject.mm	2018-04-18 16:50:36 UTC (rev 230764)
@@ -276,7 +276,9 @@
     // It's not actually correct to call shouldAllowAccessToFrame in this way because
     // JSDOMWindowBase* isn't the right object to represent the currently executing
     // _javascript_. Instead, we should use ExecState, like we do elsewhere.
-    JSDOMWindowBase* target = jsCast<JSDOMWindowBase*>(root->globalObject());
+    auto* target = JSC::jsDynamicCast<JSDOMWindowBase*>(root->globalObject()->vm(), root->globalObject());
+    if (!target)
+        return false;
     return BindingSecurity::shouldAllowAccessToDOMWindow(_private->originRootObject->globalObject()->globalExec(), target->wrapped());
 }
 

Modified: trunk/Source/WebCore/dom/Document.cpp (230763 => 230764)


--- trunk/Source/WebCore/dom/Document.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/dom/Document.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -4261,6 +4261,8 @@
 
     ASSERT(m_domWindow->document() == this);
     ASSERT(m_domWindow->frame() == m_frame);
+
+    m_frame->loader().client().didCreateWindow(*m_domWindow);
 }
 
 void Document::takeDOMWindowFrom(Document* document)

Modified: trunk/Source/WebCore/loader/FrameLoaderClient.h (230763 => 230764)


--- trunk/Source/WebCore/loader/FrameLoaderClient.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/loader/FrameLoaderClient.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -71,6 +71,7 @@
 class CachedFrame;
 class CachedResourceRequest;
 class Color;
+class DOMWindow;
 class DOMWindowExtension;
 class DOMWrapperWorld;
 class DocumentLoader;
@@ -365,6 +366,8 @@
     virtual void getLoadDecisionForIcons(const Vector<std::pair<WebCore::LinkIcon&, uint64_t>>&) { }
     virtual void finishedLoadingIcon(uint64_t, SharedBuffer*) { }
 
+    virtual void didCreateWindow(DOMWindow&) { }
+
 #if ENABLE(APPLICATION_MANIFEST)
     virtual void finishedLoadingApplicationManifest(uint64_t, const std::optional<ApplicationManifest>&) { }
 #endif

Modified: trunk/Source/WebCore/page/Frame.h (230763 => 230764)


--- trunk/Source/WebCore/page/Frame.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebCore/page/Frame.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -141,7 +141,7 @@
     void addDestructionObserver(FrameDestructionObserver*);
     void removeDestructionObserver(FrameDestructionObserver*);
 
-    void willDetachPage();
+    WEBCORE_EXPORT void willDetachPage();
     void detachFromPage();
     void disconnectOwnerElement();
 

Modified: trunk/Source/WebKit/ChangeLog (230763 => 230764)


--- trunk/Source/WebKit/ChangeLog	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/ChangeLog	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1,3 +1,77 @@
+2018-04-18  Chris Dumez  <[email protected]>
+
+        Add support for converting a local window to a remote window
+        https://bugs.webkit.org/show_bug.cgi?id=184515
+        <rdar://problem/39011318>
+
+        Reviewed by Ryosuke Niwa.
+
+        Add initial support for process-swapping when navigating cross-origin as a result
+        of a window.open(). The window object returned by window.open() is initially same
+        origin and is for about:blank. The navigation cross-origin then happens and the
+        JS wrappers for the window then point to a cross-origin window which is remote (i.e.
+        hosted in another WebProcess).
+
+        The RemoteDOMWindow exposed to JS looks like a regular cross-origin Window with a few
+        exceptions due to our incomplete implementation (e.g. w.location returns null) and
+        most of its API is currently not functional. The RemoteDOMWindow API will be implemented
+        in a follow-up by relying on IPC.
+
+        * UIProcess/API/APIProcessPoolConfiguration.cpp:
+        (API::ProcessPoolConfiguration::copy):
+        * UIProcess/API/APIProcessPoolConfiguration.h:
+        * UIProcess/API/C/WKContextConfigurationRef.cpp:
+        (WKContextConfigurationProcessSwapsOnWindowOpenWithOpener):
+        (WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener):
+        * UIProcess/API/C/WKContextConfigurationRef.h:
+        * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h:
+        * UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm:
+        (-[_WKProcessPoolConfiguration setProcessSwapsOnWindowOpenWithOpener:]):
+        (-[_WKProcessPoolConfiguration processSwapsOnWindowOpenWithOpener]):
+        Add ProcessPool configuration flag to turn on processSwap on window.open(), even
+        if there is an opener.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::continueNavigationInNewProcess):
+        If the navigation was triggered via window.open(), then set up on handler for when
+        a DOMWindow is constructed for the main frame in the new process.
+
+        (WebKit::WebPageProxy::didCreateWindow):
+        When a Window is constructed for the main frame in a new process on process swap,
+        notify the old process that its representation of the window should become remote
+        and provide it with the Frame / Window identifiers it needs.
+
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigation):
+        Do process swapping on cross-origin window.open() if the corresponding setting is
+        enabled.
+
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::didCreateWindow):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.h:
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::frameBecameRemote):
+        This is called when process swapping has happened due to a window.open() navigation
+        cross-origin, when a Frame / Window has been constructed in the new process. We do
+        the following:
+        - Construct a RemoteFrame / RemoteWindow using the provided global identifiers to
+          represent the Frame / Window in the new process.
+        - We transfer the WindowProxies from the old Frame's WindowProxyController to the
+          new RemoteFrame's WindowProxyController.
+        - We update the window proxied by those WindowProxies to be the new RemoteWindow.
+        - We detach the old Frame as it is now remote and represented by the new RemoteFrame
+          object we constructed.
+        - If the old frame was the main frame (always the case currently), we close the page
+          as it is no longer needed. The new RemoteFrame is currently owned by the RemoteWindow
+          which is kept alive by its JS wrappers.
+
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+
 2018-04-18  Carlos Garcia Campos  <[email protected]>
 
         Unreviewed. Update OptionsGTK.cmake and NEWS for 2.21.1 release.

Modified: trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -128,6 +128,7 @@
 #endif
     copy->m_presentingApplicationPID = this->m_presentingApplicationPID;
     copy->m_processSwapsOnNavigation = this->m_processSwapsOnNavigation;
+    copy->m_processSwapsOnWindowOpenWithOpener = this->m_processSwapsOnWindowOpenWithOpener;
 
     return copy;
 }

Modified: trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -138,6 +138,9 @@
     bool processSwapsOnNavigation() const { return m_processSwapsOnNavigation; }
     void setProcessSwapsOnNavigation(bool swaps) { m_processSwapsOnNavigation = swaps; }
 
+    bool processSwapsOnWindowOpenWithOpener() const { return m_processSwapsOnWindowOpenWithOpener; }
+    void setProcessSwapsOnWindowOpenWithOpener(bool swaps) { m_processSwapsOnWindowOpenWithOpener = swaps; }
+
 private:
     bool m_shouldHaveLegacyDataStore { false };
 
@@ -170,6 +173,7 @@
     bool m_shouldCaptureAudioInUIProcess { false };
     ProcessID m_presentingApplicationPID { getCurrentProcessID() };
     bool m_processSwapsOnNavigation { false };
+    bool m_processSwapsOnWindowOpenWithOpener { false };
 
 #if PLATFORM(IOS)
     WTF::String m_ctDataConnectionServiceType;

Modified: trunk/Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.cpp (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -167,3 +167,13 @@
 {
     toImpl(configuration)->setProcessSwapsOnNavigation(swaps);
 }
+
+bool WKContextConfigurationProcessSwapsOnWindowOpenWithOpener(WKContextConfigurationRef configuration)
+{
+    return toImpl(configuration)->processSwapsOnWindowOpenWithOpener();
+}
+
+void WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(WKContextConfigurationRef configuration, bool swaps)
+{
+    toImpl(configuration)->setProcessSwapsOnWindowOpenWithOpener(swaps);
+}

Modified: trunk/Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.h (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/API/C/WKContextConfigurationRef.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -71,6 +71,9 @@
 WK_EXPORT bool WKContextConfigurationProcessSwapsOnNavigation(WKContextConfigurationRef configuration);
 WK_EXPORT void WKContextConfigurationSetProcessSwapsOnNavigation(WKContextConfigurationRef configuration, bool swaps);
 
+WK_EXPORT bool WKContextConfigurationProcessSwapsOnWindowOpenWithOpener(WKContextConfigurationRef configuration);
+WK_EXPORT void WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(WKContextConfigurationRef configuration, bool swaps);
+
 #ifdef __cplusplus
 }
 #endif

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -58,6 +58,7 @@
 #endif
 @property (nonatomic) pid_t presentingApplicationPID WK_API_AVAILABLE(macosx(10.13), ios(11.0));
 @property (nonatomic) BOOL processSwapsOnNavigation WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+@property (nonatomic) BOOL processSwapsOnWindowOpenWithOpener WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 @end
 

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/_WKProcessPoolConfiguration.mm	2018-04-18 16:50:36 UTC (rev 230764)
@@ -237,6 +237,16 @@
     return _processPoolConfiguration->processSwapsOnNavigation();
 }
 
+- (void)setProcessSwapsOnWindowOpenWithOpener:(BOOL)swaps
+{
+    _processPoolConfiguration->setProcessSwapsOnWindowOpenWithOpener(swaps);
+}
+
+- (BOOL)processSwapsOnWindowOpenWithOpener
+{
+    return _processPoolConfiguration->processSwapsOnWindowOpenWithOpener();
+}
+
 #if PLATFORM(IOS)
 - (NSString *)CTDataConnectionServiceType
 {

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -127,6 +127,8 @@
 #include <WebCore/FloatRect.h>
 #include <WebCore/FocusDirection.h>
 #include <WebCore/FrameLoader.h>
+#include <WebCore/GlobalFrameIdentifier.h>
+#include <WebCore/GlobalWindowIdentifier.h>
 #include <WebCore/JSDOMBinding.h>
 #include <WebCore/JSDOMExceptionHandling.h>
 #include <WebCore/LengthBox.h>
@@ -2413,6 +2415,11 @@
 {
     LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString().utf8().data());
 
+    Ref<WebProcessProxy> previousProcess = m_process.copyRef();
+    std::optional<uint64_t> navigatedFrameIdentifierInPreviousProcess;
+    if (m_mainFrame)
+        navigatedFrameIdentifierInPreviousProcess = m_mainFrame->frameID();
+
     ASSERT(m_process.ptr() != process.ptr());
     attachToProcessForNavigation(WTFMove(process));
 
@@ -2443,6 +2450,15 @@
             didReceiveServerRedirectForProvisionalLoadForFrame(m_mainFrame->frameID(), navigation->navigationID(), WTFMove(request), { });
         };
     }
+
+    if (!navigation.isCrossOriginWindowOpenNavigation() || !navigatedFrameIdentifierInPreviousProcess)
+        return;
+
+    m_mainFrameWindowCreationHandler = [this, previousProcess = WTFMove(previousProcess), navigatedFrameIdentifierInPreviousProcess = *navigatedFrameIdentifierInPreviousProcess](const GlobalWindowIdentifier& windowIdentifier) {
+        ASSERT(m_mainFrame);
+        GlobalFrameIdentifier navigatedFrameIdentifierInNewProcess { pageID(), m_mainFrame->frameID() };
+        previousProcess->send(Messages::WebPage::FrameBecameRemote(navigatedFrameIdentifierInPreviousProcess, navigatedFrameIdentifierInNewProcess, windowIdentifier), pageID());
+    };
 }
 
 void WebPageProxy::setUserAgent(String&& userAgent)
@@ -3271,6 +3287,14 @@
     m_process->frameCreated(frameID, subFrame.get());
 }
 
+void WebPageProxy::didCreateWindow(uint64_t frameID, GlobalWindowIdentifier&& windowIdentifier)
+{
+    if (m_mainFrame && m_mainFrame->frameID() == frameID) {
+        if (auto mainFrameWindowCreationHandler = WTFMove(m_mainFrameWindowCreationHandler))
+            mainFrameWindowCreationHandler(windowIdentifier);
+    }
+}
+
 double WebPageProxy::estimatedProgress() const
 {
     return m_pageLoadState.estimatedProgress();

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -177,6 +177,7 @@
 struct DictionaryPopupInfo;
 struct ExceptionDetails;
 struct FileChooserSettings;
+struct GlobalWindowIdentifier;
 struct MediaStreamRequest;
 struct SecurityOriginData;
 struct TextAlternativeWithRange;
@@ -1338,6 +1339,7 @@
 
     void didCreateMainFrame(uint64_t frameID);
     void didCreateSubframe(uint64_t frameID);
+    void didCreateWindow(uint64_t frameID, WebCore::GlobalWindowIdentifier&&);
 
     void didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL&&, WebCore::URL&& unreachableURL, const UserData&);
     void didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::ResourceRequest&&, const UserData&);
@@ -1780,6 +1782,7 @@
 
     RefPtr<WebFrameProxy> m_mainFrame;
     Function<void()> m_mainFrameCreationHandler;
+    Function<void(const WebCore::GlobalWindowIdentifier&)> m_mainFrameWindowCreationHandler;
 
     RefPtr<WebFrameProxy> m_focusedFrame;
     RefPtr<WebFrameProxy> m_frameSetLargestFrame;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.messages.in	2018-04-18 16:50:36 UTC (rev 230764)
@@ -115,6 +115,8 @@
     DidCreateMainFrame(uint64_t frameID)
     DidCreateSubframe(uint64_t frameID)
 
+    DidCreateWindow(uint64_t frameID, struct WebCore::GlobalWindowIdentifier windowIdentifier)
+
     # Frame load messages
     DidStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::URL url, WebCore::URL unreachableURL, WebKit::UserData userData)
     DidReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::ResourceRequest request, WebKit::UserData userData)

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (230763 => 230764)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1985,15 +1985,18 @@
     if (!page.process().hasCommittedAnyProvisionalLoads())
         return page.process();
 
-    // FIXME: We should support process swap when a window has an opener.
-    if (navigation.opener())
-        return page.process();
+    if (navigation.isCrossOriginWindowOpenNavigation()) {
+        if (navigation.opener() && !m_configuration->processSwapsOnWindowOpenWithOpener())
+            return page.process();
 
-    if (navigation.isCrossOriginWindowOpenNavigation()) {
         action = ""
         return createNewWebProcess(page.websiteDataStore());
     }
 
+    // FIXME: We should support process swap when a window has an opener.
+    if (navigation.opener())
+        return page.process();
+
     auto targetURL = navigation.currentRequest().url();
     auto url = "" { ParsedURLString, page.pageLoadState().url() };
     if (!url.isValid() || url.isEmpty() || url.isBlankURL() || protocolHostAndPortAreEqual(url, targetURL))

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp (230763 => 230764)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1876,6 +1876,15 @@
     }
 }
 
+void WebFrameLoaderClient::didCreateWindow(DOMWindow& window)
+{
+    auto* webPage = m_frame->page();
+    if (!webPage)
+        return;
+
+    webPage->send(Messages::WebPageProxy::DidCreateWindow(m_frame->frameID(), window.identifier()));
+}
+
 #if ENABLE(APPLICATION_MANIFEST)
 void WebFrameLoaderClient::finishedLoadingApplicationManifest(uint64_t callbackIdentifier, const std::optional<WebCore::ApplicationManifest>& manifest)
 {

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h (230763 => 230764)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -269,6 +269,8 @@
     void getLoadDecisionForIcons(const Vector<std::pair<WebCore::LinkIcon&, uint64_t>>&) final;
     void finishedLoadingIcon(uint64_t callbackIdentifier, WebCore::SharedBuffer*) final;
 
+    void didCreateWindow(WebCore::DOMWindow&) final;
+
 #if ENABLE(APPLICATION_MANIFEST)
     void finishedLoadingApplicationManifest(uint64_t, const std::optional<WebCore::ApplicationManifest>&) final;
 #endif

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (230763 => 230764)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -182,6 +182,8 @@
 #include <WebCore/PrintContext.h>
 #include <WebCore/PromisedBlobInfo.h>
 #include <WebCore/Range.h>
+#include <WebCore/RemoteDOMWindow.h>
+#include <WebCore/RemoteFrame.h>
 #include <WebCore/RenderLayer.h>
 #include <WebCore/RenderTheme.h>
 #include <WebCore/RenderTreeAsText.h>
@@ -5871,6 +5873,32 @@
     m_isSuspended = suspended;
 }
 
+void WebPage::frameBecameRemote(uint64_t frameID, GlobalFrameIdentifier&& remoteFrameIdentifier, GlobalWindowIdentifier&& remoteWindowIdentifier)
+{
+    RefPtr<WebFrame> frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame)
+        return;
+
+    if (frame->page() != this)
+        return;
+
+    auto remoteFrame = RemoteFrame::create(WTFMove(remoteFrameIdentifier));
+    auto remoteWindow = RemoteDOMWindow::create(remoteFrame.copyRef(), WTFMove(remoteWindowIdentifier));
+    UNUSED_PARAM(remoteWindow);
+
+    auto windowProxies = frame->coreFrame()->windowProxyController().releaseWindowProxies();
+    remoteFrame->windowProxyController().setWindowProxies(WTFMove(windowProxies));
+    remoteFrame->windowProxyController().setDOMWindowForWindowProxy(remoteWindow.ptr());
+
+    auto* coreFrame = frame->coreFrame();
+    coreFrame->setView(nullptr);
+    coreFrame->willDetachPage();
+    coreFrame->detachFromPage();
+
+    if (frame->isMainFrame())
+        close();
+}
+
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
 static uint64_t nextRequestStorageAccessContextId()
 {

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (230763 => 230764)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -156,6 +156,8 @@
 
 struct CompositionUnderline;
 struct DictationAlternative;
+struct GlobalFrameIdentifier;
+struct GlobalWindowIdentifier;
 struct Highlight;
 struct KeypressCommand;
 struct PromisedBlobInfo;
@@ -1383,6 +1385,8 @@
     void didReceivePasswordForQuickLookDocument(const String&);
 #endif
 
+    void frameBecameRemote(uint64_t frameID, WebCore::GlobalFrameIdentifier&& remoteFrameIdentifier, WebCore::GlobalWindowIdentifier&& remoteWindowIdentifier);
+
     void registerURLSchemeHandler(uint64_t identifier, const String& scheme);
 
     void urlSchemeTaskDidPerformRedirection(uint64_t handlerIdentifier, uint64_t taskIdentifier, WebCore::ResourceResponse&&, WebCore::ResourceRequest&&);

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (230763 => 230764)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2018-04-18 16:50:36 UTC (rev 230764)
@@ -484,6 +484,8 @@
     DidReceivePasswordForQuickLookDocument(String password)
 #endif
 
+    FrameBecameRemote(uint64_t frameID, struct WebCore::GlobalFrameIdentifier remoteFrameIdentifier, struct WebCore::GlobalWindowIdentifier remoteWindowIdentifier)
+
     RegisterURLSchemeHandler(uint64_t identifier, String scheme)
 
     URLSchemeTaskDidPerformRedirection(uint64_t handlerIdentifier, uint64_t taskIdentifier, WebCore::ResourceResponse response, WebCore::ResourceRequest request)

Modified: trunk/Tools/ChangeLog (230763 => 230764)


--- trunk/Tools/ChangeLog	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/ChangeLog	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1,3 +1,39 @@
+2018-04-18  Chris Dumez  <[email protected]>
+
+        Add support for converting a local window to a remote window
+        https://bugs.webkit.org/show_bug.cgi?id=184515
+        <rdar://problem/39011318>
+
+        Reviewed by Ryosuke Niwa.
+
+        * MiniBrowser/mac/AppDelegate.m:
+        (defaultConfiguration):
+        * MiniBrowser/mac/SettingsController.h:
+        * MiniBrowser/mac/SettingsController.m:
+        (-[SettingsController _populateMenu]):
+        (-[SettingsController validateMenuItem:]):
+        (-[SettingsController processSwapOnWindowOpenWithOpenerEnabled]):
+        (-[SettingsController toggleProcessSwapOnWindowOpenWithOpener:]):
+        Add menu entry in minibrowser to turn on process swap on cross-origin window.open().
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+        Turn on process swap on cross-origin window.open() for corresponding test and update
+        test to expect that a new WebProcess is created.
+
+        * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+        (WTR::InjectedBundlePage::decidePolicyForResponse):
+        Add null checks for injectedBundle.testRunner(). When we swap process on navigation,
+        the InjectedBundlePage::decidePolicyForResponse() gets called in the new process.
+        In this new process, we have constructed a InjectedBundlePage for the page but we
+        have not initialized the InjectedBundle members such as testRunner.
+
+        * WebKitTestRunner/TestController.cpp:
+        (WTR::TestController::createWebViewWithOptions):
+        (WTR::updateTestOptionsFromTestHeader):
+        * WebKitTestRunner/TestOptions.h:
+        (WTR::TestOptions::hasSameInitializationOptions const):
+        Add a way for layout tests to turn on process swap on navigation via a test header.
+
 2018-04-18  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, reland r230697, r230720, and r230724.

Modified: trunk/Tools/MiniBrowser/mac/AppDelegate.m (230763 => 230764)


--- trunk/Tools/MiniBrowser/mac/AppDelegate.m	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/MiniBrowser/mac/AppDelegate.m	2018-04-18 16:50:36 UTC (rev 230764)
@@ -100,6 +100,8 @@
             processConfiguration.maximumProcessCount = 1;
         if ([SettingsController shared].processSwapOnNavigationEnabled)
             processConfiguration.processSwapsOnNavigation = true;
+        if ([SettingsController shared].processSwapOnWindowOpenWithOpenerEnabled)
+            processConfiguration.processSwapsOnWindowOpenWithOpener = true;
         
         configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease];
 

Modified: trunk/Tools/MiniBrowser/mac/SettingsController.h (230763 => 230764)


--- trunk/Tools/MiniBrowser/mac/SettingsController.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/MiniBrowser/mac/SettingsController.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -60,6 +60,7 @@
 @property (nonatomic, readonly) BOOL usesGameControllerFramework;
 @property (nonatomic, readonly) BOOL networkCacheSpeculativeRevalidationDisabled;
 @property (nonatomic, readonly) BOOL processSwapOnNavigationEnabled;
+@property (nonatomic, readonly) BOOL processSwapOnWindowOpenWithOpenerEnabled;
 
 @property (nonatomic, readonly) NSString *defaultURL;
 

Modified: trunk/Tools/MiniBrowser/mac/SettingsController.m (230763 => 230764)


--- trunk/Tools/MiniBrowser/mac/SettingsController.m	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/MiniBrowser/mac/SettingsController.m	2018-04-18 16:50:36 UTC (rev 230764)
@@ -71,6 +71,7 @@
 static NSString * const PerWindowWebProcessesDisabledKey = @"PerWindowWebProcessesDisabled";
 static NSString * const NetworkCacheSpeculativeRevalidationDisabledKey = @"NetworkCacheSpeculativeRevalidationDisabled";
 static NSString * const ProcessSwapOnNavigationKey = @"ProcessSwapOnNavigation";
+static NSString * const ProcessSwapOnWindowOpenWithOpenerKey = @"ProcessSwapOnWindowOpenWithOpener";
 
 typedef NS_ENUM(NSInteger, DebugOverylayMenuItemTag) {
     NonFastScrollableRegionOverlayTag = 100,
@@ -181,6 +182,7 @@
     [self _addItemWithTitle:@"Use GameController.framework on macOS (Restart required)" action:@selector(toggleUsesGameControllerFramework:) indented:YES];
     [self _addItemWithTitle:@"Disable network cache speculative revalidation" action:@selector(toggleNetworkCacheSpeculativeRevalidationDisabled:) indented:YES];
     [self _addItemWithTitle:@"Enable Process Swap on Navigation" action:@selector(toggleProcessSwapOnNavigation:) indented:YES];
+    [self _addItemWithTitle:@"Enable Process Swap on window.open() with an opener" action:@selector(toggleProcessSwapOnWindowOpenWithOpener:) indented:YES];
 
     NSMenuItem *debugOverlaysSubmenuItem = [[NSMenuItem alloc] initWithTitle:@"Debug Overlays" action:nil keyEquivalent:@""];
     NSMenu *debugOverlaysMenu = [[NSMenu alloc] initWithTitle:@"Debug Overlays"];
@@ -274,6 +276,8 @@
         [menuItem setState:[self networkCacheSpeculativeRevalidationDisabled] ? NSControlStateValueOn : NSControlStateValueOff];
     else if (action == @selector(toggleProcessSwapOnNavigation:))
         [menuItem setState:[self processSwapOnNavigationEnabled] ? NSControlStateValueOn : NSControlStateValueOff];
+    else if (action == @selector(toggleProcessSwapOnWindowOpenWithOpener:))
+        [menuItem setState:[self processSwapOnWindowOpenWithOpenerEnabled] ? NSControlStateValueOn : NSControlStateValueOff];
     else if (action == @selector(toggleUseUISideCompositing:))
         [menuItem setState:[self useUISideCompositing] ? NSControlStateValueOn : NSControlStateValueOff];
     else if (action == @selector(togglePerWindowWebProcessesDisabled:))
@@ -499,6 +503,16 @@
     [self _toggleBooleanDefault:ProcessSwapOnNavigationKey];
 }
 
+- (BOOL)processSwapOnWindowOpenWithOpenerEnabled
+{
+    return [[NSUserDefaults standardUserDefaults] boolForKey:ProcessSwapOnWindowOpenWithOpenerKey];
+}
+
+- (void)toggleProcessSwapOnWindowOpenWithOpener:(id)sender
+{
+    [self _toggleBooleanDefault:ProcessSwapOnWindowOpenWithOpenerKey];
+}
+
 - (BOOL)isSpaceReservedForBanners
 {
     return [[NSUserDefaults standardUserDefaults] boolForKey:ReserveSpaceForBannersPreferenceKey];

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (230763 => 230764)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2018-04-18 16:50:36 UTC (rev 230764)
@@ -409,6 +409,7 @@
 {
     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     processPoolConfiguration.get().processSwapsOnNavigation = YES;
+    processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES;
     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
 
     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -443,8 +444,7 @@
     auto pid2 = [createdWebView _webProcessIdentifier];
     EXPECT_TRUE(!!pid2);
 
-    // FIXME: This should eventually be false once we support process swapping when there is an opener.
-    EXPECT_EQ(pid1, pid2);
+    EXPECT_NE(pid1, pid2);
 }
 
 TEST(ProcessSwap, SameOriginWindowOpenNoOpener)

Modified: trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp (230763 => 230764)


--- trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -1386,7 +1386,7 @@
 WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef, WKURLResponseRef response, WKURLRequestRef, WKTypeRef*)
 {
     auto& injectedBundle = InjectedBundle::singleton();
-    if (injectedBundle.testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) {
+    if (injectedBundle.testRunner() && injectedBundle.testRunner()->isPolicyDelegateEnabled() && WKURLResponseIsAttachment(response)) {
         StringBuilder stringBuilder;
         WKRetainPtr<WKStringRef> filename = adoptWK(WKURLResponseCopySuggestedFilename(response));
         stringBuilder.appendLiteral("Policy delegate: resource is an attachment, suggested file name \'");
@@ -1395,7 +1395,7 @@
         InjectedBundle::singleton().outputText(stringBuilder.toString());
     }
 
-    if (injectedBundle.testRunner()->shouldDecideResponsePolicyAfterDelay())
+    if (injectedBundle.testRunner() && injectedBundle.testRunner()->shouldDecideResponsePolicyAfterDelay())
         return WKBundlePagePolicyActionPassThrough;
 
     WKRetainPtr<WKStringRef> mimeType = adoptWK(WKURLResponseCopyMIMEType(response));

Modified: trunk/Tools/WebKitTestRunner/TestController.cpp (230763 => 230764)


--- trunk/Tools/WebKitTestRunner/TestController.cpp	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/WebKitTestRunner/TestController.cpp	2018-04-18 16:50:36 UTC (rev 230764)
@@ -497,6 +497,11 @@
         WKArrayAppendItem(overrideLanguages.get(), adoptWK(WKStringCreateWithUTF8CString(language.utf8().data())).get());
     WKContextConfigurationSetOverrideLanguages(contextConfiguration.get(), overrideLanguages.get());
 
+    if (options.enableProcessSwapOnNavigation) {
+        WKContextConfigurationSetProcessSwapsOnNavigation(contextConfiguration.get(), true);
+        WKContextConfigurationSetProcessSwapsOnWindowOpenWithOpener(contextConfiguration.get(), true);
+    }
+
     auto configuration = generatePageConfiguration(contextConfiguration.get());
 
     // Some preferences (notably mock scroll bars setting) currently cannot be re-applied to an existing view, so we need to set them now.
@@ -1096,6 +1101,8 @@
             testOptions.allowCrossOriginSubresourcesToAskForCredentials = parseBooleanTestHeaderValue(value);
         if (key == "enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations")
             testOptions.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations = parseBooleanTestHeaderValue(value);
+        if (key == "enableProcessSwapOnNavigation")
+            testOptions.enableProcessSwapOnNavigation = parseBooleanTestHeaderValue(value);
         pairStart = pairEnd + 1;
     }
 }

Modified: trunk/Tools/WebKitTestRunner/TestOptions.h (230763 => 230764)


--- trunk/Tools/WebKitTestRunner/TestOptions.h	2018-04-18 16:33:33 UTC (rev 230763)
+++ trunk/Tools/WebKitTestRunner/TestOptions.h	2018-04-18 16:50:36 UTC (rev 230764)
@@ -56,6 +56,7 @@
     bool dumpJSConsoleLogInStdErr { false };
     bool allowCrossOriginSubresourcesToAskForCredentials { false };
     bool enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations { false };
+    bool enableProcessSwapOnNavigation { false };
 
     float deviceScaleFactor { 1 };
     Vector<String> overrideLanguages;
@@ -86,7 +87,8 @@
             || dumpJSConsoleLogInStdErr != options.dumpJSConsoleLogInStdErr
             || applicationManifest != options.applicationManifest
             || allowCrossOriginSubresourcesToAskForCredentials != options.allowCrossOriginSubresourcesToAskForCredentials
-            || enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations != options.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations)
+            || enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations != options.enableCSSAnimationsAndCSSTransitionsBackedByWebAnimations
+            || enableProcessSwapOnNavigation != options.enableProcessSwapOnNavigation)
             return false;
 
         return true;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to