Bug 1172870 - Part 1 - Move PBrowser::CreateWindow to PContent. r=smaug
authorCatalin Badea <catalin.badea392@gmail.com>
Thu, 12 Nov 2015 04:02:34 +0200
changeset 305468 953d8110ed9d0aab346328ebcc4d9406394d8793
parent 305467 d5b408ced8ce03964d3ee22d23f77f1306bbe4b9
child 305469 be8391c58a8307f2b15cfe0b12ee4ba4d9bfb27b
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1172870
milestone44.0a2
Bug 1172870 - Part 1 - Move PBrowser::CreateWindow to PContent. r=smaug
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -42,16 +42,17 @@
 #include "mozilla/ipc/FileDescriptorUtils.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
 #include "mozilla/ipc/TestShellChild.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 #include "mozilla/layers/PCompositorChild.h"
 #include "mozilla/layers/SharedBufferManagerChild.h"
+#include "mozilla/layout/RenderFrameChild.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/plugins/PluginInstanceParent.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/widget/WidgetMessageUtils.h"
 #include "mozilla/media/MediaChild.h"
 #include "mozilla/BasePrincipal.h"
 #include "mozilla/WebBrowserPersistDocumentChild.h"
 
@@ -210,16 +211,17 @@ using namespace mozilla::dom::mobilemess
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
 using namespace mozilla::media;
 using namespace mozilla::embedding;
 using namespace mozilla::gmp;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
 using namespace mozilla::layers;
+using namespace mozilla::layout;
 using namespace mozilla::net;
 using namespace mozilla::jsipc;
 using namespace mozilla::psm;
 using namespace mozilla::widget;
 #if defined(MOZ_WIDGET_GONK)
 using namespace mozilla::system;
 #endif
 using namespace mozilla::widget;
@@ -602,17 +604,18 @@ ContentChild::ContentChild()
 }
 
 ContentChild::~ContentChild()
 {
 }
 
 NS_INTERFACE_MAP_BEGIN(ContentChild)
   NS_INTERFACE_MAP_ENTRY(nsIContentChild)
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(nsIWindowProvider)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIContentChild)
 NS_INTERFACE_MAP_END
 
 bool
 ContentChild::Init(MessageLoop* aIOLoop,
                    base::ProcessId aParentPid,
                    IPC::Channel* aChannel)
 {
 #ifdef MOZ_WIDGET_GTK
@@ -735,16 +738,163 @@ ContentChild::SetProcessName(const nsASt
     mProcessName = aName;
     mozilla::ipc::SetThisProcessName(NS_LossyConvertUTF16toASCII(aName).get());
 
     if (aDontOverride) {
         mCanOverrideProcessName = false;
     }
 }
 
+NS_IMETHODIMP
+ContentChild::ProvideWindow(nsIDOMWindow* aParent,
+                            uint32_t aChromeFlags,
+                            bool aCalledFromJS,
+                            bool aPositionSpecified,
+                            bool aSizeSpecified,
+                            nsIURI* aURI,
+                            const nsAString& aName,
+                            const nsACString& aFeatures,
+                            bool* aWindowIsNew,
+                            nsIDOMWindow** aReturn)
+{
+    return ProvideWindowCommon(nullptr, aParent, false, aChromeFlags,
+                               aCalledFromJS, aPositionSpecified,
+                               aSizeSpecified, aURI, aName, aFeatures,
+                               aWindowIsNew, aReturn);
+}
+
+nsresult
+ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
+                                  nsIDOMWindow* aParent,
+                                  bool aIframeMoz,
+                                  uint32_t aChromeFlags,
+                                  bool aCalledFromJS,
+                                  bool aPositionSpecified,
+                                  bool aSizeSpecified,
+                                  nsIURI* aURI,
+                                  const nsAString& aName,
+                                  const nsACString& aFeatures,
+                                  bool* aWindowIsNew,
+                                  nsIDOMWindow** aReturn)
+{
+    MOZ_ASSERT(aTabOpener);
+    *aReturn = nullptr;
+
+    const TabId openerTabId = aTabOpener->GetTabId();
+
+    PopupIPCTabContext context;
+    context.opener() = openerTabId;
+    context.isBrowserElement() = aTabOpener->IsBrowserElement();
+
+    IPCTabContext ipcContext(context);
+
+    TabId tabId;
+    SendAllocateTabId(openerTabId,
+                      ipcContext,
+                      GetID(),
+                      &tabId);
+
+    RefPtr<TabChild> newChild = new TabChild(this, tabId,
+                                             *aTabOpener, aChromeFlags);
+    if (NS_FAILED(newChild->Init())) {
+        return NS_ERROR_ABORT;
+    }
+
+    context.opener() = aTabOpener;
+    unused << SendPBrowserConstructor(
+        // We release this ref in DeallocPBrowserChild
+        RefPtr<TabChild>(newChild).forget().take(),
+        tabId, IPCTabContext(context), aChromeFlags,
+        GetID(), IsForApp(), IsForBrowser());
+
+    nsAutoCString url;
+    if (aURI) {
+        aURI->GetSpec(url);
+    } else {
+        // We can't actually send a nullptr up as the URI, since IPDL doesn't let us
+        // send nullptr's for primitives. We indicate that the nsString for the URI
+        // should be converted to a nullptr by voiding the string.
+        url.SetIsVoid(true);
+    }
+
+    nsString name(aName);
+    nsAutoCString features(aFeatures);
+    nsTArray<FrameScriptInfo> frameScripts;
+    nsCString urlToLoad;
+
+    if (aIframeMoz) {
+        MOZ_ASSERT(aTabOpener);
+        newChild->SendBrowserFrameOpenWindow(aTabOpener, NS_ConvertUTF8toUTF16(url), name,
+                                             NS_ConvertUTF8toUTF16(features),
+                                             aWindowIsNew);
+    } else {
+        nsCOMPtr<nsPIDOMWindow> opener = do_QueryInterface(aParent);
+        nsCOMPtr<nsIDocument> doc = opener->GetDoc();
+        nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
+        if (!baseURI) {
+            NS_ERROR("nsIDocument didn't return a base URI");
+            return NS_ERROR_FAILURE;
+        }
+
+        nsAutoCString baseURIString;
+        baseURI->GetSpec(baseURIString);
+
+        nsresult rv;
+        if (!SendCreateWindow(aTabOpener, newChild,
+                              aChromeFlags, aCalledFromJS, aPositionSpecified,
+                              aSizeSpecified, url,
+                              name, features,
+                              baseURIString,
+                              &rv,
+                              aWindowIsNew,
+                              &frameScripts,
+                              &urlToLoad)) {
+            return NS_ERROR_NOT_AVAILABLE;
+        }
+
+        if (NS_FAILED(rv)) {
+            return rv;
+        }
+    }
+    if (!*aWindowIsNew) {
+        PBrowserChild::Send__delete__(newChild);
+        return NS_ERROR_ABORT;
+    }
+
+    TextureFactoryIdentifier textureFactoryIdentifier;
+    uint64_t layersId = 0;
+    PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
+    newChild->SendGetRenderFrameInfo(renderFrame,
+                                     &textureFactoryIdentifier,
+                                     &layersId);
+    if (layersId == 0) { // if renderFrame is invalid.
+        PRenderFrameChild::Send__delete__(renderFrame);
+        renderFrame = nullptr;
+    }
+
+    // Unfortunately we don't get a window unless we've shown the frame.  That's
+    // pretty bogus; see bug 763602.
+    newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame);
+
+    for (size_t i = 0; i < frameScripts.Length(); i++) {
+        FrameScriptInfo& info = frameScripts[i];
+        if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
+            MOZ_CRASH();
+        }
+    }
+
+    if (!urlToLoad.IsEmpty()) {
+        newChild->RecvLoadURL(urlToLoad, BrowserConfiguration());
+    }
+
+    nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
+    win.forget(aReturn);
+    return NS_OK;
+}
+
 void
 ContentChild::GetProcessName(nsAString& aName)
 {
     aName.Assign(mProcessName);
 }
 
 bool
 ContentChild::IsAlive()
