Bug 1502330 - Create BrowsingContext with passed opener. r=qdot
authorAndreas Farre <farre@mozilla.com>
Tue, 27 Nov 2018 09:59:44 +0000
changeset 507427 cb9dec83210d452c015b5608a3ea76c72ebbe777
parent 507426 d61b59d39b4adc3a322609cac931cab5257cbda9
child 507428 f851c3e82c2bad0afd8a2460245c9054c908e79f
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersqdot
bugs1502330
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1502330 - Create BrowsingContext with passed opener. r=qdot By replacing nsWebBrowser's implementation of the nsIBaseWindow.initWindow and nsIBaseWindow.create with a new static nsWebBrowser::Create method we make it possible to pass arguments directly when creating an nsWebBrowser, for example the opener BrowsingContext. As a bonus we can do away with nsWebBrowser::mInitInfo! Differential Revision: https://phabricator.services.mozilla.com/D12634
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
docshell/base/ChromeBrowsingContext.cpp
docshell/base/ChromeBrowsingContext.h
dom/base/nsFrameLoader.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/ipc/ContentChild.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/nsIContentChild.cpp
layout/printing/nsPrintObject.cpp
toolkit/components/browser/build/nsWebBrowserModule.cpp
toolkit/components/browser/nsWebBrowser.cpp
toolkit/components/browser/nsWebBrowser.h
xpfe/appshell/nsAppShellService.cpp
xpfe/appshell/nsWebShellWindow.cpp
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -51,17 +51,19 @@ Sync(BrowsingContext* aBrowsingContext)
     return;
   }
 
   auto cc = ContentChild::GetSingleton();
   MOZ_DIAGNOSTIC_ASSERT(cc);
   nsAutoString name;
   aBrowsingContext->GetName(name);
   RefPtr<BrowsingContext> parent = aBrowsingContext->GetParent();
+  BrowsingContext* opener = aBrowsingContext->GetOpener();
   cc->SendAttachBrowsingContext(BrowsingContextId(parent ? parent->Id() : 0),
+                                BrowsingContextId(opener ? opener->Id() : 0),
                                 BrowsingContextId(aBrowsingContext->Id()),
                                 name);
 }
 
 /* static */ void
 BrowsingContext::Init()
 {
   if (!sRootBrowsingContexts) {
@@ -92,80 +94,85 @@ BrowsingContext::GetLog()
 BrowsingContext::Get(uint64_t aId)
 {
   RefPtr<BrowsingContext> abc = sBrowsingContexts->Get(aId);
   return abc.forget();
 }
 
 /* static */ already_AddRefed<BrowsingContext>
 BrowsingContext::Create(BrowsingContext* aParent,
+                        BrowsingContext* aOpener,
                         const nsAString& aName,
                         Type aType)
 {
   MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->mType == aType);
 
   uint64_t id = nsContentUtils::GenerateBrowsingContextId();
 
   MOZ_LOG(GetLog(),
           LogLevel::Debug,
           ("Creating 0x%08" PRIx64 " in %s",
            id,
            XRE_IsParentProcess() ? "Parent" : "Child"));
 
   RefPtr<BrowsingContext> context;
   if (XRE_IsParentProcess()) {
-    context = new ChromeBrowsingContext(aParent, aName, id, /* aProcessId */ 0, aType);
+    context = new ChromeBrowsingContext(aParent, aOpener, aName, id, /* aProcessId */ 0, aType);
   } else {
-    context = new BrowsingContext(aParent, aName, id, aType);
+    context = new BrowsingContext(aParent, aOpener, aName, id, aType);
   }
 
   Register(context);
 
   // Attach the browsing context to the tree.
   context->Attach();
 
   return context.forget();
 }
 
 /* static */ already_AddRefed<BrowsingContext>
-BrowsingContext::CreateFromIPC(BrowsingContext* aParent, const nsAString& aName,
-                               uint64_t aId, ContentParent* aOriginProcess)
+BrowsingContext::CreateFromIPC(BrowsingContext* aParent,
+                               BrowsingContext* aOpener,
+                               const nsAString& aName,
+                               uint64_t aId,
+                               ContentParent* aOriginProcess)
 {
   MOZ_DIAGNOSTIC_ASSERT(aOriginProcess || XRE_IsContentProcess(),
                         "Parent Process IPC contexts need a Content Process.");
   MOZ_DIAGNOSTIC_ASSERT(!aParent || aParent->IsContent());
 
   MOZ_LOG(GetLog(),
           LogLevel::Debug,
           ("Creating 0x%08" PRIx64 " from IPC (origin=0x%08" PRIx64 ")",
            aId, aOriginProcess ? uint64_t(aOriginProcess->ChildID()) : 0));
 
   RefPtr<BrowsingContext> context;
   if (XRE_IsParentProcess()) {
     context = new ChromeBrowsingContext(
-      aParent, aName, aId, aOriginProcess->ChildID(), Type::Content);
-
+      aParent, aOpener, aName, aId, aOriginProcess->ChildID(), Type::Content);
   } else {
-    context = new BrowsingContext(aParent, aName, aId, Type::Content);
+    context = new BrowsingContext(aParent, aOpener, aName, aId, Type::Content);
   }
 
   Register(context);
 
   context->Attach();
 
   return context.forget();
 }
 
 BrowsingContext::BrowsingContext(BrowsingContext* aParent,
+                                 BrowsingContext* aOpener,
                                  const nsAString& aName,
                                  uint64_t aBrowsingContextId,
                                  Type aType)
   : mType(aType)
   , mBrowsingContextId(aBrowsingContextId)
   , mParent(aParent)
+  , mOpener(aOpener)
   , mName(aName)
 {
 }
 
 void
 BrowsingContext::SetDocShell(nsIDocShell* aDocShell)
 {
   // XXX(nika): We should communicate that we are now an active BrowsingContext
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -59,22 +59,24 @@ public:
   static LogModule* GetLog();
   static void CleanupContexts(uint64_t aProcessId);
 
   // Look up a BrowsingContext in the current process by ID.
   static already_AddRefed<BrowsingContext> Get(uint64_t aId);
 
   // Create a brand-new BrowsingContext object.
   static already_AddRefed<BrowsingContext> Create(BrowsingContext* aParent,
+                                                  BrowsingContext* aOpener,
                                                   const nsAString& aName,
                                                   Type aType);
 
   // Create a BrowsingContext object from over IPC.
   static already_AddRefed<BrowsingContext> CreateFromIPC(
     BrowsingContext* aParent,
+    BrowsingContext* aOpener,
     const nsAString& aName,
     uint64_t aId,
     ContentParent* aOriginProcess);
 
   // Get the DocShell for this BrowsingContext if it is in-process, or
   // null if it's not.
   nsIDocShell* GetDocShell() { return mDocShell; }
   void SetDocShell(nsIDocShell* aDocShell);
@@ -129,16 +131,17 @@ public:
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BrowsingContext)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(BrowsingContext)
 
   using Children = AutoCleanLinkedList<RefPtr<BrowsingContext>>;
 
 protected:
   virtual ~BrowsingContext();
   BrowsingContext(BrowsingContext* aParent,
+                  BrowsingContext* aOpener,
                   const nsAString& aName,
                   uint64_t aBrowsingContextId,
                   Type aType);
 
 private:
   // Type of BrowsingContent
   const Type mType;
 
