Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Sat, 31 Aug 2019 12:47:56 +0300
changeset 554793 b3cc8963e8718dbd40761f14664f45320c258bbd
parent 554792 56db66978b427e18362c3d1d733f7fcb61d2912e (current diff)
parent 554791 2ce54fbea7dc53831e822d3af55871a4117b9629 (diff)
child 554794 54dcc1dc10c72771c95164cfaab03544a2e86a98
push id2165
push userffxbld-merge
push dateMon, 14 Oct 2019 16:30:58 +0000
treeherdermozilla-release@0eae18af659f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone70.0a1
first release with
nightly linux32
b3cc8963e871 / 70.0a1 / 20190831095143 / files
nightly linux64
b3cc8963e871 / 70.0a1 / 20190831095143 / files
nightly mac
b3cc8963e871 / 70.0a1 / 20190831095143 / files
nightly win32
b3cc8963e871 / 70.0a1 / 20190831095143 / files
nightly win64
b3cc8963e871 / 70.0a1 / 20190831095143 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
browser/base/content/pageinfo/pageInfo.js
browser/base/content/pageinfo/pageInfo.xul
browser/locales/en-US/browser/pageInfo.ftl
dom/base/nsGlobalWindowOuter.cpp
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -144,17 +144,20 @@ pageInfoTreeView.prototype = {
   },
   hasNextSibling(index, after) {
     return false;
   },
   getLevel(index) {
     return 0;
   },
   getImageSrc(row, column) {},
-  getCellValue(row, column) {},
+  getCellValue(row, column) {
+    let col = column != null ? column : this.copycol;
+    return row < 0 || col < 0 ? "" : this.data[row][col] || "";
+  },
   toggleOpenState(index) {},
   cycleHeader(col) {},
   selectionChanged() {},
   cycleCell(row, column) {},
   isEditable(row, column) {
     return false;
   },
 };
@@ -264,16 +267,29 @@ var loadContextInfo = Services.loadConte
 var diskStorage = cacheService.diskCacheStorage(loadContextInfo, false);
 
 const nsICookiePermission = Ci.nsICookiePermission;
 const nsIPermissionManager = Ci.nsIPermissionManager;
 
 const nsICertificateDialogs = Ci.nsICertificateDialogs;
 const CERTIFICATEDIALOGS_CONTRACTID = "@mozilla.org/nsCertificateDialogs;1";
 
+// clipboard helper
+function getClipboardHelper() {
+  try {
+    return Cc["@mozilla.org/widget/clipboardhelper;1"].getService(
+      Ci.nsIClipboardHelper
+    );
+  } catch (e) {
+    // do nothing, later code will handle the error
+    return null;
+  }
+}
+const gClipboardHelper = getClipboardHelper();
+
 // namespaces, don't need all of these yet...
 const XLinkNS = "http://www.w3.org/1999/xlink";
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const XMLNS = "http://www.w3.org/XML/1998/namespace";
 const XHTMLNS = "http://www.w3.org/1999/xhtml";
 const XHTML2NS = "http://www.w3.org/2002/06/xhtml2";
 
 const XHTMLNSre = "^http://www.w3.org/1999/xhtml$";
@@ -1170,16 +1186,47 @@ function formatDate(datestr, unknown) {
 
   const dateTimeFormatter = new Services.intl.DateTimeFormat(undefined, {
     dateStyle: "long",
     timeStyle: "long",
   });
   return dateTimeFormatter.format(date);
 }
 
+function doCopy() {
+  if (!gClipboardHelper) {
+    return;
+  }
+
+  var elem = document.commandDispatcher.focusedElement;
+
+  if (elem && elem.localName == "tree") {
+    var view = elem.view;
+    var selection = view.selection;
+    var text = [],
+      tmp = "";
+    var min = {},
+      max = {};
+
+    var count = selection.getRangeCount();
+
+    for (var i = 0; i < count; i++) {
+      selection.getRangeAt(i, min, max);
+
+      for (var row = min.value; row <= max.value; row++) {
+        tmp = view.getCellValue(row, null);
+        if (tmp) {
+          text.push(tmp);
+        }
+      }
+    }
+    gClipboardHelper.copyString(text.join("\n"));
+  }
+}
+
 function doSelectAllMedia() {
   var tree = document.getElementById("imagetree");
 
   if (tree) {
     tree.view.selection.selectAll();
   }
 }
 
--- a/browser/base/content/pageinfo/pageInfo.xul
+++ b/browser/base/content/pageinfo/pageInfo.xul
@@ -42,33 +42,36 @@
   <stringbundleset id="pageinfobundleset">
     <stringbundle id="pkiBundle" src="chrome://pippki/locale/pippki.properties"/>
     <stringbundle id="browserBundle" src="chrome://browser/locale/browser.properties"/>
   </stringbundleset>
 
   <commandset id="pageInfoCommandSet">
     <command id="cmd_close"     oncommand="window.close();"/>
     <command id="cmd_help"      oncommand="doHelpButton();"/>
+    <command id="cmd_copy"      oncommand="doCopy();"/>
     <command id="cmd_selectall" oncommand="doSelectAll();"/>
   </commandset>
 
   <keyset id="pageInfoKeySet">
     <key data-l10n-id="close-dialog" data-l10n-attrs="key" modifiers="accel" command="cmd_close"/>
     <key keycode="VK_ESCAPE" command="cmd_close"/>
 #ifdef XP_MACOSX
     <key key="." modifiers="meta"  command="cmd_close"/>
 #else
     <key keycode="VK_F1" command="cmd_help"/>
 #endif
+    <key data-l10n-id="copy"       data-l10n-attrs="key" modifiers="accel" command="cmd_copy"/>
     <key data-l10n-id="select-all" data-l10n-attrs="key" modifiers="accel" command="cmd_selectall"/>
     <key data-l10n-id="select-all" data-l10n-attrs="key" modifiers="alt"   command="cmd_selectall"/>
   </keyset>
 
   <menupopup id="picontext">
     <menuitem id="menu_selectall" data-l10n-id="menu-select-all" command="cmd_selectall"/>
+    <menuitem id="menu_copy"      data-l10n-id="menu-copy"       command="cmd_copy"/>
   </menupopup>
 
   <vbox id="topBar">
     <radiogroup id="viewGroup" class="chromeclass-toolbar" orient="horizontal">
       <radio id="generalTab"  data-l10n-id="general-tab"
            oncommand="showTab('general');"/>
       <radio id="mediaTab"    data-l10n-id="media-tab"
            oncommand="showTab('media');" hidden="true"/>