@@ -2735,17 +2885,18 @@ ContentChild::RecvShutdown()
 {
     if (mPolicy) {
         mPolicy->Deactivate();
         mPolicy = nullptr;
     }
 
     nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     if (os) {
-        os->NotifyObservers(this, "content-child-shutdown", nullptr);
+        os->NotifyObservers(static_cast<nsIContentChild*>(this),
+                            "content-child-shutdown", nullptr);
     }
 
     GetIPCChannel()->SetAbortOnError(false);
 
     // Ignore errors here. If this fails, the parent will kill us after a
     // timeout.
     unused << SendFinishShutdown();
     return true;
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -12,16 +12,17 @@
 #include "mozilla/dom/nsIContentChild.h"
 #include "mozilla/dom/PBrowserOrId.h"
 #include "mozilla/dom/PContentChild.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsTHashtable.h"
 
 #include "nsWeakPtr.h"
+#include "nsIWindowProvider.h"
 
 
 struct ChromePackage;
 class nsIObserver;
 struct SubstitutionMapping;
 struct OverrideMapping;
 class nsIDomainPolicy;
 
@@ -42,40 +43,57 @@ namespace dom {
 
 class AlertObserver;
 class ConsoleListener;
 class PStorageChild;
 class ClonedMessageData;
 class TabChild;
 
 class ContentChild final : public PContentChild
+                         , public nsIWindowProvider
                          , public nsIContentChild
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::ipc::OptionalURIParams OptionalURIParams;
     typedef mozilla::ipc::PFileDescriptorSetChild PFileDescriptorSetChild;
     typedef mozilla::ipc::URIParams URIParams;
 
 public:
+    NS_DECL_NSIWINDOWPROVIDER
+
     ContentChild();
     virtual ~ContentChild();
     NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
     NS_IMETHOD_(MozExternalRefCountType) AddRef(void) override { return 1; }
     NS_IMETHOD_(MozExternalRefCountType) Release(void) override { return 1; }
 
     struct AppInfo
     {
         nsCString version;
         nsCString buildID;
         nsCString name;
         nsCString UAName;
         nsCString ID;
         nsCString vendor;
     };
 
+    nsresult
+    ProvideWindowCommon(TabChild* aTabOpener,
+                        nsIDOMWindow* aOpener,
+                        bool aIframeMoz,
+                        uint32_t aChromeFlags,
+                        bool aCalledFromJS,
+                        bool aPositionSpecified,
+                        bool aSizeSpecified,
+                        nsIURI* aURI,
+                        const nsAString& aName,
+                        const nsACString& aFeatures,
+                        bool* aWindowIsNew,
+                        nsIDOMWindow** aReturn);
+
     bool Init(MessageLoop* aIOLoop,
               base::ProcessId aParentPid,
               IPC::Channel* aChannel);
     void InitProcessAttributes();
     void InitXPCOM();
     void InitGraphicsDeviceData();
 
     static ContentChild* GetSingleton() {
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/DebugOnly.h"
 
 #include "base/basictypes.h"
 
 #include "ContentParent.h"
+#include "TabParent.h"
 
 #if defined(ANDROID) || defined(LINUX)
 # include <sys/time.h>
 # include <sys/resource.h>
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include <sys/types.h>
@@ -139,17 +140,23 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsISiteSecurityService.h"
 #include "nsISpellChecker.h"
 #include "nsIStyleSheet.h"
 #include "nsISupportsPrimitives.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsITimer.h"
 #include "nsIURIFixup.h"
+#include "nsIWindowMediator.h"
+#include "nsIDocShellTreeOwner.h"
+#include "nsIXULWindow.h"
+#include "nsIDOMChromeWindow.h"
 #include "nsIWindowWatcher.h"
+#include "nsPIWindowWatcher.h"
+#include "nsWindowWatcher.h"
 #include "nsIXULRuntime.h"
 #include "gfxDrawable.h"
 #include "ImageOps.h"
 #include "mozilla/dom/nsMixedContentBlocker.h"
 #include "nsMemoryInfoDumper.h"
 #include "nsMemoryReporterManager.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStyleSheetService.h"
@@ -161,16 +168,17 @@
 #include "SandboxHal.h"
 #include "ScreenManagerParent.h"
 #include "SourceSurfaceRawData.h"
 #include "TabParent.h"
 #include "URIUtils.h"
 #include "nsIWebBrowserChrome.h"
 #include "nsIDocShell.h"
 #include "nsDocShell.h"
+#include "nsOpenURIInFrameParams.h"
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "gfxPrefs.h"
 #include "prio.h"
 #include "private/pprio.h"
 #include "ContentProcessManager.h"
 #include "mozilla/dom/ipc/StructuredCloneData.h"
 #include "mozilla/psm/PSMContentListener.h"
 #include "nsPluginHost.h"
@@ -5334,16 +5342,241 @@ ContentParent::AllocPWebBrowserPersistDo
 
 bool
 ContentParent::DeallocPWebBrowserPersistDocumentParent(PWebBrowserPersistDocumentParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+static already_AddRefed<nsPIDOMWindow>
+FindMostRecentOpenWindow()
+{
+    nsCOMPtr<nsIWindowMediator> windowMediator =
+        do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
+    nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
+    windowMediator->GetEnumerator(MOZ_UTF16("navigator:browser"),
+                                  getter_AddRefs(windowEnumerator));
+
+    nsCOMPtr<nsPIDOMWindow> latest;
+
+    bool hasMore = false;
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
+    while (hasMore) {
+        nsCOMPtr<nsISupports> item;
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->GetNext(getter_AddRefs(item))));
+        nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(item);
+
+        if (window && !window->Closed()) {
+            latest = window;
+        }
+
+        MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
+    }
+
+    return latest.forget();
+}
+
+bool
+ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
+                                PBrowserParent* aNewTab,
+                                const uint32_t& aChromeFlags,
+                                const bool& aCalledFromJS,
+                                const bool& aPositionSpecified,
+                                const bool& aSizeSpecified,
+                                const nsCString& aURI,
+                                const nsString& aName,
+                                const nsCString& aFeatures,
+                                const nsCString& aBaseURI,
+                                nsresult* aResult,
+                                bool* aWindowIsNew,
+                                InfallibleTArray<FrameScriptInfo>* aFrameScripts,
+                                nsCString* aURLToLoad)
+{
+    // We always expect to open a new window here. If we don't, it's an error.
+    *aWindowIsNew = true;
+
+    // The content process should never be in charge of computing whether or
+    // not a window should be private or remote - the parent will do that.
+    MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW));
+    MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW));
+    MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME));
+    MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
+
+    TabParent* thisTabParent = TabParent::GetFrom(aThisTab);
+    MOZ_ASSERT(thisTabParent);
+
+    if (NS_WARN_IF(thisTabParent->IsBrowserOrApp())) {
+        return false;
+    }
+
+    nsCOMPtr<nsPIWindowWatcher> pwwatch =
+        do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
+
+    if (NS_WARN_IF(NS_FAILED(*aResult))) {
+        return true;
+    }
+
+    TabParent* newTab = TabParent::GetFrom(aNewTab);
+    MOZ_ASSERT(newTab);
+
+    // Content has requested that we open this new content window, so
+    // we must have an opener.
+    newTab->SetHasContentOpener(true);
+
+    nsCOMPtr<nsIContent> frame(do_QueryInterface(thisTabParent->GetOwnerElement()));
+
+    nsCOMPtr<nsPIDOMWindow> parent;
+    if (frame) {
+        parent = frame->OwnerDoc()->GetWindow();
+
+        // If our chrome window is in the process of closing, don't try to open a
+        // new tab in it.
+        if (parent && parent->Closed()) {
+            parent = nullptr;
+        }
+    }
+
+    nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin = thisTabParent->GetBrowserDOMWindow();
+
+    // If we haven't found a chrome window to open in, just use the most recently
+    // opened one.
+    if (!parent) {
+        parent = FindMostRecentOpenWindow();
+        if (NS_WARN_IF(!parent)) {
+            *aResult = NS_ERROR_FAILURE;
+            return true;
+        }
+
+        nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(parent);
+        if (rootChromeWin) {
+            rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
+        }
+    }
+
+    int32_t openLocation =
+        nsWindowWatcher::GetWindowOpenLocation(parent, aChromeFlags, aCalledFromJS,
+                                               aPositionSpecified, aSizeSpecified);
+
+    MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
+               openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
+
+    // Opening new tabs is the easy case...
+    if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
+        if (NS_WARN_IF(!browserDOMWin)) {
+            *aResult = NS_ERROR_FAILURE;
+            return true;
+        }
+
+        bool isPrivate = false;
+        nsCOMPtr<nsILoadContext> loadContext = thisTabParent->GetLoadContext();
+        loadContext->GetUsePrivateBrowsing(&isPrivate);
+
+        nsCOMPtr<nsIOpenURIInFrameParams> params = new nsOpenURIInFrameParams();
+        params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
+        params->SetIsPrivate(isPrivate);
+
+        TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
+
+        nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
+        browserDOMWin->OpenURIInFrame(nullptr, params,
+                                      openLocation,
+                                      nsIBrowserDOMWindow::OPEN_NEW,
+                                      getter_AddRefs(frameLoaderOwner));
+        if (!frameLoaderOwner) {
+            *aWindowIsNew = false;
+        }
+
+        newTab->SwapFrameScriptsFrom(*aFrameScripts);
+        return true;
+    }
+
+    // WindowWatcher is going to expect a valid URI to open a window
+    // to. If it can't find one, it's going to attempt to figure one
+    // out on its own, which is problematic because it can't access
+    // the document for the remote browser we're opening. Luckily,
+    // TabChild has sent us a baseURI with which we can ensure that
+    // the URI we pass to WindowWatcher is valid.
+    nsCOMPtr<nsIURI> baseURI;
+    *aResult = NS_NewURI(getter_AddRefs(baseURI), aBaseURI);
+
+    if (NS_WARN_IF(NS_FAILED(*aResult))) {
+        return true;
+    }
+
+    nsAutoCString finalURIString;
+    if (!aURI.IsEmpty()) {
+        nsCOMPtr<nsIURI> finalURI;
+        *aResult = NS_NewURI(getter_AddRefs(finalURI), aURI.get(), baseURI);
+
+        if (NS_WARN_IF(NS_FAILED(*aResult))) {
+            return true;
+        }
+
+        finalURI->GetSpec(finalURIString);
+    }
+
+    nsCOMPtr<nsIDOMWindow> window;
+
+    TabParent::AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
+
+    // If nsWindowWatcher::OpenWindowInternal was passed a nullptr for the URI
+    // to open in the content process, we indicate that by sending up a voided
+    // nsString (since primitives are not nullable). If we detect the voided
+    // nsString, we know that we need to send OpenWindow2 a nullptr for the URI.
+    const char* uri = aURI.IsVoid() ? nullptr : finalURIString.get();
+    const char* name = aName.IsVoid() ? nullptr : NS_ConvertUTF16toUTF8(aName).get();
+    const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
+
+    *aResult = pwwatch->OpenWindow2(parent, uri, name, features, aCalledFromJS,
+                                    false, false, thisTabParent, nullptr, getter_AddRefs(window));
+
+    if (NS_WARN_IF(NS_FAILED(*aResult))) {
+        return true;
+    }
+
+    *aResult = NS_ERROR_FAILURE;
+
+    nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(window);
+    if (NS_WARN_IF(!pwindow)) {
+        return true;
+    }
+
+    nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
+    if (NS_WARN_IF(!windowDocShell)) {
+        return true;
+    }
+
+    nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
+    windowDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
+
+    nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(treeOwner);
+    if (NS_WARN_IF(!xulWin)) {
+        return true;
+    }
+
+    nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
+    xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
+    if (NS_WARN_IF(!xulBrowserWin)) {
+        return true;
+    }
+
+    nsCOMPtr<nsITabParent> newRemoteTab;
+    *aResult = xulBrowserWin->ForceInitialBrowserRemote(getter_AddRefs(newRemoteTab));
+
+    if (NS_WARN_IF(NS_FAILED(*aResult))) {
+        return true;
+    }
+
+    MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
+
+    newTab->SwapFrameScriptsFrom(*aFrameScripts);
+    return true;
+}
+
 /* static */ bool
 ContentParent::PermissionManagerAddref(const ContentParentId& aCpId,
                                        const TabId& aTabId)
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
              "Call PermissionManagerAddref in content process!");
   ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
   uint32_t appId = cpm->GetAppIdByProcessAndTabId(aCpId, aTabId);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -429,16 +429,31 @@ public:
 
     virtual bool HandleWindowsMessages(const Message& aMsg) const override;
 
     bool HasGamepadListener() const { return mHasGamepadListener; }
 
     void SetNuwaParent(NuwaParent* aNuwaParent) { mNuwaParent = aNuwaParent; }
     void ForkNewProcess(bool aBlocking);
 