--- a/docshell/base/ChromeBrowsingContext.cpp
+++ b/docshell/base/ChromeBrowsingContext.cpp
@@ -7,21 +7,22 @@
 #include "ChromeBrowsingContext.h"
 
 #include "mozilla/dom/ContentParent.h"
 
 namespace mozilla {
 namespace dom {
 
 ChromeBrowsingContext::ChromeBrowsingContext(BrowsingContext* aParent,
+                                             BrowsingContext* aOpener,
                                              const nsAString& aName,
                                              uint64_t aBrowsingContextId,
                                              uint64_t aProcessId,
                                              BrowsingContext::Type aType)
-  : BrowsingContext(aParent, aName, aBrowsingContextId, aType)
+  : BrowsingContext(aParent, aOpener, aName, aBrowsingContextId, aType)
   , mProcessId(aProcessId)
 {
   // You are only ever allowed to create ChromeBrowsingContexts in the
   // parent process.
   MOZ_RELEASE_ASSERT(XRE_IsParentProcess());
 }
 
 // TODO(farre): ChromeBrowsingContext::CleanupContexts starts from the
--- a/docshell/base/ChromeBrowsingContext.h
+++ b/docshell/base/ChromeBrowsingContext.h
@@ -35,16 +35,17 @@ public:
   }
 
 protected:
   void Traverse(nsCycleCollectionTraversalCallback& cb) {}
   void Unlink() {}
 
   using Type = BrowsingContext::Type;
   ChromeBrowsingContext(BrowsingContext* aParent,
+                        BrowsingContext* aOpener,
                         const nsAString& aName,
                         uint64_t aBrowsingContextId,
                         uint64_t aProcessId,
                         Type aType = Type::Chrome);
 
 private:
   friend class BrowsingContext;
 
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -1888,29 +1888,30 @@ nsFrameLoader::IsRemoteFrame()
     MOZ_ASSERT(!mDocShell, "Found a remote frame with a DocShell");
     return true;
   }
   return false;
 }
 
 static already_AddRefed<BrowsingContext>
 CreateBrowsingContext(BrowsingContext* aParentContext,
+                      BrowsingContext* aOpenerContext,
                       const nsAString& aName,
                       bool aIsContent)
 {
   // If we're content but our parent isn't, we're going to want to start a new
   // browsing context tree.
   if (aIsContent && !aParentContext->IsContent()) {
     aParentContext = nullptr;
   }
 
   BrowsingContext::Type type =
     aIsContent ? BrowsingContext::Type::Content : BrowsingContext::Type::Chrome;
 
-  return BrowsingContext::Create(aParentContext, aName, type);
+  return BrowsingContext::Create(aParentContext, aOpenerContext, aName, type);
 }
 
 nsresult
 nsFrameLoader::MaybeCreateDocShell()
 {
   if (mDocShell) {
     return NS_OK;
   }
@@ -1972,17 +1973,19 @@ nsFrameLoader::MaybeCreateDocShell()
   // Force mozbrowser frames to always be content, even if the mozbrowser
   // interfaces are disabled.
   nsCOMPtr<nsIMozBrowserFrame> mozbrowser =
     mOwnerContent->GetAsMozBrowserFrame();
   if (!isContent && mozbrowser) {
     mozbrowser->GetMozbrowser(&isContent);
   }
 
-  RefPtr<BrowsingContext> browsingContext = CreateBrowsingContext(parentBC, frameName, isContent);
+  RefPtr<BrowsingContext> openerBC = mOpener ? mOpener->GetBrowsingContext() : nullptr;
+  RefPtr<BrowsingContext> browsingContext =
+    CreateBrowsingContext(parentBC, openerBC, frameName, isContent);
 
   mDocShell = nsDocShell::Create(browsingContext);
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   mIsTopLevelContent = isContent && !parentBC->IsContent();
   if (!mNetworkCreated && !mIsTopLevelContent) {
     mDocShell->SetCreatedDynamically(true);
   }
@@ -2027,18 +2030,20 @@ nsFrameLoader::MaybeCreateDocShell()
   if (NS_WARN_IF(!newWindow)) {
     // Do not call Destroy() here. See bug 472312.
     NS_WARNING("Something wrong when creating the docshell for a frameloader!");
     return NS_ERROR_FAILURE;
   }
 
   newWindow->SetFrameElementInternal(mOwnerContent);
 
-  // Set the opener window if we have one provided here
-  // XXX(nika): We should tell our BrowsingContext this as we create it.
+  // Set the opener window if we have one provided here XXX(nika): We
+  // should tell our BrowsingContext this as we create it.
+  // TODO(farre): Remove this when nsGlobalWindowOuter::GetOpenerWindowOuter
+  // starts using BrowsingContext::GetOpener.
   if (mOpener) {
     newWindow->SetOpenerWindow(mOpener, true);
     mOpener = nullptr;
   }
 
   // Allow scripts to close the docshell if specified.
   if (mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
       mOwnerContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::allowscriptstoclose,
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -2262,19 +2262,21 @@ nsGlobalWindowOuter::SetOpenerWindow(nsP
                "SetOpenerWindow!");
   NS_ASSERTION(aOpener || !aOriginalOpener,
                "Shouldn't set mHadOriginalOpener if aOpener is null");
 
   mOpener = opener.forget();
   NS_ASSERTION(mOpener || !aOpener, "Opener must support weak references!");
 
   if (mDocShell) {
+    MOZ_DIAGNOSTIC_ASSERT(!aOriginalOpener || !aOpener ||
+                          aOpener->GetBrowsingContext() ==
+                            GetBrowsingContext()->GetOpener());
     // TODO(farre): Here we really wish to only consider the case
-    // where 'aOriginalOpener' is false, and we also really want to
-    // move opener entirely to BrowsingContext. See bug 1502330.
+    // where 'aOriginalOpener'. See bug 1509016.
     GetBrowsingContext()->SetOpener(aOpener ? aOpener->GetBrowsingContext() : nullptr);
   }
 
   // Check that the js visible opener matches! We currently don't depend on this
   // being true outside of nightly, so we disable the assertion in optimized
   // release / beta builds.
   nsPIDOMWindowOuter* contentOpener = GetSanitizedOpener(aOpener);
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -949,17 +949,17 @@ ContentChild::ProvideWindowCommon(TabChi
     tabGroup = aTabOpener->TabGroup();
   } else {
     tabGroup = new TabGroup();
   }
 
   TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
   RefPtr<TabChild> newChild = new TabChild(this, tabId, tabGroup,
                                            newTabContext, aChromeFlags);
-  if (NS_FAILED(newChild->Init())) {
+  if (NS_FAILED(newChild->Init(aParent))) {
     return NS_ERROR_ABORT;
   }
 
   if (aTabOpener) {
     MOZ_ASSERT(ipcContext->type() == IPCTabContext::TPopupIPCTabContext);
     ipcContext->get_PopupIPCTabContext().opener() = aTabOpener;
   }
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -6035,16 +6035,17 @@ ContentParent::RecvStoreUserInteractionA
 {
   AntiTrackingCommon::StoreUserInteractionFor(aPrincipal);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvAttachBrowsingContext(
   const BrowsingContextId& aParentId,
+  const BrowsingContextId& aOpenerId,
   const BrowsingContextId& aChildId,
   const nsString& aName)
 {
   RefPtr<ChromeBrowsingContext> parent = ChromeBrowsingContext::Get(aParentId);
   if (aParentId && !parent) {
     // Unless 'aParentId' is 0 (which it is when the child is a root
     // BrowsingContext) there should always be a corresponding
     // 'parent'. The only reason for there not beeing one is if the
@@ -6098,17 +6099,18 @@ ContentParent::RecvAttachBrowsingContext
             ("ParentIPC: Trying to attach already attached 0x%08" PRIx64
              " to 0x%08" PRIx64,
              child->Id(),
              (uint64_t)aParentId));
     return IPC_OK();
   }
 
   if (!child) {
-    child = BrowsingContext::CreateFromIPC(parent, aName, (uint64_t)aChildId, this);
+    RefPtr<BrowsingContext> opener = BrowsingContext::Get(aOpenerId);
+    child = BrowsingContext::CreateFromIPC(parent, opener, aName, (uint64_t)aChildId, this);
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 ContentParent::RecvDetachBrowsingContext(const BrowsingContextId& aContextId,
                                          const bool& aMoveToBFCache)
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -683,16 +683,17 @@ public:
   {
     return mIsInputPriorityEventEnabled;
   }
 
   static bool IsInputEventQueueSupported();
 
   virtual mozilla::ipc::IPCResult RecvAttachBrowsingContext(
     const BrowsingContextId& aParentContextId,
+    const BrowsingContextId& aOpenerId,
     const BrowsingContextId& aContextId,
     const nsString& aName) override;
 
   virtual mozilla::ipc::IPCResult RecvDetachBrowsingContext(
     const BrowsingContextId& aContextId,
     const bool& aMoveToBFCache) override;
 
   virtual mozilla::ipc::IPCResult RecvSetOpenerBrowsingContext(
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1171,16 +1171,17 @@ parent:
      * 'aParentContextId'. If 'aParentContextId' is '0' the
      * BrowsingContext is a root in the BrowsingContext
      * tree. AttachBrowsingContext must only be called at most once
      * for any child BrowsingContext, and only for BrowsingContexts
      * where the parent and the child context contains their
      * nsDocShell.
      */
     async AttachBrowsingContext(BrowsingContextId aParentContextId,
+                                BrowsingContextId aOpenerId,
                                 BrowsingContextId aContextId,
                                 nsString aName);
 
     /**
      * Remove the synced BrowsingContext with id 'aContextId' from the
      * parent. DetachBrowsingContext is only needed to be called once
      * for any BrowsingContext, since detaching a node in the
      * BrowsingContext detaches the entire sub-tree rooted at that
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -535,52 +535,43 @@ TabChild::DoUpdateZoomConstraints(const 
 
   ScrollableLayerGuid guid = ScrollableLayerGuid(mLayersId, aPresShellId, aViewId);
 
   mApzcTreeManager->UpdateZoomConstraints(guid, aConstraints);
   return true;
 }
 
 nsresult
-TabChild::Init()
+TabChild::Init(mozIDOMWindowProxy* aParent)
 {
   if (!mTabGroup) {
     mTabGroup = TabGroup::GetFromActor(this);
   }
 
-  // Directly create our web browser object and store it, so we can start
-  // eliminating QIs.
-  mWebBrowser = new nsWebBrowser(nsIDocShellTreeItem::typeContentWrapper);
-  nsIWebBrowser* webBrowser = mWebBrowser;
-
-  webBrowser->SetContainerWindow(this);
-  webBrowser->SetOriginAttributes(OriginAttributesRef());
-  mWebNav = do_QueryInterface(webBrowser);
-  NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
-
-  nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
-  if (!baseWindow) {
-    NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
-    return NS_ERROR_FAILURE;
-  }
-
   nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(this);
   mPuppetWidget = static_cast<PuppetWidget*>(widget.get());
   if (!mPuppetWidget) {
     NS_ERROR("couldn't create fake widget");
     return NS_ERROR_FAILURE;
   }
-  mPuppetWidget->InfallibleCreate(
-    nullptr, 0,              // no parents
-    LayoutDeviceIntRect(0, 0, 0, 0),
-    nullptr                  // HandleWidgetEvent
+  mPuppetWidget->InfallibleCreate(nullptr,
+                                  nullptr, // no parents
+                                  LayoutDeviceIntRect(0, 0, 0, 0),
+                                  nullptr // HandleWidgetEvent
   );
 
-  baseWindow->InitWindow(0, mPuppetWidget, 0, 0, 0, 0);
-  baseWindow->Create();
+  mWebBrowser = nsWebBrowser::Create(this,
+                                     mPuppetWidget,
+                                     OriginAttributesRef(),
+                                     aParent,
+                                     nsIDocShellTreeItem::typeContentWrapper);
+  nsIWebBrowser* webBrowser = mWebBrowser;
+
+  mWebNav = do_QueryInterface(webBrowser);
+  NS_ASSERTION(mWebNav, "nsWebBrowser doesn't implement nsIWebNavigation?");
 
   // Set the tab context attributes then pass to docShell
   NotifyTabContextUpdated(false);
 
   // IPC uses a WebBrowser object for which DNS prefetching is turned off
   // by default. But here we really want it, so enable it explicitly
   mWebBrowser->SetAllowDNSPrefetch(true);
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -227,17 +227,17 @@ public:
    * Create a new TabChild object.
    */
   TabChild(nsIContentChild* aManager,
            const TabId& aTabId,
            TabGroup* aTabGroup,
            const TabContext& aContext,
            uint32_t aChromeFlags);
 
-  nsresult Init();
+  nsresult Init(mozIDOMWindowProxy* aParent);
 
   /** Return a TabChild with the given attributes. */
   static already_AddRefed<TabChild>
   Create(nsIContentChild* aManager, const TabId& aTabId,
          const TabId& aSameTabGroupAs,
          const TabContext& aContext, uint32_t aChromeFlags);
 
   // Let managees query if it is safe to send messages.
--- a/dom/ipc/nsIContentChild.cpp
+++ b/dom/ipc/nsIContentChild.cpp
@@ -90,17 +90,17 @@ nsIContentChild::RecvPBrowserConstructor
                                          const ContentParentId& aCpID,
                                          const bool& aIsForBrowser)
 {
   // This runs after AllocPBrowserChild() returns and the IPC machinery for this
   // PBrowserChild has been set up.
 
   auto tabChild = static_cast<TabChild*>(static_cast<TabChild*>(aActor));
 
-  if (NS_WARN_IF(NS_FAILED(tabChild->Init()))) {
+  if (NS_WARN_IF(NS_FAILED(tabChild->Init(/* aOpener */ nullptr)))) {
     return IPC_FAIL(tabChild, "TabChild::Init failed");
   }
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (os) {
     os->NotifyObservers(static_cast<nsITabChild*>(tabChild), "tab-child-created", nullptr);
   }
   // Notify parent that we are ready to handle input events.
--- a/layout/printing/nsPrintObject.cpp
+++ b/layout/printing/nsPrintObject.cpp
@@ -57,17 +57,18 @@ nsPrintObject::Init(nsIDocShell* aDocShe
 
   if (mPrintPreview || mParent) {
     mDocShell = aDocShell;
   } else {
     mTreeOwner = do_GetInterface(aDocShell);
 
     // Create a new BrowsingContext to create our DocShell in.
     RefPtr<BrowsingContext> bc = BrowsingContext::Create(
-      nullptr,
+      /* aParent */ nullptr,
+      /* aOpener */ nullptr,
       EmptyString(),
       aDocShell->ItemType() == nsIDocShellTreeItem::typeContent
         ? BrowsingContext::Type::Content
         : BrowsingContext::Type::Chrome);
 
     // Create a container docshell for printing.
     mDocShell = nsDocShell::Create(bc);
     NS_ENSURE_TRUE(mDocShell, NS_ERROR_OUT_OF_MEMORY);
--- a/toolkit/components/browser/build/nsWebBrowserModule.cpp
+++ b/toolkit/components/browser/build/nsWebBrowserModule.cpp
@@ -10,30 +10,26 @@
 
 #include "nsEmbedCID.h"
 
 #include "nsWebBrowser.h"
 #include "nsWebBrowserContentPolicy.h"
 
 // Factory Constructors
 
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebBrowser)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebBrowserContentPolicy)
 
-NS_DEFINE_NAMED_CID(NS_WEBBROWSER_CID);
 NS_DEFINE_NAMED_CID(NS_WEBBROWSERCONTENTPOLICY_CID);
 
 static const mozilla::Module::CIDEntry kWebBrowserCIDs[] = {
-  { &kNS_WEBBROWSER_CID, false, nullptr, nsWebBrowserConstructor },
   { &kNS_WEBBROWSERCONTENTPOLICY_CID, false, nullptr, nsWebBrowserContentPolicyConstructor },
   { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kWebBrowserContracts[] = {
-  { NS_WEBBROWSER_CONTRACTID, &kNS_WEBBROWSER_CID },
   { NS_WEBBROWSERCONTENTPOLICY_CONTRACTID, &kNS_WEBBROWSERCONTENTPOLICY_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kWebBrowserCategories[] = {
   { "content-policy", NS_WEBBROWSERCONTENTPOLICY_CONTRACTID, NS_WEBBROWSERCONTENTPOLICY_CONTRACTID },
   { nullptr }
 };
--- a/toolkit/components/browser/nsWebBrowser.cpp
+++ b/toolkit/components/browser/nsWebBrowser.cpp
@@ -52,18 +52,17 @@
 #include "nsISecureBrowserUI.h"
 #include "nsXULAppAPI.h"
 
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::layers;
 
 nsWebBrowser::nsWebBrowser(int aItemType)
-  : mInitInfo(new nsWebBrowserInitInfo())
-  , mContentType(aItemType)
+  : mContentType(aItemType)
   , mActivating(false)
   , mShouldEnableHistory(true)
   , mIsActive(true)
   , mParentNativeWindow(nullptr)
   , mProgressListener(nullptr)
   , mWidgetListenerDelegate(this)
   , mBackgroundColor(0)
   , mPersistCurrentState(nsIWebBrowserPersist::PERSIST_STATE_READY)
@@ -75,34 +74,150 @@ nsWebBrowser::nsWebBrowser(int aItemType
   NS_ASSERTION(mWWatch, "failed to get WindowWatcher");
 }
 
 nsWebBrowser::~nsWebBrowser()
 {
   InternalDestroy();
 }
 
+nsIWidget*
+nsWebBrowser::EnsureWidget()
+{
+  if (mParentWidget) {
+    return mParentWidget;
+  }
+
+  mInternalWidget = nsIWidget::CreateChildWindow();
+  if (NS_WARN_IF(!mInternalWidget)) {
+    return nullptr;
+  }
+
+  nsWidgetInitData widgetInit;
+  widgetInit.clipChildren = true;
+  widgetInit.mWindowType = eWindowType_child;
+  LayoutDeviceIntRect bounds(0, 0, 0, 0);
+
+  mInternalWidget->SetWidgetListener(&mWidgetListenerDelegate);
+  NS_ENSURE_SUCCESS(mInternalWidget->Create(nullptr, mParentNativeWindow,
+                                            bounds, &widgetInit),
+                    nullptr);
+
+  return mInternalWidget;
+}
+
+/* static */ already_AddRefed<nsWebBrowser>
+nsWebBrowser::Create(nsIWebBrowserChrome* aContainerWindow,
+                     nsIWidget* aParentWidget,
+                     const OriginAttributes& aOriginAttributes,
+                     mozIDOMWindowProxy* aOpener,
+                     int aItemType)
+{
+  RefPtr<nsWebBrowser> browser = new nsWebBrowser(aItemType);
+
+  // nsWebBrowser::SetContainer also calls nsWebBrowser::EnsureDocShellTreeOwner
+  NS_ENSURE_SUCCESS(browser->SetContainerWindow(aContainerWindow), nullptr);
+  NS_ENSURE_SUCCESS(browser->SetParentWidget(aParentWidget), nullptr);
+
+  nsCOMPtr<nsIWidget> docShellParentWidget = browser->EnsureWidget();
+  if (NS_WARN_IF(!docShellParentWidget)) {
+    return nullptr;
+  }
+
+  // XXX(nika): Consider supporting creating nsWebBrowser for an existing
+  // BrowsingContext (e.g. during a X-process load).
+  using BrowsingContext = mozilla::dom::BrowsingContext;
+  RefPtr<BrowsingContext> openerContext =
+      aOpener ? nsPIDOMWindowOuter::From(aOpener)->GetBrowsingContext()
+              : nullptr;
+
+  RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
+      /* aParent */ nullptr, openerContext, EmptyString(),
+      aItemType != typeChromeWrapper ? BrowsingContext::Type::Content
+                                     : BrowsingContext::Type::Chrome);
+
+  RefPtr<nsDocShell> docShell = nsDocShell::Create(browsingContext);
+  if (NS_WARN_IF(!docShell)) {
+    return nullptr;
+  }
+  docShell->SetOriginAttributes(aOriginAttributes);
+  browser->SetDocShell(docShell);
+
+  // get the system default window background colour
+  LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
+                        &browser->mBackgroundColor);
+
+  // HACK ALERT - this registration registers the nsDocShellTreeOwner as a
+  // nsIWebBrowserListener so it can setup its MouseListener in one of the
+  // progress callbacks. If we can register the MouseListener another way, this
+  // registration can go away, and nsDocShellTreeOwner can stop implementing
+  // nsIWebProgressListener.
+  RefPtr<nsDocShellTreeOwner> docShellTreeOwner = browser->mDocShellTreeOwner;
+  nsCOMPtr<nsISupports> supports = nullptr;
+  Unused << docShellTreeOwner->QueryInterface(
+    NS_GET_IID(nsIWebProgressListener),
+    static_cast<void**>(getter_AddRefs(supports)));
+  Unused << browser->BindListener(supports, NS_GET_IID(nsIWebProgressListener));
+
+  nsCOMPtr<nsIBaseWindow> docShellAsWin = browser->mDocShellAsWin;
+  NS_ENSURE_SUCCESS(
+      docShellAsWin->InitWindow(nullptr, docShellParentWidget, 0, 0, 0, 0),
+      nullptr);
+
+  docShell->SetTreeOwner(docShellTreeOwner);
+
+  // If the webbrowser is a content docshell item then we won't hear any
+  // events from subframes. To solve that we install our own chrome event
+  // handler that always gets called (even for subframes) for any bubbling
+  // event.
+
+  docShell->InitSessionHistory();
+
+  if (XRE_IsParentProcess()) {
+    // Hook up global history. Do not fail if we can't - just warn.
+    DebugOnly<nsresult> rv = browser->EnableGlobalHistory(browser->mShouldEnableHistory);
+    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EnableGlobalHistory() failed");
+  }
+
+  NS_ENSURE_SUCCESS(docShellAsWin->Create(), nullptr);
+
+  // Hook into the OnSecurityChange() notification for lock/unlock icon
+  // updates
+  // this works because the implementation of nsISecureBrowserUI
+  // (nsSecureBrowserUIImpl) calls docShell->SetSecurityUI(this);
+  nsCOMPtr<nsISecureBrowserUI> securityUI =
+    do_CreateInstance(NS_SECURE_BROWSER_UI_CONTRACTID);
+  if (NS_WARN_IF(!securityUI)) {
+    return nullptr;
+  }
+  securityUI->Init(docShell);
+
+  docShellTreeOwner->AddToWatcher(); // evil twin of Remove in SetDocShell(0)
+  docShellTreeOwner->AddChromeListeners();
+
+  return browser.forget();
+}
+
+
 NS_IMETHODIMP
 nsWebBrowser::InternalDestroy()
 {
   if (mInternalWidget) {
     mInternalWidget->SetWidgetListener(nullptr);
     mInternalWidget->Destroy();
     mInternalWidget = nullptr; // Force release here.
   }
 
   SetDocShell(nullptr);
 
   if (mDocShellTreeOwner) {
     mDocShellTreeOwner->WebBrowser(nullptr);
     mDocShellTreeOwner = nullptr;
   }
 
-  mInitInfo = nullptr;
-
   return NS_OK;
 }
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsWebBrowser)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsWebBrowser)
 
 NS_IMPL_CYCLE_COLLECTION(nsWebBrowser,
                          mDocShell,
@@ -248,43 +363,37 @@ nsWebBrowser::SetOriginAttributes(const 
 // nsWebBrowser::nsIDocShellTreeItem
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsWebBrowser::GetName(nsAString& aName)
 {
   if (mDocShell) {
     mDocShell->GetName(aName);
-  } else {
-    aName = mInitInfo->name;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetName(const nsAString& aName)
 {
   if (mDocShell) {
     return mDocShell->SetName(aName);
-  } else {
-    mInitInfo->name = aName;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::NameEquals(const nsAString& aName, bool* aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
   if (mDocShell) {
     return mDocShell->NameEquals(aName, aResult);
-  } else {
-    *aResult = mInitInfo->name.Equals(aName);
   }
 
   return NS_OK;
 }
 
 /* virtual */ int32_t
 nsWebBrowser::ItemType()
 {
@@ -915,144 +1024,36 @@ nsWebBrowser::Cancel(nsresult aReason)
 //*****************************************************************************
 
 NS_IMETHODIMP
 nsWebBrowser::InitWindow(nativeWindow aParentNativeWindow,
                          nsIWidget* aParentWidget,
                          int32_t aX, int32_t aY,
                          int32_t aCX, int32_t aCY)
 {
-  NS_ENSURE_ARG(aParentNativeWindow || aParentWidget);
-  NS_ENSURE_STATE(!mDocShell || mInitInfo);
-
-  if (aParentWidget) {
-    NS_ENSURE_SUCCESS(SetParentWidget(aParentWidget), NS_ERROR_FAILURE);
-  } else
-    NS_ENSURE_SUCCESS(SetParentNativeWindow(aParentNativeWindow),
-                      NS_ERROR_FAILURE);
-
-  NS_ENSURE_SUCCESS(SetPositionAndSize(aX, aY, aCX, aCY, 0),
-                    NS_ERROR_FAILURE);
-
-  return NS_OK;
+  // nsIBaseWindow::InitWindow and nsIBaseWindow::Create
+  // implementations have been merged into nsWebBrowser::Create
+  MOZ_DIAGNOSTIC_ASSERT(false);
+  return NS_ERROR_NULL_POINTER;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::Create()
 {
-  NS_ENSURE_STATE(!mDocShell && (mParentNativeWindow || mParentWidget));
-
-  nsresult rv = EnsureDocShellTreeOwner();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIWidget> docShellParentWidget(mParentWidget);
-  if (!mParentWidget) {
-    // Create the widget
-    mInternalWidget = nsIWidget::CreateChildWindow();
-    NS_ENSURE_TRUE(mInternalWidget, NS_ERROR_FAILURE);
-
-    docShellParentWidget = mInternalWidget;
-    nsWidgetInitData widgetInit;
-
-    widgetInit.clipChildren = true;
-
-    widgetInit.mWindowType = eWindowType_child;
-    LayoutDeviceIntRect bounds(mInitInfo->x, mInitInfo->y,
-                               mInitInfo->cx, mInitInfo->cy);
-
-    mInternalWidget->SetWidgetListener(&mWidgetListenerDelegate);
-    rv = mInternalWidget->Create(nullptr, mParentNativeWindow, bounds,
-                                 &widgetInit);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // XXX(nika): Consider supporting creating nsWebBrowser for an existing
-  // BrowsingContext (e.g. during a X-process load).
-  // XXX(nika): Get window opener information into nsWebBrowser::Create.
-  using BrowsingContext = mozilla::dom::BrowsingContext;
-  RefPtr<mozilla::dom::BrowsingContext> browsingContext =
-    BrowsingContext::Create(nullptr,
-                            mInitInfo->name,
-                            mContentType != typeChromeWrapper
-                              ? BrowsingContext::Type::Content
-                              : BrowsingContext::Type::Chrome);
-
-  RefPtr<nsDocShell> docShell = nsDocShell::Create(browsingContext);
-  if (NS_WARN_IF(!docShell)) {
-    return NS_ERROR_UNEXPECTED;
-  }
-  docShell->SetOriginAttributes(mOriginAttributes);
-  rv = SetDocShell(docShell);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // get the system default window background colour
-  LookAndFeel::GetColor(LookAndFeel::eColorID_WindowBackground,
-                        &mBackgroundColor);
-
-  // HACK ALERT - this registration registers the nsDocShellTreeOwner as a
-  // nsIWebBrowserListener so it can setup its MouseListener in one of the
-  // progress callbacks. If we can register the MouseListener another way, this
-  // registration can go away, and nsDocShellTreeOwner can stop implementing
-  // nsIWebProgressListener.
-  nsCOMPtr<nsISupports> supports = nullptr;
-  (void)mDocShellTreeOwner->QueryInterface(
-    NS_GET_IID(nsIWebProgressListener),
-    static_cast<void**>(getter_AddRefs(supports)));
-  (void)BindListener(supports, NS_GET_IID(nsIWebProgressListener));
-
-  NS_ENSURE_SUCCESS(mDocShellAsWin->InitWindow(nullptr, docShellParentWidget,
-                                               mInitInfo->x, mInitInfo->y,
-                                               mInitInfo->cx, mInitInfo->cy),
-                    NS_ERROR_FAILURE);
-
-  mDocShell->SetTreeOwner(mDocShellTreeOwner);
-
-  // If the webbrowser is a content docshell item then we won't hear any
-  // events from subframes. To solve that we install our own chrome event
-  // handler that always gets called (even for subframes) for any bubbling
-  // event.
-
-  mDocShell->InitSessionHistory();
-
-  if (XRE_IsParentProcess()) {
-    // Hook up global history. Do not fail if we can't - just warn.
-    rv = EnableGlobalHistory(mShouldEnableHistory);
-    NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EnableGlobalHistory() failed");
-  }
-
-  NS_ENSURE_SUCCESS(mDocShellAsWin->Create(), NS_ERROR_FAILURE);
-
-  // Hook into the OnSecurityChange() notification for lock/unlock icon
-  // updates
-  // this works because the implementation of nsISecureBrowserUI
-  // (nsSecureBrowserUIImpl) calls docShell->SetSecurityUI(this);
-  nsCOMPtr<nsISecureBrowserUI> securityUI =
-    do_CreateInstance(NS_SECURE_BROWSER_UI_CONTRACTID, &rv);
-  if (NS_FAILED(rv)) {
-    return rv;
-  }
-  securityUI->Init(mDocShell);
-
-  mDocShellTreeOwner->AddToWatcher(); // evil twin of Remove in SetDocShell(0)
-  mDocShellTreeOwner->AddChromeListeners();
-
-  mInitInfo = nullptr;
-
-  return NS_OK;
+  // nsIBaseWindow::InitWindow and nsIBaseWindow::Create
+  // implementations have been merged into nsWebBrowser::Create
+  MOZ_DIAGNOSTIC_ASSERT(false);
+  return NS_ERROR_NULL_POINTER;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::Destroy()
 {
   InternalDestroy();
 
-  if (!mInitInfo) {
-    mInitInfo = new nsWebBrowserInitInfo();
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::GetUnscaledDevicePixelsPerCSSPixel(double* aScale)
 {
   *aScale = mParentWidget ? mParentWidget->GetDefaultScale().scale : 1.0;
   return NS_OK;
@@ -1115,60 +1116,40 @@ nsWebBrowser::GetSize(int32_t* aCX, int3
 {
   return GetPositionAndSize(nullptr, nullptr, aCX, aCY);
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetPositionAndSize(int32_t aX, int32_t aY,
                                  int32_t aCX, int32_t aCY, uint32_t aFlags)
 {
-  if (!mDocShell) {
-    mInitInfo->x = aX;
-    mInitInfo->y = aY;
-    mInitInfo->cx = aCX;
-    mInitInfo->cy = aCY;
-  } else {
-    int32_t doc_x = aX;
-    int32_t doc_y = aY;
+  int32_t doc_x = aX;
+  int32_t doc_y = aY;
 
-    // If there is an internal widget we need to make the docShell coordinates
-    // relative to the internal widget rather than the calling app's parent.
-    // We also need to resize our widget then.
-    if (mInternalWidget) {
-      doc_x = doc_y = 0;
-      mInternalWidget->Resize(aX, aY, aCX, aCY,
-                              !!(aFlags & nsIBaseWindow::eRepaint));
-    }
-    // Now reposition/ resize the doc
-    NS_ENSURE_SUCCESS(
-      mDocShellAsWin->SetPositionAndSize(doc_x, doc_y, aCX, aCY, aFlags),
-      NS_ERROR_FAILURE);
+  // If there is an internal widget we need to make the docShell coordinates
+  // relative to the internal widget rather than the calling app's parent.
+  // We also need to resize our widget then.
+  if (mInternalWidget) {
+    doc_x = doc_y = 0;
+    mInternalWidget->Resize(aX, aY, aCX, aCY,
+                            !!(aFlags & nsIBaseWindow::eRepaint));
   }
+  // Now reposition/ resize the doc
+  NS_ENSURE_SUCCESS(
+    mDocShellAsWin->SetPositionAndSize(doc_x, doc_y, aCX, aCY, aFlags),
+    NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::GetPositionAndSize(int32_t* aX, int32_t* aY,
                                  int32_t* aCX, int32_t* aCY)
 {
-  if (!mDocShell) {
-    if (aX) {
-      *aX = mInitInfo->x;
-    }
-    if (aY) {
-      *aY = mInitInfo->y;
-    }
-    if (aCX) {
-      *aCX = mInitInfo->cx;
-    }
-    if (aCY) {
-      *aCY = mInitInfo->cy;
-    }
-  } else if (mInternalWidget) {
+  if (mInternalWidget) {
     LayoutDeviceIntRect bounds = mInternalWidget->GetBounds();
 
     if (aX) {
       *aX = bounds.X();
     }
     if (aY) {
       *aY = bounds.Y();
     }
@@ -1250,32 +1231,28 @@ nsWebBrowser::GetNativeHandle(nsAString&
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::GetVisibility(bool* aVisibility)
 {
   NS_ENSURE_ARG_POINTER(aVisibility);
 
-  if (!mDocShell) {
-    *aVisibility = mInitInfo->visible;
-  } else {
+  if (mDocShell) {
     NS_ENSURE_SUCCESS(mDocShellAsWin->GetVisibility(aVisibility),
                       NS_ERROR_FAILURE);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsWebBrowser::SetVisibility(bool aVisibility)
 {
-  if (!mDocShell) {
-    mInitInfo->visible = aVisibility;
-  } else {
+  if (mDocShell) {
     NS_ENSURE_SUCCESS(mDocShellAsWin->SetVisibility(aVisibility),
                       NS_ERROR_FAILURE);
     if (mInternalWidget) {
       mInternalWidget->Show(aVisibility);
     }
   }
 
   return NS_OK;
--- a/toolkit/components/browser/nsWebBrowser.h
+++ b/toolkit/components/browser/nsWebBrowser.h
@@ -48,16 +48,17 @@ public:
   bool visible;
   nsString name;
 };
 
 //  {cda5863a-aa9c-411e-be49-ea0d525ab4b5} -
 #define NS_WEBBROWSER_CID \
   { 0xcda5863a, 0xaa9c, 0x411e, { 0xbe, 0x49, 0xea, 0x0d, 0x52, 0x5a, 0xb4, 0xb5 } }
 
+class mozIDOMWindowProxy;
 
 class nsWebBrowser final : public nsIWebBrowser,
                            public nsIWebNavigation,
                            public nsIDocShellTreeItem,
                            public nsIBaseWindow,
                            public nsIScrollable,
                            public nsIInterfaceRequestor,
                            public nsIWebBrowserPersist,
@@ -82,18 +83,16 @@ public:
       nsIWidget* aWidget, mozilla::LayoutDeviceIntRegion aRegion) override;
 
   private:
     // The lifetime of WidgetListenerDelegate is bound to nsWebBrowser so we
     // just use raw pointer here.
     nsWebBrowser* mWebBrowser;
   };
 
-  explicit nsWebBrowser(int aItemType = typeContentWrapper);
-
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsWebBrowser, nsIWebBrowser)
 
   NS_DECL_NSIBASEWINDOW
   NS_DECL_NSIDOCSHELLTREEITEM
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSISCROLLABLE
   NS_DECL_NSIWEBBROWSER
@@ -101,44 +100,54 @@ public:
   NS_DECL_NSIWEBBROWSERPERSIST
   NS_DECL_NSICANCELABLE
   NS_DECL_NSIWEBPROGRESSLISTENER
 
   void SetAllowDNSPrefetch(bool aAllowPrefetch);
   void FocusActivate();
   void FocusDeactivate();
 
+  static already_AddRefed<nsWebBrowser> Create(
+    nsIWebBrowserChrome* aContainerWindow,
+    nsIWidget* aParentWidget,
+    const mozilla::OriginAttributes& aOriginAttributes,
+    mozIDOMWindowProxy* aOpener,
+    int aItemType);
+
 protected:
   virtual ~nsWebBrowser();
   NS_IMETHOD InternalDestroy();
 
   // XXXbz why are these NS_IMETHOD?  They're not interface methods!
   NS_IMETHOD SetDocShell(nsIDocShell* aDocShell);
   NS_IMETHOD EnsureDocShellTreeOwner();
   NS_IMETHOD BindListener(nsISupports* aListener, const nsIID& aIID);
   NS_IMETHOD EnableGlobalHistory(bool aEnable);
 
+  nsIWidget* EnsureWidget();
+
   // nsIWidgetListener methods for WidgetListenerDelegate.
   MOZ_CAN_RUN_SCRIPT void WindowActivated();
   MOZ_CAN_RUN_SCRIPT void WindowDeactivated();
   MOZ_CAN_RUN_SCRIPT bool PaintWindow(
     nsIWidget* aWidget, mozilla::LayoutDeviceIntRegion aRegion);
 
+  explicit nsWebBrowser(int aItemType);
+
 protected:
   RefPtr<nsDocShellTreeOwner> mDocShellTreeOwner;
   nsCOMPtr<nsIDocShell> mDocShell;
   nsCOMPtr<nsIInterfaceRequestor> mDocShellAsReq;
   nsCOMPtr<nsIBaseWindow> mDocShellAsWin;
   nsCOMPtr<nsIWebNavigation> mDocShellAsNav;
   nsCOMPtr<nsIScrollable> mDocShellAsScrollable;
   mozilla::OriginAttributes mOriginAttributes;
 
   nsCOMPtr<nsIWidget> mInternalWidget;
   nsCOMPtr<nsIWindowWatcher> mWWatch;
-  nsAutoPtr<nsWebBrowserInitInfo> mInitInfo;
   const uint32_t mContentType;
   bool mActivating;
   bool mShouldEnableHistory;
   bool mIsActive;
   nativeWindow mParentNativeWindow;
   nsIWebProgressListener* mProgressListener;
   nsCOMPtr<nsIWebProgress> mWebProgress;
 
--- a/xpfe/appshell/nsAppShellService.cpp
+++ b/xpfe/appshell/nsAppShellService.cpp
@@ -216,25 +216,26 @@ nsAppShellService::CreateTopLevelWindow(
 
   return rv;
 }
 
 /*
  * This class provides a stub implementation of nsIWebBrowserChrome2, as needed
  * by nsAppShellService::CreateWindowlessBrowser
  */
-class WebBrowserChrome2Stub : public nsIWebBrowserChrome2,
-                              public nsIEmbeddingSiteWindow,
-                              public nsIInterfaceRequestor,
-                              public nsSupportsWeakReference {
+class WebBrowserChrome2Stub final : public nsIWebBrowserChrome2,
+                                    public nsIEmbeddingSiteWindow,
+                                    public nsIInterfaceRequestor,
+                                    public nsSupportsWeakReference {
 protected:
     nsCOMPtr<nsIWebBrowser> mBrowser;
     virtual ~WebBrowserChrome2Stub() {}
 public:
-    explicit WebBrowserChrome2Stub(nsIWebBrowser *aBrowser) : mBrowser(aBrowser) {}
+    void SetBrowser(nsIWebBrowser* aBrowser) { mBrowser = aBrowser; }
+
     NS_DECL_ISUPPORTS
     NS_DECL_NSIWEBBROWSERCHROME
     NS_DECL_NSIWEBBROWSERCHROME2
     NS_DECL_NSIINTERFACEREQUESTOR
     NS_DECL_NSIEMBEDDINGSITEWINDOW
 };
 
 NS_INTERFACE_MAP_BEGIN(WebBrowserChrome2Stub)
@@ -473,59 +474,61 @@ WindowlessBrowser::GetDocShell(nsIDocShe
   docShell.forget(aDocShell);
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWindowlessBrowser **aResult)
 {
-  /* First, we create an instance of nsWebBrowser. Instances of this class have
-   * an associated doc shell, which is what we're interested in.
-   */
-  nsCOMPtr<nsIWebBrowser> browser =
-    new nsWebBrowser(aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
-                               : nsIDocShellTreeItem::typeContentWrapper);
-
-  if (!browser) {
-    NS_ERROR("Couldn't create instance of nsWebBrowser!");
-    return NS_ERROR_FAILURE;
-  }
-
-  /* Next, we set the container window for our instance of nsWebBrowser. Since
+  /* First, we set the container window for our instance of nsWebBrowser. Since
    * we don't actually have a window, we instead set the container window to be
    * an instance of WebBrowserChrome2Stub, which provides a stub implementation
    * of nsIWebBrowserChrome2.
    */
-  RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub(browser);
-  browser->SetContainerWindow(stub);
-
-  nsCOMPtr<nsIWebNavigation> navigation = do_QueryInterface(browser);
+  RefPtr<WebBrowserChrome2Stub> stub = new WebBrowserChrome2Stub();
 
   /* A windowless web browser doesn't have an associated OS level window. To
    * accomplish this, we initialize the window associated with our instance of
    * nsWebBrowser with an instance of HeadlessWidget/PuppetWidget, which provide
    * a stub implementation of nsIWidget.
    */
   nsCOMPtr<nsIWidget> widget;
   if (gfxPlatform::IsHeadless()) {
     widget = nsIWidget::CreateHeadlessWidget();
   } else {
     widget = nsIWidget::CreatePuppetWidget(nullptr);
   }
   if (!widget) {
     NS_ERROR("Couldn't create instance of stub widget");
     return NS_ERROR_FAILURE;
   }
+
   nsresult rv =
     widget->Create(nullptr, 0, LayoutDeviceIntRect(0, 0, 0, 0), nullptr);
   NS_ENSURE_SUCCESS(rv, rv);
-  nsCOMPtr<nsIBaseWindow> window = do_QueryInterface(navigation);
-  window->InitWindow(0, widget, 0, 0, 0, 0);
-  window->Create();
+
+  /* Next, we create an instance of nsWebBrowser. Instances of this class have
+   * an associated doc shell, which is what we're interested in.
+   */
+  nsCOMPtr<nsIWebBrowser> browser =
+    nsWebBrowser::Create(stub,
+                         widget,
+                         OriginAttributes(),
+                         nullptr,
+                         aIsChrome ? nsIDocShellTreeItem::typeChromeWrapper
+                         : nsIDocShellTreeItem::typeContentWrapper);
+
+  if (NS_WARN_IF(!browser)) {
+    NS_ERROR("Couldn't create instance of nsWebBrowser!");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Make sure the container window owns the the nsWebBrowser instance.
+  stub->SetBrowser(browser);
 
   nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub);
   RefPtr<nsIWindowlessBrowser> result = new WindowlessBrowser(browser, isstub);
   nsCOMPtr<nsIDocShell> docshell = do_GetInterface(result);
   docshell->SetInvisible(true);
 
   result.forget(aResult);
   return NS_OK;
--- a/xpfe/appshell/nsWebShellWindow.cpp
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -177,18 +177,25 @@ nsresult nsWebShellWindow::Initialize(ns
   NS_ENSURE_SUCCESS(rv, rv);
 
   LayoutDeviceIntRect r = mWindow->GetClientBounds();
   // Match the default background color of content. Important on windows
   // since we no longer use content child widgets.
   mWindow->SetBackgroundColor(NS_RGB(255,255,255));
 
   // Create web shell
+  RefPtr<BrowsingContext> openerContext =
+    aOpenerWindow
+      ? nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext()
+      : nullptr;
   RefPtr<BrowsingContext> browsingContext =
-    BrowsingContext::Create(nullptr, EmptyString(), BrowsingContext::Type::Chrome);
+    BrowsingContext::Create(/* aParent */ nullptr,
+                            openerContext,
+                            EmptyString(),
+                            BrowsingContext::Type::Chrome);
   mDocShell = nsDocShell::Create(browsingContext);
   NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE);
 
   // XXX(nika): This is used to handle propagating opener across remote tab
   // creation. We should come up with a better system for doing this (probably
   // based on BrowsingContext).
   mDocShell->SetOpener(aOpeningTab);