--- a/browser/base/content/test/permissions/browser_temporary_permissions.js
+++ b/browser/base/content/test/permissions/browser_temporary_permissions.js
@@ -67,17 +67,17 @@ add_task(async function testTempPermissi
       "popupshown"
     );
 
     // Request a permission.
     await ContentTask.spawn(browser, uri.host, async function(host0) {
       // FIXME(Fission): The load event fires before cross-origin iframes have
       // loaded (bug 1559841).
       if (content.SpecialPowers.useRemoteSubframes) {
-        for (let i = 0; i < 200; i++) {
+        for (let i = 0; i < 800; i++) {
           await new Promise(resolve => content.setTimeout(resolve, 0));
         }
       }
 
       let frame = content.document.getElementById("frame");
 
       await content.SpecialPowers.spawn(frame, [host0], async function(host) {
         const { E10SUtils } = ChromeUtils.import(
--- a/browser/locales/en-US/browser/pageInfo.ftl
+++ b/browser/locales/en-US/browser/pageInfo.ftl
@@ -1,15 +1,21 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # 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/. --
 
 page-info-window =
     .style = width: 600px; min-height: 550px;
 
+copy =
+    .key = C
+menu-copy =
+    .label = Copy
+    .accesskey = C
+
 select-all =
     .key = A
 menu-select-all =
     .label = Select All
     .accesskey = A
 
 close-dialog =
     .key = w
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -127,17 +127,20 @@ already_AddRefed<BrowsingContext> Browsi
                                            /* aProcessId */ 0, aType);
   } else {
     context = new BrowsingContext(aParent, group, id, aType);
   }
 
   // The name and opener fields need to be explicitly initialized. Don't bother
   // using transactions to set them, as we haven't been attached yet.
   context->mName = aName;
-  context->mOpenerId = aOpener ? aOpener->Id() : 0;
+  if (aOpener) {
+    context->mOpenerId = aOpener->Id();
+    context->mHadOriginalOpener = true;
+  }
   context->mEmbedderPolicy = nsILoadInfo::EMBEDDER_POLICY_NULL;
 
   BrowsingContext* inherit = aParent ? aParent : aOpener;
   if (inherit) {
     context->mOpenerPolicy = inherit->mOpenerPolicy;
     // CORPP 3.1.3 https://mikewest.github.io/corpp/#integration-html
     context->mEmbedderPolicy = inherit->mEmbedderPolicy;
   }
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -204,23 +204,32 @@ class BrowsingContext : public nsWrapper
   bool IsTopContent() const { return IsContent() && !GetParent(); }
 
   uint64_t Id() const { return mBrowsingContextId; }
 
   BrowsingContext* GetParent() const { return mParent; }
 
   BrowsingContext* Top();
 
-  already_AddRefed<BrowsingContext> GetOpener() const { return Get(mOpenerId); }
+  already_AddRefed<BrowsingContext> GetOpener() const {
+    RefPtr<BrowsingContext> opener(Get(mOpenerId));
+    if (!mIsDiscarded && opener && !opener->mIsDiscarded) {
+      return opener.forget();
+    }
+    return nullptr;
+  }
   void SetOpener(BrowsingContext* aOpener) {
+    MOZ_DIAGNOSTIC_ASSERT(!aOpener || aOpener->Group() == Group());
     SetOpenerId(aOpener ? aOpener->Id() : 0);
   }
 
   bool HasOpener() const;
 
+  bool HadOriginalOpener() const { return mHadOriginalOpener; }
+
   /**
    * When a new browsing context is opened by a sandboxed document, it needs to
    * keep track of the browsing context that opened it, so that it can be
    * navigated by it.  This is the "one permitted sandboxed navigator".
    */
   already_AddRefed<BrowsingContext> GetOnePermittedSandboxedNavigator() const {
     return Get(mOnePermittedSandboxedNavigatorId);
   }
@@ -476,19 +485,17 @@ class BrowsingContext : public nsWrapper
 
    protected:
     friend class RemoteLocationProxy;
     BrowsingContext* GetBrowsingContext() override {
       return reinterpret_cast<BrowsingContext*>(
           uintptr_t(this) - offsetof(BrowsingContext, mLocation));
     }
 
-    already_AddRefed<nsIDocShell> GetDocShell() override {
-      return nullptr;
-    }
+    already_AddRefed<nsIDocShell> GetDocShell() override { return nullptr; }
   };
 
   // Ensure that opener is in the same BrowsingContextGroup.
   bool MaySetOpener(const uint64_t& aValue, ContentParent* aSource) {
     if (aValue != 0) {
       RefPtr<BrowsingContext> opener = Get(aValue);
       return opener && opener->Group() == Group();
     }
--- a/docshell/base/BrowsingContextFieldList.h
+++ b/docshell/base/BrowsingContextFieldList.h
@@ -16,16 +16,18 @@ MOZ_BC_FIELD(EmbedderPolicy, nsILoadInfo
 MOZ_BC_FIELD(OpenerPolicy, nsILoadInfo::CrossOriginOpenerPolicy)
 
 // The current opener for this BrowsingContext. This is a weak reference, and
 // stored as the opener ID.
 MOZ_BC_FIELD(OpenerId, uint64_t)
 
 MOZ_BC_FIELD(OnePermittedSandboxedNavigatorId, uint64_t)
 
+MOZ_BC_FIELD(HadOriginalOpener, bool)
+
 // Toplevel browsing contexts only. This field controls whether the browsing
 // context is currently considered to be activated by a gesture.
 MOZ_BC_FIELD(IsActivatedByUserGesture, bool)
 
 // Hold the audio muted state and should be used
 // on top level browsing contexts only.
 MOZ_BC_FIELD(Muted, bool)
 
--- a/docshell/base/nsDSURIContentListener.cpp
+++ b/docshell/base/nsDSURIContentListener.cpp
@@ -11,16 +11,17 @@
 #include "nsDocShellCID.h"
 #include "nsIWebNavigationInfo.h"
 #include "mozilla/dom/Document.h"
 #include "nsIDOMWindow.h"
 #include "nsIHttpChannel.h"
 #include "nsError.h"
 #include "nsContentSecurityManager.h"
 #include "nsDocShellLoadTypes.h"
+#include "nsGlobalWindowOuter.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIMultiPartChannel.h"
 
 using namespace mozilla;
 
 NS_IMPL_ADDREF(MaybeCloseWindowHelper)
 NS_IMPL_RELEASE(MaybeCloseWindowHelper)
 
@@ -43,20 +44,21 @@ void MaybeCloseWindowHelper::SetShouldCl
 
 nsIInterfaceRequestor* MaybeCloseWindowHelper::MaybeCloseWindow() {
   nsCOMPtr<nsPIDOMWindowOuter> window = do_GetInterface(mContentContext);
   NS_ENSURE_TRUE(window, mContentContext);
 
   if (mShouldCloseWindow) {
     // Reset the window context to the opener window so that the dependent
     // dialogs have a parent
-    nsCOMPtr<nsPIDOMWindowOuter> opener = window->GetOpener();
+    nsCOMPtr<nsPIDOMWindowOuter> opener =
+        nsGlobalWindowOuter::Cast(window)->GetSameProcessOpener();
 
     if (opener && !opener->Closed()) {
-      mContentContext = do_GetInterface(opener);
+      mContentContext = do_QueryInterface(opener);
 
       // Now close the old window.  Do it on a timer so that we don't run
       // into issues trying to close the window before it has fully opened.
       NS_ASSERTION(!mTimer, "mTimer was already initialized once!");
       NS_NewTimerWithCallback(getter_AddRefs(mTimer), this, 0,
                               nsITimer::TYPE_ONE_SHOT);
       mWindowToClose = window;
     }
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -14858,22 +14858,22 @@ void Document::MaybeAllowStorageForOpene
   // and the opener are on the same process. In the future, we should make this
   // part async.
 
   nsPIDOMWindowInner* inner = GetInnerWindow();
   if (NS_WARN_IF(!inner)) {
     return;
   }
 
-  nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
+  auto* outer = nsGlobalWindowOuter::Cast(inner->GetOuterWindow());
   if (NS_WARN_IF(!outer)) {
     return;
   }
 
-  nsCOMPtr<nsPIDOMWindowOuter> outerOpener = outer->GetOpener();
+  nsCOMPtr<nsPIDOMWindowOuter> outerOpener = outer->GetSameProcessOpener();
   if (!outerOpener) {
     return;
   }
 
   nsPIDOMWindowInner* openerInner = outerOpener->GetCurrentInnerWindow();
   if (NS_WARN_IF(!openerInner)) {
     return;
   }
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -2079,22 +2079,16 @@ nsresult nsFrameLoader::MaybeCreateDocSh
   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);
 
-  // TODO(farre): Remove this when nsGlobalWindowOuter::GetOpenerWindowOuter
-  // starts using BrowsingContext::GetOpener.
-  if (RefPtr<BrowsingContext> opener = mBrowsingContext->GetOpener()) {
-    newWindow->SetOpenerWindow(opener->GetDOMWindow(), true);
-  }
-
   // Allow scripts to close the docshell if specified.
   if (mOwnerContent->IsXULElement(nsGkAtoms::browser) &&
       mOwnerContent->AttrValueIs(kNameSpaceID_None,
                                  nsGkAtoms::allowscriptstoclose,
                                  nsGkAtoms::_true, eCaseMatters)) {
     nsGlobalWindowOuter::Cast(newWindow)->AllowScriptsToClose();
   }
 
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -3029,37 +3029,43 @@ nsIControllers* nsGlobalWindowInner::Get
 nsresult nsGlobalWindowInner::GetControllers(nsIControllers** aResult) {
   ErrorResult rv;
   nsCOMPtr<nsIControllers> controllers = GetControllers(rv);
   controllers.forget(aResult);
 
   return rv.StealNSResult();
 }
 
-nsPIDOMWindowOuter* nsGlobalWindowInner::GetOpenerWindow(ErrorResult& aError) {
+Nullable<WindowProxyHolder> nsGlobalWindowInner::GetOpenerWindow(
+    ErrorResult& aError) {
   FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
 }
 
 void nsGlobalWindowInner::GetOpener(JSContext* aCx,
                                     JS::MutableHandle<JS::Value> aRetval,
                                     ErrorResult& aError) {
-  nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindow(aError);
-  if (aError.Failed() || !opener) {
+  Nullable<WindowProxyHolder> opener = GetOpenerWindow(aError);
+  if (aError.Failed() || opener.IsNull()) {
     aRetval.setNull();
     return;
   }
 
-  aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
+  if (!ToJSValue(aCx, opener.Value(), aRetval)) {
+    aError.NoteJSContextException(aCx);
+  }
 }
 
 void nsGlobalWindowInner::SetOpener(JSContext* aCx,
                                     JS::Handle<JS::Value> aOpener,
                                     ErrorResult& aError) {
   if (aOpener.isNull()) {
-    FORWARD_TO_OUTER_VOID(SetOpenerWindow, (nullptr, false));
+    RefPtr<BrowsingContext> bc(GetBrowsingContext());
+    if (!bc->IsDiscarded()) {
+      bc->SetOpener(nullptr);
+    }
     return;
   }
 
   // If something other than null is passed, just define aOpener on our inner
   // window's JS object, wrapped into the current compartment so that for Xrays
   // we define on the Xray expando object, but don't set it on the outer window,
   // so that it'll get reset on navigation.  This is just like replaceable
   // properties, but we're not quite readonly.
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -617,17 +617,18 @@ class nsGlobalWindowInner final : public
 
  protected:
   explicit nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow,
                                mozilla::dom::WindowGlobalChild* aActor);
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 
  public:
-  nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetOpenerWindow(
+      mozilla::ErrorResult& aError);
   void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
                  mozilla::ErrorResult& aError);
   void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
                  mozilla::ErrorResult& aError);
   void GetEvent(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
   mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParent(
       mozilla::ErrorResult& aError);
   nsPIDOMWindowOuter* GetInProcessScriptableParent() override;
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -1090,17 +1090,16 @@ static JSObject* NewOuterWindowProxy(JSC
 
 nsGlobalWindowOuter::nsGlobalWindowOuter(uint64_t aWindowID)
     : nsPIDOMWindowOuter(aWindowID),
       mFullscreen(false),
       mFullscreenMode(false),
       mIsClosed(false),
       mInClose(false),
       mHavePendingClose(false),
-      mHadOriginalOpener(false),
       mIsPopupSpam(false),
       mBlockScriptedClosingFlag(false),
       mWasOffline(false),
       mCreatingInnerWindow(false),
       mIsChrome(false),
       mAllowScriptsToClose(false),
       mTopLevelOuterContentWindow(false),
       mHasStorageAccess(false),
@@ -1293,20 +1292,17 @@ void nsGlobalWindowOuter::CleanUp() {
   mCleanedUp = true;
 
   StartDying();
 
   mWindowUtils = nullptr;
 
   ClearControllers();
 
-  mOpener = nullptr;  // Forces Release
-  if (mContext) {
-    mContext = nullptr;  // Forces Release
-  }
+  mContext = nullptr;             // Forces Release
   mChromeEventHandler = nullptr;  // Forces Release
   mParentTarget = nullptr;
   mMessageManager = nullptr;
 
   mArguments = nullptr;
 }
 
 void nsGlobalWindowOuter::ClearControllers() {
@@ -2513,80 +2509,16 @@ void nsGlobalWindowOuter::DetachFromDocS
 
   mDocShell = nullptr;
   mBrowsingContext->ClearDocShell();
 
   MaybeForgiveSpamCount();
   CleanUp();
 }
 
-void nsGlobalWindowOuter::SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
-                                          bool aOriginalOpener) {
-  nsWeakPtr opener = do_GetWeakReference(aOpener);
-  if (opener == mOpener) {
-    MOZ_DIAGNOSTIC_ASSERT(!aOpener || !aOpener->GetDocShell() ||
-                          (GetBrowsingContext() &&
-                           aOpener->GetBrowsingContext() &&
-                           aOpener->GetBrowsingContext()->Id() ==
-                               GetBrowsingContext()->GetOpenerId()));
-    return;
-  }
-
-  NS_ASSERTION(!aOriginalOpener || !mSetOpenerWindowCalled,
-               "aOriginalOpener is true, but not first call to "
-               "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 ||
-        // TODO(farre): Allowing to set a closed or closing window as
-        // opener is not ideal, since it won't have a docshell and
-        // therefore no browsing context. This means that we're
-        // effectively setting the browsing context opener to null and
-        // the window opener to a closed window. This needs to be
-        // cleaned up, see Bug 1511353.
-        nsGlobalWindowOuter::Cast(aOpener)->IsClosedOrClosing() ||
-        // TODO(farre): Allowing to set an opener on a closed window is
-        // not ideal either, but we need to allow it for now. Bug 1543056.
-        IsClosedOrClosing() ||
-        aOpener->GetBrowsingContext()->Id() ==
-            GetBrowsingContext()->GetOpenerId());
-    // TODO(farre): Here we really wish to only consider the case
-    // 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);
-
-  // contentOpener is not used when the DIAGNOSTIC_ASSERT is compiled out.
-  mozilla::Unused << contentOpener;
-  MOZ_DIAGNOSTIC_ASSERT(
-      !contentOpener || !mTabGroup ||
-      mTabGroup == nsGlobalWindowOuter::Cast(contentOpener)->mTabGroup);
-
-  if (aOriginalOpener) {
-    MOZ_ASSERT(!mHadOriginalOpener,
-               "Probably too late to call ComputeIsSecureContext again");
-    mHadOriginalOpener = true;
-  }
-
-#ifdef DEBUG
-  mSetOpenerWindowCalled = true;
-#endif
-}
-
 void nsGlobalWindowOuter::UpdateParentTarget() {
   // NOTE: This method is nearly identical to
   // nsGlobalWindowInner::UpdateParentTarget(). IF YOU UPDATE THIS METHOD,
   // UPDATE THE OTHER ONE TOO!  The one difference is that this method updates
   // mMessageManager as well, which inner windows don't have.
 
   // Try to get our frame element's tab child global (its in-process message
   // manager).  If that fails, fall back to the chrome event handler's tab
@@ -3285,73 +3217,54 @@ nsIControllers* nsGlobalWindowOuter::Get
 
   return mControllers;
 }
 
 nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
   FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
 }
 
-nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSanitizedOpener(
-    nsPIDOMWindowOuter* aOpener) {
-  if (!aOpener) {
-    return nullptr;
-  }
-
-  nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(aOpener);
-
-  // First, ensure that we're not handing back a chrome window to content:
-  if (win->IsChromeWindow()) {
+already_AddRefed<BrowsingContext>
+nsGlobalWindowOuter::GetOpenerBrowsingContext() {
+  RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
+  MOZ_DIAGNOSTIC_ASSERT(!opener ||
+                        opener->Group() == GetBrowsingContext()->Group());
+  if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
     return nullptr;
   }
 
-  // We don't want to reveal the opener if the opener is a mail window,
-  // because opener can be used to spoof the contents of a message (bug 105050).
-  // So, we look in the opener's root docshell to see if it's a mail window.
-  nsCOMPtr<nsIDocShell> openerDocShell = aOpener->GetDocShell();
-
-  if (openerDocShell) {
-    nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
-    openerDocShell->GetInProcessRootTreeItem(getter_AddRefs(openerRootItem));
-    nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
-    if (openerRootDocShell) {
-      nsIDocShell::AppType appType = openerRootDocShell->GetAppType();
-      if (appType != nsIDocShell::APP_TYPE_MAIL) {
-        return aOpener;
-      }
-    }
-  }
-
+  // Catch the case where we're chrome but the opener is not...
+  if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
+      GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
+    auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
+    if (!openerWin ||
+        openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
+      return nullptr;
+    }
+  }
+
+  return opener.forget();
+}
+
+nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
+  if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
+    return opener->GetDOMWindow();
+  }
   return nullptr;
 }
 
-nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOpenerWindowOuter() {
-  nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryReferent(mOpener);
-
-  if (!opener) {
-    return nullptr;
-  }
-
-  // First, check if we were called from a privileged chrome script
-  if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
-    // Catch the case where we're chrome but the opener is not...
-    if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() &&
-        nsGlobalWindowOuter::Cast(opener)->GetPrincipal() !=
-            nsContentUtils::GetSystemPrincipal()) {
-      return nullptr;
-    }
-    return opener;
-  }
-
-  return GetSanitizedOpener(opener);
-}
-
-already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetOpener() {
-  nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindowOuter();
-  return opener.forget();
+Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
+  if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
+    return WindowProxyHolder(opener.forget());
+  }
+  return nullptr;
+}
+
+Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
+  return GetOpenerWindowOuter();
 }
 
 void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
   aStatus = mStatus;
 }
 
 void nsGlobalWindowOuter::SetStatusOuter(const nsAString& aStatus) {
   mStatus = aStatus;
@@ -4735,17 +4648,17 @@ void nsGlobalWindowOuter::MakeScriptDial
   }
 }
 
 bool nsGlobalWindowOuter::CanMoveResizeWindows(CallerType aCallerType) {
   // When called from chrome, we can avoid the following checks.
   if (aCallerType != CallerType::System) {
     // Don't allow scripts to move or resize windows that were not opened by a
     // script.
-    if (!mHadOriginalOpener) {
+    if (!HadOriginalOpener()) {
       return false;
     }
 
     if (!CanSetProperty("dom.disable_window_move_resize")) {
       return false;
     }
 
     // Ignore the request if we have more than one tab in the window.
@@ -4967,23 +4880,25 @@ void nsGlobalWindowOuter::FocusOuter() {
 
   nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
   if (!baseWin) {
     return;
   }
 
   nsCOMPtr<nsPIDOMWindowInner> caller = do_QueryInterface(GetEntryGlobal());
   nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr;
-  nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpener();
+  BrowsingContext* callerBC =
+      callerOuter ? callerOuter->GetBrowsingContext() : nullptr;
+  RefPtr<BrowsingContext> openerBC = GetOpenerBrowsingContext();
 
   // Enforce dom.disable_window_flip (for non-chrome), but still allow the
   // window which opened us to raise us at times when popups are allowed
   // (bugs 355482 and 369306).
   bool canFocus = CanSetProperty("dom.disable_window_flip") ||
-                  (opener == callerOuter &&
+                  (openerBC == callerBC &&
                    RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
                        PopupBlocker::openBlocked);
 
   nsCOMPtr<mozIDOMWindowProxy> activeDOMWindow;
   fm->GetActiveWindow(getter_AddRefs(activeDOMWindow));
 
   nsCOMPtr<nsIDocShellTreeItem> rootItem;
   mDocShell->GetInProcessRootTreeItem(getter_AddRefs(rootItem));
@@ -6278,17 +6193,17 @@ void nsGlobalWindowOuter::CloseOuter(boo
   // Don't allow scripts from content to close non-neterror windows that
   // were not opened by script.
   if (mDoc) {
     nsAutoString url;
     nsresult rv = mDoc->GetURL(url);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     if (!StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
-        !mHadOriginalOpener && !aTrustedCaller) {
+        !HadOriginalOpener() && !aTrustedCaller) {
       bool allowClose =
           mAllowScriptsToClose ||
           Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
       if (!allowClose) {
         // We're blocking the close operation
         // report localized error msg in JS console
         nsContentUtils::ReportToConsole(
             nsIScriptError::warningFlag, NS_LITERAL_CSTRING("DOM Window"),
@@ -7776,21 +7691,21 @@ void nsGlobalWindowOuter::CheckForDPICha
   }
 }
 
 mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() {
   // Outer windows lazily join TabGroups when requested. This is usually done
   // because a document is getting its NodePrincipal, and asking for the
   // TabGroup to determine its DocGroup.
   if (!mTabGroup) {
-    // Get mOpener ourselves, instead of relying on GetOpenerWindowOuter,
+    // Get the opener ourselves, instead of relying on GetOpenerWindowOuter,
     // because that way we dodge the LegacyIsCallerChromeOrNativeCode() call
     // which we want to return false.
-    nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
-    nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
+    RefPtr<BrowsingContext> openerBC = GetBrowsingContext()->GetOpener();
+    nsPIDOMWindowOuter* opener = openerBC ? openerBC->GetDOMWindow() : nullptr;
     nsPIDOMWindowOuter* parent = GetInProcessScriptableParentOrNull();
     MOZ_ASSERT(!parent || !opener,
                "Only one of parent and opener may be provided");
 
     mozilla::dom::TabGroup* toJoin = nullptr;
     if (GetDocShell()->ItemType() == nsIDocShellTreeItem::typeChrome) {
       toJoin = TabGroup::GetChromeTabGroup();
     } else if (opener) {
@@ -7818,19 +7733,21 @@ mozilla::dom::TabGroup* nsGlobalWindowOu
     mIsValidatingTabGroup = true;
     // We only need to do this check if we aren't in the chrome tab group
     if (mIsChrome) {
       MOZ_ASSERT(mTabGroup == TabGroup::GetChromeTabGroup());
     } else {
       // Sanity check that our tabgroup matches our opener or parent.
       RefPtr<nsPIDOMWindowOuter> parent = GetInProcessScriptableParentOrNull();
       MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
-      nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
-      nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
-      MOZ_ASSERT_IF(opener && nsGlobalWindowOuter::Cast(opener) != this,
+
+      RefPtr<BrowsingContext> openerBC = GetBrowsingContext()->GetOpener();
+      nsPIDOMWindowOuter* opener =
+          openerBC ? openerBC->GetDOMWindow() : nullptr;
+      MOZ_ASSERT_IF(opener && Cast(opener) != this,
                     opener->TabGroup() == mTabGroup);
     }
     mIsValidatingTabGroup = false;
   }
 #endif
 
   return mTabGroup;
 }
--- a/dom/base/nsGlobalWindowOuter.h
+++ b/dom/base/nsGlobalWindowOuter.h
@@ -318,19 +318,16 @@ class nsGlobalWindowOuter final : public
       mozilla::dom::WindowGlobalChild* aActor = nullptr) override;
 
   // Outer windows only.
   static void PrepareForProcessChange(JSObject* aProxy);
 
   // Outer windows only.
   void DispatchDOMWindowCreated();
 
-  virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
-                               bool aOriginalOpener) override;
-
   // Outer windows only.
   virtual void EnsureSizeAndPositionUpToDate() override;
 
   MOZ_CAN_RUN_SCRIPT_BOUNDARY virtual void EnterModalState() override;
   virtual void LeaveModalState() override;
 
   // Outer windows only.
   virtual bool CanClose() override;
@@ -451,17 +448,19 @@ class nsGlobalWindowOuter final : public
 
   void MaybeForgiveSpamCount();
   bool IsClosedOrClosing() {
     return (mIsClosed || mInClose || mHavePendingClose || mCleanedUp);
   }
 
   bool IsCleanedUp() const { return mCleanedUp; }
 
-  bool HadOriginalOpener() const { return mHadOriginalOpener; }
+  bool HadOriginalOpener() const {
+    return GetBrowsingContext()->HadOriginalOpener();
+  }
 
   bool IsTopLevelWindow();
 
   virtual void FirePopupBlockedEvent(
       Document* aDoc, nsIURI* aPopupURI, const nsAString& aPopupWindowName,
       const nsAString& aPopupWindowFeatures) override;
 
   virtual void NotifyContentBlockingEvent(
@@ -543,24 +542,25 @@ class nsGlobalWindowOuter final : public
   uint32_t Length();
   mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetTopOuter();
 
   nsresult GetPrompter(nsIPrompt** aPrompt) override;
 
   RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
 
  protected:
-  nsPIDOMWindowOuter* GetOpenerWindowOuter();
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder>
+  GetOpenerWindowOuter();
   // Initializes the mWasOffline member variable
   void InitWasOffline();
 
  public:
-  nsPIDOMWindowOuter* GetSanitizedOpener(nsPIDOMWindowOuter* aOpener);
-
-  already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
+  nsPIDOMWindowOuter* GetSameProcessOpener();
+  already_AddRefed<mozilla::dom::BrowsingContext> GetOpenerBrowsingContext();
+  mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetOpener() override;
   mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParentOuter();
   already_AddRefed<nsPIDOMWindowOuter> GetInProcessParent() override;
   nsPIDOMWindowOuter* GetInProcessScriptableParent() override;
   nsPIDOMWindowOuter* GetInProcessScriptableParentOrNull() override;
   mozilla::dom::Element* GetFrameElementOuter(nsIPrincipal& aSubjectPrincipal);
   mozilla::dom::Element* GetFrameElement() override;
   mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> OpenOuter(
       const nsAString& aUrl, const nsAString& aName, const nsAString& aOptions,
@@ -1069,17 +1069,16 @@ class nsGlobalWindowOuter final : public
   bool mFullscreen : 1;
   bool mFullscreenMode : 1;
   bool mIsClosed : 1;
   bool mInClose : 1;
   // mHavePendingClose means we've got a termination function set to
   // close us when the JS stops executing or that we have a close
   // event posted.  If this is set, just ignore window.close() calls.
   bool mHavePendingClose : 1;
-  bool mHadOriginalOpener : 1;
   bool mIsPopupSpam : 1;
 
   // Indicates whether scripts are allowed to close this window.
   bool mBlockScriptedClosingFlag : 1;
 
   // Window offline status. Checked to see if we need to fire offline event
   bool mWasOffline : 1;
 
@@ -1095,17 +1094,16 @@ class nsGlobalWindowOuter final : public
   bool mAllowScriptsToClose : 1;
 
   bool mTopLevelOuterContentWindow : 1;
 
   // whether storage access has been granted to this frame.
   bool mHasStorageAccess : 1;
 
   nsCOMPtr<nsIScriptContext> mContext;
-  nsWeakPtr mOpener;
   nsCOMPtr<nsIControllers> mControllers;
 
   // For |window.arguments|, via |openDialog|.
   nsCOMPtr<nsIArray> mArguments;
 
   RefPtr<nsDOMWindowUtils> mWindowUtils;
   nsString mStatus;
 
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -881,26 +881,16 @@ class nsPIDOMWindowOuter : public mozIDO
    *
    * aDocument must not be null.
    */
   virtual nsresult SetNewDocument(
       Document* aDocument, nsISupports* aState, bool aForceReuseInnerWindow,
       mozilla::dom::WindowGlobalChild* aActor = nullptr) = 0;
 
   /**
-   * Set the opener window.  aOriginalOpener is true if and only if this is the
-   * original opener for the window.  That is, it can only be true at most once
-   * during the life cycle of a window, and then only the first time
-   * SetOpenerWindow is called.  It might never be true, of course, if the
-   * window does not have an opener when it's created.
-   */
-  virtual void SetOpenerWindow(nsPIDOMWindowOuter* aOpener,
-                               bool aOriginalOpener) = 0;
-
-  /**
    * Ensure the size and position of this window are up-to-date by doing
    * a layout flush in the parent (which will in turn, do a layout flush
    * in its parent, etc.).
    */
   virtual void EnsureSizeAndPositionUpToDate() = 0;
 
   /**
    * Callback for notifying a window about a modal dialog being
@@ -1042,17 +1032,18 @@ class nsPIDOMWindowOuter : public mozIDO
   // XXX(nika): These feel like they should be inner window only, but they're
   // called on the outer window.
   virtual mozilla::dom::Navigator* GetNavigator() = 0;
   virtual mozilla::dom::Location* GetLocation() = 0;
 
   virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
   virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
   virtual already_AddRefed<mozilla::dom::Selection> GetSelection() = 0;
-  virtual already_AddRefed<nsPIDOMWindowOuter> GetOpener() = 0;
+  virtual mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder>
+  GetOpener() = 0;
 
   // aLoadState will be passed on through to the windowwatcher.
   // aForceNoOpener will act just like a "noopener" feature in aOptions except
   //                will not affect any other window features.
   virtual nsresult Open(const nsAString& aUrl, const nsAString& aName,
                         const nsAString& aOptions,
                         nsDocShellLoadState* aLoadState, bool aForceNoOpener,
                         mozilla::dom::BrowsingContext** _retval) = 0;
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -957,26 +957,27 @@ nsresult ContentChild::ProvideWindowComm
 
   MOZ_ASSERT(ipcContext);
   TabId tabId(nsContentUtils::GenerateTabId());
 
   // We need to assign a TabGroup to the PBrowser actor before we send it to the
   // parent. Otherwise, the parent could send messages to us before we have a
   // proper TabGroup for that actor.
   RefPtr<TabGroup> tabGroup;
+  RefPtr<BrowsingContext> openerBC;
   if (aTabOpener && !aForceNoOpener) {
     // The new actor will use the same tab group as the opener.
     tabGroup = aTabOpener->TabGroup();
+    if (aParent) {
+      openerBC = nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext();
+    }
   } else {
     tabGroup = new TabGroup();
   }
 
-  RefPtr<BrowsingContext> openerBC =
-      aParent ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext()
-              : nullptr;
   RefPtr<BrowsingContext> browsingContext = BrowsingContext::Create(
       nullptr, openerBC, aName, BrowsingContext::Type::Content);
 
   TabContext newTabContext = aTabOpener ? *aTabOpener : TabContext();
 
   // The initial about:blank document we generate within the nsDocShell will
   // almost certainly be replaced at some point. Unfortunately, getting the
   // principal right here causes bugs due to frame scripts not getting events
@@ -1094,27 +1095,35 @@ nsresult ContentChild::ProvideWindowComm
                           true, false, aTabOpener->WebWidget()->GetDPI(),
                           aTabOpener->WebWidget()->RoundsWidgetCoordinatesTo(),
                           aTabOpener->WebWidget()->GetDefaultScale().scale);
     }
 
     newChild->SetMaxTouchPoints(maxTouchPoints);
     newChild->SetHasSiblings(hasSiblings);
 
-    // Set the opener window for this window before we start loading the
-    // document inside of it. We have to do this before loading the remote
-    // scripts, because they can poke at the document and cause the Document
-    // to be created before the openerwindow
-    nsCOMPtr<mozIDOMWindowProxy> windowProxy =
-        do_GetInterface(newChild->WebNavigation());
-    if (!aForceNoOpener && windowProxy && aParent) {
-      nsPIDOMWindowOuter* outer = nsPIDOMWindowOuter::From(windowProxy);
-      nsPIDOMWindowOuter* parent = nsPIDOMWindowOuter::From(aParent);
-      outer->SetOpenerWindow(parent, *aWindowIsNew);
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+    if (nsCOMPtr<nsPIDOMWindowOuter> outer =
+            do_GetInterface(newChild->WebNavigation())) {
+      BrowsingContext* bc = outer->GetBrowsingContext();
+      auto parentBC =
+          aParent
+              ? nsPIDOMWindowOuter::From(aParent)->GetBrowsingContext()->Id()
+              : 0;
+
+      if (aForceNoOpener) {
+        MOZ_DIAGNOSTIC_ASSERT(!*aWindowIsNew || !bc->HadOriginalOpener());
+        MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == 0);
+      } else {
+        MOZ_DIAGNOSTIC_ASSERT(!*aWindowIsNew ||
+                              bc->HadOriginalOpener() == !!parentBC);
+        MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == parentBC);
+      }
     }
+#endif
 
     // Unfortunately we don't get a window unless we've shown the frame.  That's
     // pretty bogus; see bug 763602.
     newChild->DoFakeShow(showInfo);
 
     newChild->RecvUpdateDimensions(dimensionInfo);
 
     for (size_t i = 0; i < frameScripts.Length(); i++) {
--- a/dom/tests/mochitest/bugs/mochitest.ini
+++ b/dom/tests/mochitest/bugs/mochitest.ini
@@ -33,16 +33,18 @@ support-files =
   file_redirector.sjs
   file_prime_cookie.html
   test1_bug369306.html
   test2_bug369306.html
   test1_bug622361.html
   test2_bug622361.html
   file1_bug414291.html
   file2_bug414291.html
+prefs =
+  fission.rebuild_frameloaders_on_remoteness_change=true
 
 [test_DOMWindowCreated_chromeonly.html]
 [test_bug132255.html]
 [test_bug1551425_reference_to_childnodes_nodelist_keeps_childnodes_alive.html]
 [test_bug159849.html]
 [test_bug289714.html]
 [test_bug260264.html]
 skip-if = fission || toolkit == 'android'
--- a/dom/tests/mochitest/localstorage/mochitest.ini
+++ b/dom/tests/mochitest/localstorage/mochitest.ini
@@ -13,16 +13,18 @@ support-files =
   frameSlaveNotEqual.html
   interOriginFrame.js
   interOriginTest.js
   interOriginTest2.js
   localStorageCommon.js
   frameLocalStorageSessionOnly.html
   file_tryAccessSessionStorage.html
   windowProxy.html
+prefs =
+  fission.rebuild_frameloaders_on_remoteness_change=true
 
 [test_brokenUTF-16.html]
 [test_bug600307-DBOps.html]
 [test_bug746272-1.html]
 [test_bug746272-2.html]
 skip-if = os == "android" || verify # bug 962029
 [test_cookieBlock.html]
 [test_embededNulls.html]
@@ -48,11 +50,10 @@ skip-if = toolkit == 'android' #TIMED_OU
 fail-if = fission
 [test_localStorageQuota.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_localStorageQuotaSessionOnly.html]
 skip-if = toolkit == 'android' || (verify && (os == 'linux' || os == 'mac' || os == 'win')) #TIMED_OUT
 [test_localStorageQuotaSessionOnly2.html]
 skip-if = true # bug 1347690
 [test_localStorageReplace.html]
-fail-if = fission
 skip-if = toolkit == 'android'
 [test_storageConstructor.html]
--- a/dom/tests/mochitest/sessionstorage/mochitest.ini
+++ b/dom/tests/mochitest/sessionstorage/mochitest.ini
@@ -2,19 +2,20 @@
 support-files =
   file_http.html
   file_https.html
   frameEqual.html
   frameNotEqual.html
   frameReplace.html
   interOriginSlave.js
   interOriginTest.js
+prefs =
+  fission.rebuild_frameloaders_on_remoteness_change=true
 
 [test_sessionStorageBase.html]
 [test_sessionStorageBaseSessionOnly.html]
 [test_sessionStorageClone.html]
-fail-if = fission
 skip-if = toolkit == 'android'
 [test_sessionStorageHttpHttps.html]
 skip-if = toolkit == 'android' #TIMED_OUT
 [test_sessionStorageReplace.html]
 fail-if = fission
 [test_sessionStorageUsage.html]
--- a/dom/tests/mochitest/whatwg/mochitest.ini
+++ b/dom/tests/mochitest/whatwg/mochitest.ini
@@ -10,40 +10,39 @@ support-files =
   postMessage_onOther.html
   postMessage_origin_helper.xhtml
   postMessage_override_helper.html
   postMessage_structured_clone_helper.html
   postMessage_structured_clone_helper.js
   postMessage_throw_helper.html
   postMessage_transfer_helper.html
   postMessage_userpass_helper.html
+prefs =
+  fission.rebuild_frameloaders_on_remoteness_change=true
 
 [test_bug477323.html]
 [test_document_scripts.html]
 [test_MessageEvent_dispatchToOther.html]
 [test_MessageEvent.html]
 [test_postMessage_basehref.html]
 [test_postMessage_closed.html]
 skip-if = toolkit == 'android' #bug 894914 - wrong data - got FAIL, expected message
 [test_postMessage_hash.html]
 [test_postMessage.html]
 skip-if = fission # Timeouts
 [test_postMessage_idn.xhtml]
 skip-if = fission # Timeouts
 [test_postMessage_joined.html]
 skip-if = fission # Timeouts
 [test_postMessage_onOther.html]
-skip-if = fission #Bug 1571273
 [test_postMessage_origin.xhtml]
 skip-if = fission # Timeouts
 [test_postMessage_override.html]
 skip-if = fission
 [test_postMessage_special.xhtml]
 [test_postMessage_structured_clone.html]
-skip-if = fission #Bug 1570918
 [test_postMessage_throw.html]
 [test_postMessage_transfer.html]
-skip-if = fission #Bug 1571208
 [test_postMessage_userpass.html]
 skip-if = fission # Timeouts
 [test_bug500328.html]
 skip-if = true || toolkit=='android' # bug 696306, #TIMED_OUT android
 support-files = file_bug500328_1.html file_bug500328_2.html
--- a/dom/websocket/WebSocket.cpp
+++ b/dom/websocket/WebSocket.cpp
@@ -2696,24 +2696,18 @@ nsresult WebSocketImpl::GetLoadingPrinci
     nsCOMPtr<nsPIDOMWindowInner> currentInnerWindow =
         parentWindow->GetCurrentInnerWindow();
     if (NS_WARN_IF(!currentInnerWindow)) {
       return NS_ERROR_DOM_SECURITY_ERR;
     }
 
     // We are at the top. Let's see if we have an opener window.
     if (innerWindow == currentInnerWindow) {
-      ErrorResult error;
-      parentWindow =
-          nsGlobalWindowInner::Cast(innerWindow)->GetOpenerWindow(error);
-      if (NS_WARN_IF(error.Failed())) {
-        error.SuppressException();
-        return NS_ERROR_DOM_SECURITY_ERR;
-      }
-
+      parentWindow = nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow())
+                         ->GetSameProcessOpener();
       if (!parentWindow) {
         break;
       }
 
       if (parentWindow->GetInProcessScriptableTop() ==
           innerWindow->GetInProcessScriptableTop()) {
         break;
       }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ctypes/conversion-to-number.js
@@ -0,0 +1,98 @@
+// Type conversion to number should use ECMA-style semantics.
+
+load(libdir + 'asserts.js');
+
+function test() {
+  function checkValue(type, provided, expected) {
+    assertEq(ctypes[type](provided).value, expected,
+             `ctypes.${type}(${provided}) contains unexpected value`);
+  }
+
+  function checkCantConvert(type, value) {
+    var ctor = ctypes[type];
+    assertTypeErrorMessage(() => ctor(value),
+                           /can't convert the number/);
+  }
+
+  let testInt8 = checkValue.bind(undefined, "int8_t");
+  let testInt8Throws = checkCantConvert.bind(undefined, "int8_t");
+  testInt8(1e100, 0);
+  testInt8Throws(-129);
+  testInt8(-128, -128);
+  testInt8(-1, -1);
+  testInt8(0, 0);
+  testInt8(1, 1);
+  testInt8(127, 127);
+  testInt8Throws(128);
+
+  let testUint8 = checkValue.bind(undefined, "uint8_t");
+  let testUint8Throws = checkCantConvert.bind(undefined, "uint8_t");
+  testUint8(1e100, 0);
+  testUint8Throws(-1);
+  testUint8(0, 0);
+  testUint8(1, 1);
+  testUint8(127, 127);
+  testUint8(128, 128);
+  testUint8(255, 255);
+  testUint8Throws(256);
+
+  let testInt16 = checkValue.bind(undefined, "int16_t");
+  let testInt16Throws = checkCantConvert.bind(undefined, "int16_t");
+  testInt16(1e100, 0);
+  testInt16Throws(-32769);
+  testInt16(-32768, -32768);
+  testInt16(-1, -1);
+  testInt16(0, 0);
+  testInt16(1, 1);
+  testInt16(32767, 32767);
+  testInt16Throws(32768);
+
+  let testUint16 = checkValue.bind(undefined, "uint16_t");
+  let testUint16Throws = checkCantConvert.bind(undefined, "uint16_t");
+  testUint16(1e100, 0);
+  testUint16Throws(-1);
+  testUint16(0, 0);
+  testUint16(1, 1);
+  testUint16(32767, 32767);
+  testUint16(32768, 32768);
+  testUint16(65535, 65535);
+  testUint16Throws(65536);
+
+  let testInt32 = checkValue.bind(undefined, "int32_t");
+  let testInt32Throws = checkCantConvert.bind(undefined, "int32_t");
+  testInt32(1e100, 0);
+  // This probably should pass, but right now doubles fall into a different
+  // code path where no error occurs.  ctypes is probably/hopefully declining in
+  // use now, so just don't bother with this test.
+  //testInt32Throws(-2147483649);
+  testInt32(-2147483648, -2147483648);
+  testInt32(-1, -1);
+  testInt32(0, 0);
+  testInt32(1, 1);
+  testInt32(2147483647, 2147483647);
+  // This probably should pass, but right now doubles fall into a different
+  // code path where no error occurs.  ctypes is probably/hopefully declining in
+  // use now, so just don't bother with this test.
+  //testInt32Throws(2147483648);
+
+  let testUint32 = checkValue.bind(undefined, "uint32_t");
+  let testUint32Throws = checkCantConvert.bind(undefined, "uint32_t");
+  testUint32(1e100, 0);
+  testUint32Throws(-1);
+  // This probably should pass, but right now doubles fall into a different
+  // code path where no error occurs.  ctypes is probably/hopefully declining in
+  // use now, so just don't bother with this test.
+  //testUint32Throws(-1 * Math.cos(Math.PI)); // -1.0 encoded as a double
+  testUint32(0, 0);
+  testUint32(1, 1);
+  testUint32(2147483647, 2147483647);
+  testUint32(2147483648, 2147483648);
+  testUint32(4294967295, 4294967295);
+  // This probably should pass, but right now doubles fall into a different
+  // code path where no error occurs.  ctypes is probably/hopefully declining in
+  // use now, so just don't bother with this test.
+  //testUint32Throws(4294967296);
+}
+
+if (typeof ctypes === "object")
+  test();
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -80,17 +80,16 @@ skip-if =
   (verify && debug && (os == 'linux')) ||
   fission # Fails intermittently under Fission.
 [test_ext_contentscript_devtools_metadata.html]
 skip-if = (!debug && android_version == '18') #Bug 1523193
 [test_ext_contentscript_incognito.html]
 skip-if = os == 'android' # Android does not support multiple windows.
 [test_ext_contentscript_permission.html]
 [test_ext_cookies.html]
-fail-if = fission
 [test_ext_cookies_containers.html]
 [test_ext_cookies_expiry.html]
 [test_ext_cookies_first_party.html]
 [test_ext_cookies_incognito.html]
 skip-if = os == 'android' # Bug 1513544 Android does not support multiple windows.
 [test_ext_cookies_permissions_bad.html]
 [test_ext_cookies_permissions_good.html]
 [test_ext_exclude_include_globs.html]
--- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp
+++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp
@@ -946,20 +946,29 @@ nsresult nsWindowWatcher::OpenWindowInte
   // so.  Note that it's only nonzero if the window is new, so clobbering
   // sandbox flags on the window makes sense in that case.
   if (activeDocsSandboxFlags &
       SANDBOX_PROPAGATES_TO_AUXILIARY_BROWSING_CONTEXTS) {
     MOZ_ASSERT(windowIsNew, "Should only get here for new windows");
     newDocShell->SetSandboxFlags(activeDocsSandboxFlags);
   }
 
-  nsCOMPtr<nsPIDOMWindowOuter> win(newBC->GetDOMWindow());
+  RefPtr<nsGlobalWindowOuter> win(
+      nsGlobalWindowOuter::Cast(newBC->GetDOMWindow()));
   if (win) {
     if (!aForceNoOpener) {
-      win->SetOpenerWindow(parentWindow, windowIsNew);
+      if (windowIsNew) {
+        // If this is a new window, its opener should have been set when its
+        // BrowsingContext was created. If not, we need to set it ourselves.
+        MOZ_DIAGNOSTIC_ASSERT(newBC->GetOpenerId() ==
+                              (parentBC ? parentBC->Id() : 0));
+        MOZ_DIAGNOSTIC_ASSERT(!!parentBC == newBC->HadOriginalOpener());
+      } else {
+        newBC->SetOpener(parentBC);
+      }
     } else if (parentWindow && parentWindow != win) {
       MOZ_ASSERT(
           win->TabGroup() != parentWindow->TabGroup(),
           "If we're forcing no opener, they should be in different tab groups");
     }
 
     if (windowIsNew) {
 #ifdef DEBUG
@@ -1064,33 +1073,32 @@ nsresult nsWindowWatcher::OpenWindowInte
     NS_ASSERTION(win == newDocShell->GetWindow(), "Different windows??");
 
     // The principal of the initial about:blank document gets set up in
     // nsWindowWatcher::AddWindow. Make sure to call it. In the common case
     // this call already happened when the window was created, but
     // SetInitialPrincipalToSubject is safe to call multiple times.
     if (win) {
       nsCOMPtr<nsIContentSecurityPolicy> cspToInheritForAboutBlank;
-      nsCOMPtr<mozIDOMWindowProxy> targetOpener = win->GetOpener();
+      nsCOMPtr<mozIDOMWindowProxy> targetOpener = win->GetSameProcessOpener();
       nsCOMPtr<nsIDocShell> openerDocShell(do_GetInterface(targetOpener));
       if (openerDocShell) {
         RefPtr<Document> openerDoc =
             static_cast<nsDocShell*>(openerDocShell.get())->GetDocument();
         cspToInheritForAboutBlank = openerDoc ? openerDoc->GetCsp() : nullptr;
       }
       win->SetInitialPrincipalToSubject(cspToInheritForAboutBlank);
 
       if (aIsPopupSpam) {
-        auto* globalWin = nsGlobalWindowOuter::Cast(win);
-        MOZ_ASSERT(!globalWin->IsPopupSpamWindow(),
+        MOZ_ASSERT(!win->IsPopupSpamWindow(),
                    "Who marked it as popup spam already???");
-        if (!globalWin->IsPopupSpamWindow()) {  // Make sure we don't mess up
-                                                // our counter even if the above
-                                                // assert fails.
-          globalWin->SetIsPopupSpamWindow(true);
+        if (!win->IsPopupSpamWindow()) {  // Make sure we don't mess up
+                                          // our counter even if the above
+                                          // assert fails.
+          win->SetIsPopupSpamWindow(true);
         }
       }
     }
   }
 
   // We rely on CalculateChromeFlags to decide whether remote (out-of-process)
   // tabs should be used.
   bool isRemoteWindow =
@@ -1157,17 +1165,18 @@ nsresult nsWindowWatcher::OpenWindowInte
   }
 
   if (isNewToplevelWindow) {
     // Notify observers that the window is open and ready.
     // The window has not yet started to load a document.
     nsCOMPtr<nsIObserverService> obsSvc =
         mozilla::services::GetObserverService();
     if (obsSvc) {
-      obsSvc->NotifyObservers(win, "toplevel-window-ready", nullptr);
+      obsSvc->NotifyObservers(ToSupports(win), "toplevel-window-ready",
+                              nullptr);
     }
   }
 
   // Before loading the URI we want to be 100% sure that we use the correct
   // userContextId.
   MOZ_ASSERT_IF(newDocShell, CheckUserContextCompatibility(newDocShell));
 
   // If this tab or window has been opened by a window.open call, we have to
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -184,17 +184,17 @@ handle to wayland compositor by WindowBa
 
 WindowBackBufferDMABuf
 
 It's WindowBackBuffer implementation based on DMA Buffer.
 It owns wl_buffer object, owns WaylandDMABufSurface
 (which provides the DMA Buffer) and ties them together.
 
 WindowBackBufferDMABuf backend is used only when WaylandDMABufSurface is
-available and gfx.wayland_dmabuf_backend.enabled preference is set.
+available and widget.wayland_dmabuf_backend.enabled preference is set.
 
 */
 
 #define EVENT_LOOP_DELAY (1000 / 240)
 
 #define BUFFER_BPP 4
 gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
 
@@ -499,16 +499,18 @@ WindowSurfaceWayland::WindowSurfaceWayla
       mDelayedCommitHandle(nullptr),
       mDrawToWaylandBufferDirectly(true),
       mPendingCommit(false),
       mWholeWindowBufferDamage(false),
       mBufferNeedsClear(false),
       mIsMainThread(NS_IsMainThread()),
       mNeedScaleFactorUpdate(true) {
   for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr;
+  mRenderingCacheMode = static_cast<RenderingCacheMode>(
+      mWaylandDisplay->GetRenderingCacheModePref());
 }
 
 WindowSurfaceWayland::~WindowSurfaceWayland() {
   if (mPendingCommit) {
     NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
   }
 
   if (mDelayedCommitHandle) {
@@ -805,31 +807,52 @@ already_AddRefed<gfx::DrawTarget> Window
       // This should not happen. Screen size changed but we got only
       // partal screen update instead of whole screen. Discard this painting
       // as it produces artifacts.
       return nullptr;
     }
     mBufferScreenRect = lockedScreenRect;
   }
 
-  if (mWholeWindowBufferDamage) {
+  if (mWholeWindowBufferDamage || mRenderingCacheMode != CACHE_ALL) {
     // We can lock/commit entire buffer direcly.
     mDrawToWaylandBufferDirectly = true;
+  }
 
+  if (mDrawToWaylandBufferDirectly) {
     // If there's any pending image commit scratch them as we're going
     // to redraw the whole sceen anyway.
     mDelayedImageCommits.Clear();
 
     RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(
         /* aCanSwitchBuffer */ mWholeWindowBufferDamage);
     if (dt) {
+      // TODO: Try to set clip regions according to given area provided by
+      // compositor, not sure it has any effect. Also disable when drawing
+      // without any cache to speed up rendering.
+      if (!mWholeWindowBufferDamage && mRenderingCacheMode != CACHE_NONE) {
+        uint32_t numRects = aRegion.GetNumRects();
+        if (numRects != 1) {
+          AutoTArray<IntRect, 32> rects;
+          rects.SetCapacity(numRects);
+          for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
+            rects.AppendElement(iter.Get().ToUnknownRect());
+          }
+          dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length());
+        }
+      }
       return dt.forget();
     }
   }
 
+  // Any caching is disabled and we don't have any back buffer available.
+  if (mRenderingCacheMode == CACHE_NONE) {
+    return nullptr;
+  }
+
   // We do indirect drawing due to:
   //
   // 1) We don't have any front buffer available. Try indirect drawing
   //    to mImageSurface which is mirrored to front buffer at commit.
   // 2) Only part of the screen is locked. We can't lock entire screen for
   //    such drawing as it produces visible artifacts.
   mDrawToWaylandBufferDirectly = false;
 
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -170,16 +170,31 @@ class WindowSurfaceWayland : public Wind
   ~WindowSurfaceWayland();
 
   already_AddRefed<gfx::DrawTarget> Lock(
       const LayoutDeviceIntRegion& aRegion) override;
   void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
   void FrameCallbackHandler();
   void DelayedCommitHandler();
 
+  // Image cache mode can be set by widget.wayland_cache_mode
+  typedef enum {
+    // Cache and clip all drawings, default. It's slowest
+    // but also without any rendered artifacts.
+    CACHE_ALL = 0,
+    // Cache drawing only when back buffer is missing. May produce
+    // some rendering artifacts and flickering when partial screen update
+    // is rendered.
+    CACHE_MISSING = 1,
+    // Don't cache anything, draw only when back buffer is available.
+    // Suitable for fullscreen content only like fullscreen video playback and
+    // may work well with dmabuf backend.
+    CACHE_NONE = 2
+  } RenderingCacheMode;
+
  private:
   WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight);
   WindowBackBuffer* GetWaylandBufferToDraw(bool aCanSwitchBuffer);
 
   already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(bool aCanSwitchBuffer);
   void UnlockWaylandBuffer();
 
   already_AddRefed<gfx::DrawTarget> LockImageSurface(
@@ -210,16 +225,17 @@ class WindowSurfaceWayland : public Wind
   RefPtr<gfxImageSurface> mImageSurface;
   AutoTArray<WindowImageSurface, 30> mDelayedImageCommits;
   bool mDrawToWaylandBufferDirectly;
   bool mPendingCommit;
   bool mWholeWindowBufferDamage;
   bool mBufferNeedsClear;
   bool mIsMainThread;
   bool mNeedScaleFactorUpdate;
+  RenderingCacheMode mRenderingCacheMode;
 
   static bool UseDMABufBackend();
   static bool mUseDMABufInitialized;
   static bool mUseDMABuf;
 };
 
 }  // namespace widget
 }  // namespace mozilla
--- a/widget/gtk/nsWaylandDisplay.cpp
+++ b/widget/gtk/nsWaylandDisplay.cpp
@@ -8,20 +8,25 @@
 #include "nsWaylandDisplay.h"
 
 namespace mozilla {
 namespace widget {
 
 #define GBMLIB_NAME "libgbm.so.1"
 #define DRMLIB_NAME "libdrm.so.2"
 
+#define DMABUF_PREF "widget.wayland_dmabuf_backend.enabled"
+// See WindowSurfaceWayland::RenderingCacheMode for details.
+#define CACHE_MODE_PREF "widget.wayland_cache_mode"
+
 bool nsWaylandDisplay::mIsDMABufEnabled = false;
 // -1 mean the pref was not loaded yet
 int nsWaylandDisplay::mIsDMABufPrefState = -1;
 bool nsWaylandDisplay::mIsDMABufConfigured = false;
+int nsWaylandDisplay::mRenderingCacheModePref = -1;
 
 wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay) {
   if (!aGdkDisplay) {
     aGdkDisplay = gdk_display_get_default();
   }
 
   // Available as of GTK 3.8+
   static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay*))
@@ -312,24 +317,25 @@ nsWaylandDisplay::nsWaylandDisplay(wl_di
       mXRGBFormat({false, false, -1, nullptr, 0}),
       mARGBFormat({false, false, -1, nullptr, 0}),
       mGdmConfigured(false),
       mExplicitSync(false) {
   mRegistry = wl_display_get_registry(mDisplay);
   wl_registry_add_listener(mRegistry, &registry_listener, this);
 
   if (NS_IsMainThread()) {
-    // We can't load the preference from compositor/render thread,
-    // only from main one. So we can't call it directly from
-    // nsWaylandDisplay::IsDMABufEnabled() as it can be called from various
-    // threads.
+    // We can't load the preference from compositor/render thread
+    // so load all Wayland prefs here.
     if (mIsDMABufPrefState == -1) {
-      mIsDMABufPrefState =
-          Preferences::GetBool("widget.wayland_dmabuf_backend.enabled", false);
+      mIsDMABufPrefState = Preferences::GetBool(DMABUF_PREF, false);
     }
+    if (mRenderingCacheModePref == -1) {
+      mRenderingCacheModePref = Preferences::GetInt(CACHE_MODE_PREF, 0);
+    }
+
     // Use default event queue in main thread operated by Gtk+.
     mEventQueue = nullptr;
     wl_display_roundtrip(mDisplay);
     wl_display_roundtrip(mDisplay);
   } else {
     mDispatcherThreadLoop = MessageLoop::current();
     mEventQueue = wl_display_create_queue(mDisplay);
     wl_proxy_set_queue((struct wl_proxy*)mRegistry, mEventQueue);
--- a/widget/gtk/nsWaylandDisplay.h
+++ b/widget/gtk/nsWaylandDisplay.h
@@ -72,16 +72,19 @@ class nsWaylandDisplay {
   bool IsExplicitSyncEnabled() { return mExplicitSync; }
   GbmFormat* GetGbmFormat(bool aHasAlpha);
   GbmFormat* GetExactGbmFormat(int aFormat);
 
   void AddFormatModifier(bool aHasAlpha, int aFormat, uint32_t mModifierHi,
                          uint32_t mModifierLo);
   static bool IsDMABufEnabled();
 
+  // See WindowSurfaceWayland::CacheMode for details.
+  int GetRenderingCacheModePref() { return mRenderingCacheModePref; };
+
  private:
   bool ConfigureGbm();
 
   MessageLoop* mDispatcherThreadLoop;
   PRThread* mThreadId;
   wl_display* mDisplay;
   wl_event_queue* mEventQueue;
   wl_data_device_manager* mDataDeviceManager;
@@ -95,16 +98,17 @@ class nsWaylandDisplay {
   int mGbmFd;
   GbmFormat mXRGBFormat;
   GbmFormat mARGBFormat;
   bool mGdmConfigured;
   bool mExplicitSync;
   static bool mIsDMABufEnabled;
   static int mIsDMABufPrefState;
   static bool mIsDMABufConfigured;
+  static int mRenderingCacheModePref;
 };
 
 void WaylandDispatchDisplays();
 void WaylandDisplayShutdown();
 nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
 wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay = nullptr);
 
 typedef struct gbm_device* (*CreateDeviceFunc)(int);
--- a/xpfe/appshell/nsWebShellWindow.cpp
+++ b/xpfe/appshell/nsWebShellWindow.cpp
@@ -205,21 +205,25 @@ nsresult nsWebShellWindow::Initialize(
 
   // Attach a WebProgress listener.during initialization...
   nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(mDocShell, &rv));
   if (webProgress) {
     webProgress->AddProgressListener(this,
                                      nsIWebProgress::NOTIFY_STATE_NETWORK);
   }
 
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   if (aOpenerWindow) {
-    nsPIDOMWindowOuter* window = mDocShell->GetWindow();
-    MOZ_ASSERT(window);
-    window->SetOpenerWindow(nsPIDOMWindowOuter::From(aOpenerWindow), true);
+    BrowsingContext* bc = mDocShell->GetBrowsingContext();
+    BrowsingContext* openerBC =
+        nsPIDOMWindowOuter::From(aOpenerWindow)->GetBrowsingContext();
+    MOZ_DIAGNOSTIC_ASSERT(bc->GetOpenerId() == openerBC->Id());
+    MOZ_DIAGNOSTIC_ASSERT(bc->HadOriginalOpener());
   }
+#endif
 
   // Eagerly create an about:blank content viewer with the right principal here,
   // rather than letting it happening in the upcoming call to
   // SetInitialPrincipalToSubject. This avoids creating the about:blank document
   // and then blowing it away with a second one, which can cause problems for
   // the top-level chrome window case. See bug 789773. Note that we don't accept
   // expanded principals here, similar to SetInitialPrincipalToSubject.
   if (nsContentUtils::IsInitialized()) {  // Sometimes this happens really early