+    virtual bool RecvCreateWindow(PBrowserParent* aThisTabParent,
+                                  PBrowserParent* aOpener,
+                                  const uint32_t& aChromeFlags,
+                                  const bool& aCalledFromJS,
+                                  const bool& aPositionSpecified,
+                                  const bool& aSizeSpecified,
+                                  const nsCString& aURI,
+                                  const nsString& aName,
+                                  const nsCString& aFeatures,
+                                  const nsCString& aBaseURI,
+                                  nsresult* aResult,
+                                  bool* aWindowIsNew,
+                                  InfallibleTArray<FrameScriptInfo>* aFrameScripts,
+                                  nsCString* aURLToLoad) override;
+
 protected:
     void OnChannelConnected(int32_t pid) override;
     virtual void ActorDestroy(ActorDestroyReason why) override;
     void OnNuwaForkTimeout();
 
     bool ShouldContinueFromReplyTimeout() override;
 
 private:
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -89,22 +89,16 @@ struct ShowInfo
 {
   nsString name;
   bool fullscreenAllowed;
   bool isPrivate;
   float dpi;
   double defaultScale;
 };
 
-struct FrameScriptInfo
-{
-    nsString url;
-    bool runInGlobalScope;
-};
-
 prio(normal upto urgent) sync protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDocAccessible;
     manages PDocumentRenderer;
     manages PFilePicker;
@@ -160,30 +154,16 @@ parent:
     /**
      * When child sends this message, parent should move focus to
      * the next or previous focusable element or document.
      */
     MoveFocus(bool forward, bool forDocumentNavigation);
 
     Event(RemoteDOMEvent aEvent);
 
-    sync CreateWindow(PBrowser aNewTab,
-                      uint32_t aChromeFlags,
-                      bool aCalledFromJS,
-                      bool aPositionSpecified,
-                      bool aSizeSpecified,
-                      nsCString aURI,
-                      nsString aName,
-                      nsCString aFeatures,
-                      nsCString aBaseURI)
-      returns (nsresult rv,
-               bool windowOpened,
-               FrameScriptInfo[] frameScripts,
-               nsCString urlToLoad);
-
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
                                CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -405,16 +405,22 @@ struct GamepadButtonInformation {
 
 union GamepadChangeEvent {
     GamepadAdded;
     GamepadRemoved;
     GamepadAxisInformation;
     GamepadButtonInformation;
 };
 
+struct FrameScriptInfo
+{
+    nsString url;
+    bool runInGlobalScope;
+};
+
 prio(normal upto urgent) sync protocol PContent
 {
     parent spawns PPluginModule;
 
     parent opens PCompositor;
     parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PImageBridge;
@@ -1102,16 +1108,31 @@ parent:
     async Profile(nsCString aProfile);
 
     /**
      * Request graphics initialization information from the parent.
      */
     sync GetGraphicsDeviceInitData()
         returns (DeviceInitData aData);
 
+    sync CreateWindow(PBrowser aThisTab,
+                      PBrowser aNewTab,
+                      uint32_t aChromeFlags,
+                      bool aCalledFromJS,
+                      bool aPositionSpecified,
+                      bool aSizeSpecified,
+                      nsCString aURI,
+                      nsString aName,
+                      nsCString aFeatures,
+                      nsCString aBaseURI)
+      returns (nsresult rv,
+               bool windowOpened,
+               FrameScriptInfo[] frameScripts,
+               nsCString urlToLoad);
+
     sync GetDeviceStorageLocation(nsString type)
         returns (nsString path);
 
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -1110,159 +1110,29 @@ TabChild::ProvideWindow(nsIDOMWindow* aP
         *aWindowIsNew = false;
         return browser->GetContentDOMWindow(aReturn);
       }
     }
 
     // Note that ProvideWindowCommon may return NS_ERROR_ABORT if the
     // open window call was canceled.  It's important that we pass this error
     // code back to our caller.
-    return ProvideWindowCommon(aParent,
-                               iframeMoz,
-                               aChromeFlags,
-                               aCalledFromJS,
-                               aPositionSpecified,
-                               aSizeSpecified,
-                               aURI,
-                               aName,
-                               aFeatures,
-                               aWindowIsNew,
-                               aReturn);
-}
-
-nsresult
-TabChild::ProvideWindowCommon(nsIDOMWindow* aOpener,
-                              bool aIframeMoz,
-                              uint32_t aChromeFlags,
-                              bool aCalledFromJS,
-                              bool aPositionSpecified,
-                              bool aSizeSpecified,
-                              nsIURI* aURI,
-                              const nsAString& aName,
-                              const nsACString& aFeatures,
-                              bool* aWindowIsNew,
-                              nsIDOMWindow** aReturn)
-{
-  *aReturn = nullptr;
-
-  ContentChild* cc = ContentChild::GetSingleton();
-  const TabId openerTabId = GetTabId();
-
-  // We must use PopupIPCTabContext here; ContentParent will not accept the
-  // result of this->AsIPCTabContext() (which will be a
-  // BrowserFrameIPCTabContext or an AppFrameIPCTabContext), for security
-  // reasons.
-  PopupIPCTabContext context;
-  context.opener() = openerTabId;
-  context.isBrowserElement() = IsBrowserElement();
-
-  IPCTabContext ipcContext(context);
-
-  TabId tabId;
-  cc->SendAllocateTabId(openerTabId,
-                        ipcContext,
-                        cc->GetID(),
-                        &tabId);
-
-  RefPtr<TabChild> newChild = new TabChild(ContentChild::GetSingleton(), tabId,
-                                             /* TabContext */ *this, aChromeFlags);
-  if (NS_FAILED(newChild->Init())) {
-    return NS_ERROR_ABORT;
-  }
-
-  context.opener() = this;
-  unused << Manager()->SendPBrowserConstructor(
-      // We release this ref in DeallocPBrowserChild
-      RefPtr<TabChild>(newChild).forget().take(),
-      tabId, IPCTabContext(context), aChromeFlags,
-      cc->GetID(), cc->IsForApp(), cc->IsForBrowser());
-
-  nsAutoCString url;
-  if (aURI) {
-    aURI->GetSpec(url);
-  } else {
-    // We can't actually send a nullptr up as the URI, since IPDL doesn't let us
-    // send nullptr's for primitives. We indicate that the nsString for the URI
-    // should be converted to a nullptr by voiding the string.
-    url.SetIsVoid(true);
-  }
-
-  nsString name(aName);
-  nsAutoCString features(aFeatures);
-  nsTArray<FrameScriptInfo> frameScripts;
-  nsCString urlToLoad;
-
-  if (aIframeMoz) {
-    newChild->SendBrowserFrameOpenWindow(this, NS_ConvertUTF8toUTF16(url), name,
-                                         NS_ConvertUTF8toUTF16(features),
-                                         aWindowIsNew);
-  } else {
-    nsCOMPtr<nsPIDOMWindow> opener = do_QueryInterface(aOpener);
-    nsCOMPtr<nsIDocument> doc = opener->GetDoc();
-    nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
-    if (!baseURI) {
-      NS_ERROR("nsIDocument didn't return a base URI");
-      return NS_ERROR_FAILURE;
-    }
-
-    nsAutoCString baseURIString;
-    baseURI->GetSpec(baseURIString);
-
-    nsresult rv;
-
-    if (!SendCreateWindow(newChild,
-                          aChromeFlags, aCalledFromJS, aPositionSpecified,
-                          aSizeSpecified, url,
-                          name, features,
-                          baseURIString,
-                          &rv,
-                          aWindowIsNew,
-                          &frameScripts,
-                          &urlToLoad)) {
-      return NS_ERROR_NOT_AVAILABLE;
-    }
-
-    if (NS_FAILED(rv)) {
-      return rv;
-    }
-  }
-  if (!*aWindowIsNew) {
-    PBrowserChild::Send__delete__(newChild);
-    return NS_ERROR_ABORT;
-  }
-
-  TextureFactoryIdentifier textureFactoryIdentifier;
-  uint64_t layersId = 0;
-  PRenderFrameChild* renderFrame = newChild->SendPRenderFrameConstructor();
-  newChild->SendGetRenderFrameInfo(renderFrame,
-                                   &textureFactoryIdentifier,
-                                   &layersId);
-  if (layersId == 0) { // if renderFrame is invalid.
-    PRenderFrameChild::Send__delete__(renderFrame);
-    renderFrame = nullptr;
-  }
-
-  // Unfortunately we don't get a window unless we've shown the frame.  That's
-  // pretty bogus; see bug 763602.
-  newChild->DoFakeShow(textureFactoryIdentifier, layersId, renderFrame);
-
-  for (size_t i = 0; i < frameScripts.Length(); i++) {
-    FrameScriptInfo& info = frameScripts[i];
-    if (!newChild->RecvLoadRemoteScript(info.url(), info.runInGlobalScope())) {
-      MOZ_CRASH();
-    }
-  }
-
-  if (!urlToLoad.IsEmpty()) {
-    newChild->RecvLoadURL(urlToLoad, BrowserConfiguration());
-  }
-
-  nsCOMPtr<nsIDOMWindow> win = do_GetInterface(newChild->WebNavigation());
-  win.forget(aReturn);
-  return NS_OK;
+    ContentChild* cc = ContentChild::GetSingleton();
+    return cc->ProvideWindowCommon(this,
+                                   aParent,
+                                   iframeMoz,
+                                   aChromeFlags,
+                                   aCalledFromJS,
+                                   aPositionSpecified,
+                                   aSizeSpecified,
+                                   aURI,
+                                   aName,
+                                   aFeatures,
+                                   aWindowIsNew,
+                                   aReturn);
 }
 
 void
 TabChild::DestroyWindow()
 {
     nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
     if (baseWindow)
         baseWindow->Destroy();
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -236,16 +236,26 @@ public:
     /**
      * Find TabChild of aTabId in the same content process of the
      * caller.
      */
     static already_AddRefed<TabChild> FindTabChild(const TabId& aTabId);
 
 public:
     /**
+     * Create a new TabChild object.
+     */
+    TabChild(nsIContentChild* aManager,
+             const TabId& aTabId,
+             const TabContext& aContext,
+             uint32_t aChromeFlags);
+
+    nsresult Init();
+
+    /**
      * This is expected to be called off the critical path to content
      * startup.  This is an opportunity to load things that are slow
      * on the critical path.
      */
     static void PreloadSlowThings();
 
     /** Return a TabChild with the given attributes. */
     static already_AddRefed<TabChild>
@@ -505,16 +515,21 @@ public:
     bool ParentIsActive()
     {
       return mParentIsActive;
     }
     bool AsyncPanZoomEnabled() { return mAsyncPanZoomEnabled; }
 
     virtual ScreenIntSize GetInnerSize() override;
 
+    // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
+    void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
+                    const uint64_t& aLayersId,
+                    PRenderFrameChild* aRenderFrame);
+
 protected:
     virtual ~TabChild();
 
     virtual PRenderFrameChild* AllocPRenderFrameChild() override;
     virtual bool DeallocPRenderFrameChild(PRenderFrameChild* aFrame) override;
     virtual bool RecvDestroy() override;
     virtual bool RecvSetUpdateHitRegion(const bool& aEnabled) override;
     virtual bool RecvSetDocShellIsActive(const bool& aIsActive) override;
@@ -530,26 +545,16 @@ protected:
     virtual bool RecvMenuKeyboardListenerInstalled(
                    const bool& aInstalled) override;
 
 #ifdef MOZ_WIDGET_GONK
     void MaybeRequestPreinitCamera();
 #endif
 
 private:
-    /**
-     * Create a new TabChild object.
-     */
-    TabChild(nsIContentChild* aManager,
-             const TabId& aTabId,
-             const TabContext& aContext,
-             uint32_t aChromeFlags);
-
-    nsresult Init();
-
     class DelayedFireContextMenuEvent;
 
     // Notify others that our TabContext has been updated.  (At the moment, this
     // sets the appropriate app-id and is-browser flags on our docshell.)
     //
     // You should call this after calling TabContext::SetTabContext().  We also
     // call this during Init().
     void NotifyTabContextUpdated();
@@ -559,46 +564,28 @@ private:
     enum FrameScriptLoading { DONT_LOAD_SCRIPTS, DEFAULT_LOAD_SCRIPTS };
     bool InitTabChildGlobal(FrameScriptLoading aScriptLoading = DEFAULT_LOAD_SCRIPTS);
     bool InitRenderingState(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
                             const uint64_t& aLayersId,
                             PRenderFrameChild* aRenderFrame);
     void DestroyWindow();
     void SetProcessNameToAppName();
 
-    // Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
-    void DoFakeShow(const TextureFactoryIdentifier& aTextureFactoryIdentifier,
-                    const uint64_t& aLayersId,
-                    PRenderFrameChild* aRenderFrame);
-
     void ApplyShowInfo(const ShowInfo& aInfo);
 
     // These methods are used for tracking synthetic mouse events
     // dispatched for compatibility.  On each touch event, we
     // UpdateTapState().  If we've detected that the current gesture
     // isn't a tap, then we CancelTapTracking().  In the meantime, we
     // may detect a context-menu event, and if so we
     // FireContextMenuEvent().
     void FireContextMenuEvent();
     void CancelTapTracking();
     void UpdateTapState(const WidgetTouchEvent& aEvent, nsEventStatus aStatus);
 
-    nsresult
-    ProvideWindowCommon(nsIDOMWindow* aOpener,
-                        bool aIframeMoz,
-                        uint32_t aChromeFlags,
-                        bool aCalledFromJS,
-                        bool aPositionSpecified,
-                        bool aSizeSpecified,
-                        nsIURI* aURI,
-                        const nsAString& aName,
-                        const nsACString& aFeatures,
-                        bool* aWindowIsNew,
-                        nsIDOMWindow** aReturn);
-
     bool HasValidInnerSize();
 
     void SetTabId(const TabId& aTabId);
 
     ScreenIntRect GetOuterRect();
 
     void SetUnscaledInnerSize(const CSSSize& aSize) {
       mUnscaledInnerSize = aSize;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -45,47 +45,40 @@
 #include "nsContentUtils.h"
 #include "nsDebug.h"
 #include "nsFocusManager.h"
 #include "nsFrameLoader.h"
 #include "nsIBaseWindow.h"
 #include "nsIContent.h"
 #include "nsIDocShell.h"
 #include "nsIDocShellTreeOwner.h"
-#include "nsIDOMChromeWindow.h"
 #include "nsIDOMElement.h"
 #include "nsIDOMEvent.h"
 #include "nsIDOMWindow.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadInfo.h"
 #include "nsPrincipal.h"
 #include "nsIPromptFactory.h"
 #include "nsIURI.h"
 #include "nsIWebBrowserChrome.h"
-#include "nsIWindowCreator2.h"
 #include "nsIXULBrowserWindow.h"
 #include "nsIXULWindow.h"
 #include "nsIRemoteBrowser.h"
 #include "nsViewManager.h"
 #include "nsVariant.h"
 #include "nsIWidget.h"
-#include "nsIWindowMediator.h"
-#include "nsIWindowWatcher.h"
 #ifndef XP_WIN
 #include "nsJARProtocolHandler.h"
 #endif
-#include "nsOpenURIInFrameParams.h"
 #include "nsPIDOMWindow.h"
-#include "nsPIWindowWatcher.h"
 #include "nsPresShell.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
-#include "nsWindowWatcher.h"
 #include "private/pprio.h"
 #include "PermissionMessageUtils.h"
 #include "StructuredCloneData.h"
 #include "ColorPickerParent.h"
 #include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
@@ -718,263 +711,16 @@ TabParent::RecvEvent(const RemoteDOMEven
 
   event->SetOwner(target);
 
   bool dummy;
   target->DispatchEvent(event, &dummy);
   return true;
 }
 
-struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
-{
-public:
-  AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew, nsCString* aURLToLoad)
-   : mNewTab(aNewTab), mWindowIsNew(aWindowIsNew), mURLToLoad(aURLToLoad)
-  {
-    MOZ_ASSERT(!TabParent::sNextTabParent);
-    MOZ_ASSERT(!aNewTab->mCreatingWindow);
-
-    TabParent::sNextTabParent = aNewTab;
-    aNewTab->mCreatingWindow = true;
-    aNewTab->mDelayedURL.Truncate();
-  }
-
-  ~AutoUseNewTab()
-  {
-    mNewTab->mCreatingWindow = false;
-    *mURLToLoad = mNewTab->mDelayedURL;
-
-    if (TabParent::sNextTabParent) {
-      MOZ_ASSERT(TabParent::sNextTabParent == mNewTab);
-      TabParent::sNextTabParent = nullptr;
-      *mWindowIsNew = false;
-    }
-  }
-
-private:
-  TabParent* mNewTab;
-  bool* mWindowIsNew;
-  nsCString* mURLToLoad;
-};
-
-static already_AddRefed<nsPIDOMWindow>
-FindMostRecentOpenWindow()
-{
-  nsCOMPtr<nsIWindowMediator> windowMediator =
-    do_GetService(NS_WINDOWMEDIATOR_CONTRACTID);
-  nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
-  windowMediator->GetEnumerator(MOZ_UTF16("navigator:browser"),
-                                getter_AddRefs(windowEnumerator));
-
-  nsCOMPtr<nsPIDOMWindow> latest;
-
-  bool hasMore = false;
-  MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
-  while (hasMore) {
-    nsCOMPtr<nsISupports> item;
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->GetNext(getter_AddRefs(item))));
-    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(item);
-
-    if (window && !window->Closed()) {
-      latest = window;
-    }
-
-    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(windowEnumerator->HasMoreElements(&hasMore)));
-  }
-
-  return latest.forget();
-}
-
-bool
-TabParent::RecvCreateWindow(PBrowserParent* aNewTab,
-                            const uint32_t& aChromeFlags,
-                            const bool& aCalledFromJS,
-                            const bool& aPositionSpecified,
-                            const bool& aSizeSpecified,
-                            const nsCString& aURI,
-                            const nsString& aName,
-                            const nsCString& aFeatures,
-                            const nsCString& aBaseURI,
-                            nsresult* aResult,
-                            bool* aWindowIsNew,
-                            InfallibleTArray<FrameScriptInfo>* aFrameScripts,
-                            nsCString* aURLToLoad)
-{
-  // We always expect to open a new window here. If we don't, it's an error.
-  *aWindowIsNew = true;
-
-  // The content process should never be in charge of computing whether or
-  // not a window should be private or remote - the parent will do that.
-  MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_WINDOW));
-  MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_NON_PRIVATE_WINDOW));
-  MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_PRIVATE_LIFETIME));
-  MOZ_ASSERT(!(aChromeFlags & nsIWebBrowserChrome::CHROME_REMOTE_WINDOW));
-
-  if (NS_WARN_IF(IsBrowserOrApp()))
-    return false;
-
-  nsCOMPtr<nsPIWindowWatcher> pwwatch =
-    do_GetService(NS_WINDOWWATCHER_CONTRACTID, aResult);
-
-  if (NS_WARN_IF(NS_FAILED(*aResult)))
-    return true;
-
-  TabParent* newTab = TabParent::GetFrom(aNewTab);
-  MOZ_ASSERT(newTab);
-
-  // Content has requested that we open this new content window, so
-  // we must have an opener.
-  newTab->SetHasContentOpener(true);
-
-  nsCOMPtr<nsIContent> frame(do_QueryInterface(mFrameElement));
-
-  nsCOMPtr<nsPIDOMWindow> parent;
-  if (frame) {
-    parent = frame->OwnerDoc()->GetWindow();
-
-    // If our chrome window is in the process of closing, don't try to open a
-    // new tab in it.
-    if (parent && parent->Closed()) {
-      parent = nullptr;
-    }
-  }
-
-  nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin = mBrowserDOMWindow;
-
-  // If we haven't found a chrome window to open in, just use the most recently
-  // opened one.
-  if (!parent) {
-    parent = FindMostRecentOpenWindow();
-    if (NS_WARN_IF(!parent)) {
-      *aResult = NS_ERROR_FAILURE;
-      return true;
-    }
-
-    nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(parent);
-    if (rootChromeWin) {
-      rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
-    }
-  }
-
-  int32_t openLocation =
-    nsWindowWatcher::GetWindowOpenLocation(parent, aChromeFlags, aCalledFromJS,
-                                           aPositionSpecified, aSizeSpecified);
-
-  MOZ_ASSERT(openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB ||
-             openLocation == nsIBrowserDOMWindow::OPEN_NEWWINDOW);
-
-  // Opening new tabs is the easy case...
-  if (openLocation == nsIBrowserDOMWindow::OPEN_NEWTAB) {
-    if (NS_WARN_IF(!browserDOMWin)) {
-      *aResult = NS_ERROR_FAILURE;
-      return true;
-    }
-
-    bool isPrivate;
-    nsCOMPtr<nsILoadContext> loadContext = GetLoadContext();
-    loadContext->GetUsePrivateBrowsing(&isPrivate);
-
-    nsCOMPtr<nsIOpenURIInFrameParams> params = new nsOpenURIInFrameParams();
-    params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
-    params->SetIsPrivate(isPrivate);
-
-    AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
-
-    nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
-    browserDOMWin->OpenURIInFrame(nullptr, params,
-                                  openLocation,
-                                  nsIBrowserDOMWindow::OPEN_NEW,
-                                  getter_AddRefs(frameLoaderOwner));
-    if (!frameLoaderOwner) {
-      *aWindowIsNew = false;
-    }
-
-    aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
-    return true;
-  }
-
-  // WindowWatcher is going to expect a valid URI to open a window
-  // to. If it can't find one, it's going to attempt to figure one
-  // out on its own, which is problematic because it can't access
-  // the document for the remote browser we're opening. Luckily,
-  // TabChild has sent us a baseURI with which we can ensure that
-  // the URI we pass to WindowWatcher is valid.
-  nsCOMPtr<nsIURI> baseURI;
-  *aResult = NS_NewURI(getter_AddRefs(baseURI), aBaseURI);
-
-  if (NS_WARN_IF(NS_FAILED(*aResult)))
-    return true;
-
-  nsAutoCString finalURIString;
-  if (!aURI.IsEmpty()) {
-    nsCOMPtr<nsIURI> finalURI;
-    *aResult = NS_NewURI(getter_AddRefs(finalURI), aURI.get(), baseURI);
-
-    if (NS_WARN_IF(NS_FAILED(*aResult)))
-      return true;
-
-    finalURI->GetSpec(finalURIString);
-  }
-
-  nsCOMPtr<nsIDOMWindow> window;
-
-  AutoUseNewTab aunt(newTab, aWindowIsNew, aURLToLoad);
-
-  // If nsWindowWatcher::OpenWindowInternal was passed a nullptr for the URI
-  // to open in the content process, we indicate that by sending up a voided
-  // nsString (since primitives are not nullable). If we detect the voided
-  // nsString, we know that we need to send OpenWindow2 a nullptr for the URI.
-  const char* uri = aURI.IsVoid() ? nullptr : finalURIString.get();
-  const char* name = aName.IsVoid() ? nullptr : NS_ConvertUTF16toUTF8(aName).get();
-  const char* features = aFeatures.IsVoid() ? nullptr : aFeatures.get();
-
-  *aResult = pwwatch->OpenWindow2(parent, uri, name, features, aCalledFromJS,
-                                  false, false, this, nullptr, getter_AddRefs(window));
-
-  if (NS_WARN_IF(NS_FAILED(*aResult)))
-    return true;
-
-  *aResult = NS_ERROR_FAILURE;
-
-  nsCOMPtr<nsPIDOMWindow> pwindow = do_QueryInterface(window);
-  if (NS_WARN_IF(!pwindow)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIDocShell> windowDocShell = pwindow->GetDocShell();
-  if (NS_WARN_IF(!windowDocShell)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
-  windowDocShell->GetTreeOwner(getter_AddRefs(treeOwner));
-
-  nsCOMPtr<nsIXULWindow> xulWin = do_GetInterface(treeOwner);
-  if (NS_WARN_IF(!xulWin)) {
-    return true;
-  }
-
-  nsCOMPtr<nsIXULBrowserWindow> xulBrowserWin;
-  xulWin->GetXULBrowserWindow(getter_AddRefs(xulBrowserWin));
-  if (NS_WARN_IF(!xulBrowserWin)) {
-    return true;
-  }
-
-  nsCOMPtr<nsITabParent> newRemoteTab;
-  *aResult = xulBrowserWin->ForceInitialBrowserRemote(getter_AddRefs(newRemoteTab));
-
-  if (NS_WARN_IF(NS_FAILED(*aResult)))
-    return true;
-
-  MOZ_ASSERT(TabParent::GetFrom(newRemoteTab) == newTab);
-
-  aFrameScripts->SwapElements(newTab->mDelayedFrameScripts);
-  return true;
-}
-
 TabParent* TabParent::sNextTabParent;
 
 /* static */ TabParent*
 TabParent::GetNextTabParent()
 {
   TabParent* result = sNextTabParent;
   sNextTabParent = nullptr;
   return result;
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_tabs_TabParent_h
 #define mozilla_tabs_TabParent_h
 
 #include "js/TypeDecls.h"
 #include "mozilla/ContentCache.h"
 #include "mozilla/dom/ipc/IdType.h"
 #include "mozilla/dom/PBrowserParent.h"
+#include "mozilla/dom/PContent.h"
 #include "mozilla/dom/PFilePickerParent.h"
 #include "mozilla/dom/TabContext.h"
 #include "mozilla/EventForwards.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIBrowserDOMWindow.h"
@@ -88,16 +89,19 @@ class TabParent final : public PBrowserP
                       , public nsIWebBrowserPersistable
 {
     typedef mozilla::dom::ClonedMessageData ClonedMessageData;
     typedef mozilla::layers::AsyncDragMetrics AsyncDragMetrics;
 
     virtual ~TabParent();
 
 public:
+    // Helper class for ContentParent::RecvCreateWindow.
+    struct AutoUseNewTab;
+
     // nsITabParent
     NS_DECL_NSITABPARENT
     // nsIDOMEventListener interfaces
     NS_DECL_NSIDOMEVENTLISTENER
 
     TabParent(nsIContentParent* aManager,
               const TabId& aTabId,
               const TabContext& aContext,
@@ -120,16 +124,22 @@ public:
      */
     bool IsVisible();
 
     nsIBrowserDOMWindow *GetBrowserDOMWindow() { return mBrowserDOMWindow; }
     void SetBrowserDOMWindow(nsIBrowserDOMWindow* aBrowserDOMWindow) {
         mBrowserDOMWindow = aBrowserDOMWindow;
     }
 
+    void SetHasContentOpener(bool aHasContentOpener);
+
+    void SwapFrameScriptsFrom(nsTArray<FrameScriptInfo>& aFrameScripts) {
+        aFrameScripts.SwapElements(mDelayedFrameScripts);
+    }
+
     already_AddRefed<nsILoadContext> GetLoadContext();
     already_AddRefed<nsIWidget> GetTopLevelWidget();
     nsIXULBrowserWindow* GetXULBrowserWindow();
 
     void Destroy();
     void Detach();
     void Attach(nsFrameLoader* aFrameLoader);
 
@@ -142,29 +152,16 @@ public:
     virtual bool RecvEvent(const RemoteDOMEvent& aEvent) override;
     virtual bool RecvReplyKeyEvent(const WidgetKeyboardEvent& aEvent) override;
     virtual bool RecvDispatchAfterKeyboardEvent(const WidgetKeyboardEvent& aEvent) override;
     virtual bool RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                             const nsString& aURL,
                                             const nsString& aName,
                                             const nsString& aFeatures,
                                             bool* aOutWindowOpened) override;
-    virtual bool RecvCreateWindow(PBrowserParent* aOpener,
-                                  const uint32_t& aChromeFlags,
-                                  const bool& aCalledFromJS,
-                                  const bool& aPositionSpecified,
-                                  const bool& aSizeSpecified,
-                                  const nsCString& aURI,
-                                  const nsString& aName,
-                                  const nsCString& aFeatures,
-                                  const nsCString& aBaseURI,
-                                  nsresult* aResult,
-                                  bool* aWindowIsNew,
-                                  InfallibleTArray<FrameScriptInfo>* aFrameScripts,
-                                  nsCString* aURLToLoad) override;
     virtual bool RecvSyncMessage(const nsString& aMessage,
                                  const ClonedMessageData& aData,
                                  InfallibleTArray<CpowEntry>&& aCpows,
                                  const IPC::Principal& aPrincipal,
                                  nsTArray<ipc::StructuredCloneData>* aRetVal) override;
     virtual bool RecvRpcMessage(const nsString& aMessage,
                                 const ClonedMessageData& aData,
                                 InfallibleTArray<CpowEntry>&& aCpows,
@@ -492,18 +489,16 @@ protected:
                                    const int32_t& aCx, const int32_t& aCy) override;
 
     virtual bool RecvAudioChannelActivityNotification(const uint32_t& aAudioChannel,
                                                       const bool& aActive) override;
 
     bool InitBrowserConfiguration(const nsCString& aURI,
                                   BrowserConfiguration& aConfiguration);
 
-    void SetHasContentOpener(bool aHasContentOpener);
-
     // Decide whether we have to use a new process to reload the URI associated
     // with the given channel.
     bool ShouldSwitchProcess(nsIChannel* aChannel);
 
     ContentCacheInParent mContentCache;
 
     nsIntRect mRect;
     ScreenIntSize mDimensions;
@@ -579,19 +574,16 @@ private:
 
     // We keep a strong reference to the frameloader after we've sent the
     // Destroy message and before we've received __delete__. This allows us to
     // dispatch message manager messages during this time.
     RefPtr<nsFrameLoader> mFrameLoader;
 
     TabId mTabId;
 
-    // Helper class for RecvCreateWindow.
-    struct AutoUseNewTab;
-
     // When loading a new tab or window via window.open, the child process sends
     // a new PBrowser to use. We store that tab in sNextTabParent and then
     // proceed through the browser's normal paths to create a new
     // window/tab. When it comes time to create a new TabParent, we instead use
     // sNextTabParent.
     static TabParent* sNextTabParent;
 
     // When loading a new tab or window via window.open, the child is
@@ -650,12 +642,44 @@ private:
 
     static void AddTabParentToTable(uint64_t aLayersId, TabParent* aTabParent);
     static void RemoveTabParentFromTable(uint64_t aLayersId);
 
 public:
     static TabParent* GetTabParentFromLayersId(uint64_t aLayersId);
 };
 
+struct MOZ_STACK_CLASS TabParent::AutoUseNewTab final
+{
+public:
+    AutoUseNewTab(TabParent* aNewTab, bool* aWindowIsNew, nsCString* aURLToLoad)
+     : mNewTab(aNewTab), mWindowIsNew(aWindowIsNew), mURLToLoad(aURLToLoad)
+    {
+        MOZ_ASSERT(!TabParent::sNextTabParent);
+        MOZ_ASSERT(!aNewTab->mCreatingWindow);
+
+        TabParent::sNextTabParent = aNewTab;
+        aNewTab->mCreatingWindow = true;
+        aNewTab->mDelayedURL.Truncate();
+    }
+
+    ~AutoUseNewTab()
+    {
+        mNewTab->mCreatingWindow = false;
+        *mURLToLoad = mNewTab->mDelayedURL;
+
+        if (TabParent::sNextTabParent) {
+            MOZ_ASSERT(TabParent::sNextTabParent == mNewTab);
+            TabParent::sNextTabParent = nullptr;
+            *mWindowIsNew = false;
+        }
+    }
+
+private:
+    TabParent* mNewTab;
+    bool* mWindowIsNew;
+    nsCString* mURLToLoad;
+};
+
 } // namespace dom
 } // namespace mozilla
 
 #endif