Bug 1590782 - Switch process when InternalLoad finds oop BrowsingContext. r=mattwoodrow
authorAndreas Farre <farre@mozilla.com>
Tue, 12 Nov 2019 21:52:18 +0000
changeset 501670 09005ea3861f549d6f4f613d1e83fe18fd13ebc8
parent 501669 ac269d3b31551eb918685c274bb07b5e6db3511d
child 501671 b562df92157acd793a7da500c718f95685c91990
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1590782
milestone72.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 1590782 - Switch process when InternalLoad finds oop BrowsingContext. r=mattwoodrow Differential Revision: https://phabricator.services.mozilla.com/D50945
docshell/base/BrowsingContext.cpp
docshell/base/BrowsingContext.h
docshell/base/BrowsingContextFieldList.h
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/test/navigation/mochitest.ini
dom/ipc/PWindowGlobal.ipdl
dom/ipc/WindowGlobalChild.cpp
dom/ipc/WindowGlobalChild.h
dom/ipc/WindowGlobalParent.cpp
dom/ipc/WindowGlobalParent.h
--- a/docshell/base/BrowsingContext.cpp
+++ b/docshell/base/BrowsingContext.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/Components.h"
 #include "mozilla/HashTable.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsIURIFixup.h"
 
 #include "nsDocShell.h"
+#include "nsFocusManager.h"
 #include "nsGlobalWindowOuter.h"
 #include "nsIObserverService.h"
 #include "nsContentUtils.h"
 #include "nsScriptError.h"
 #include "nsThreadUtils.h"
 #include "xpcprivate.h"
 
 #include "AutoplayPolicy.h"
@@ -205,16 +206,18 @@ BrowsingContext::BrowsingContext(Browsin
       mGroup(aGroup),
       mParent(aParent),
       mIsInProcess(false),
       mIsDiscarded(false),
       mDanglingRemoteOuterProxies(false) {
   MOZ_RELEASE_ASSERT(!mParent || mParent->Group() == mGroup);
   MOZ_RELEASE_ASSERT(mBrowsingContextId != 0);
   MOZ_RELEASE_ASSERT(mGroup);
+
+  mIsActive = true;
 }
 
 void BrowsingContext::SetDocShell(nsIDocShell* aDocShell) {
   // XXX(nika): We should communicate that we are now an active BrowsingContext
   // process to the parent & do other validation here.
   MOZ_RELEASE_ASSERT(aDocShell->GetBrowsingContext() == this);
   mDocShell = aDocShell;
   mDanglingRemoteOuterProxies = !mIsInProcess;
@@ -878,16 +881,67 @@ nsresult BrowsingContext::LoadURI(Browsi
     if (WindowGlobalChild* wgc =
             win->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
       wgc->SendLoadURI(this, aLoadState, aSetNavigating);
     }
   }
   return NS_OK;
 }
 
+nsresult BrowsingContext::InternalLoad(BrowsingContext* aAccessor,
+                                       nsDocShellLoadState* aLoadState,
+                                       nsIDocShell** aDocShell,
+                                       nsIRequest** aRequest) {
+  if (IsDiscarded() || (aAccessor && aAccessor->IsDiscarded())) {
+    return NS_OK;
+  }
+
+  bool isActive =
+      aAccessor->GetIsActive() && !mIsActive &&
+      !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false);
+  if (mDocShell) {
+    nsresult rv = nsDocShell::Cast(mDocShell)->InternalLoad(
+        aLoadState, aDocShell, aRequest);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Switch to target tab if we're currently focused window.
+    // Take loadDivertedInBackground into account so the behavior would be
+    // the same as how the tab first opened.
+    nsCOMPtr<nsPIDOMWindowOuter> domWin = GetDOMWindow();
+    if (isActive && domWin) {
+      nsFocusManager::FocusWindow(domWin);
+    }
+
+    // Else we ran out of memory, or were a popup and got blocked,
+    // or something.
+
+    return rv;
+  }
+
+  if (!aAccessor && XRE_IsParentProcess()) {
+    Unused << Canonical()->GetCurrentWindowGlobal()->SendInternalLoadInChild(
+        aLoadState, isActive);
+  } else {
+    MOZ_DIAGNOSTIC_ASSERT(aAccessor);
+    MOZ_DIAGNOSTIC_ASSERT(aAccessor->Group() == Group());
+
+    if (!aAccessor->CanAccess(this)) {
+      return NS_ERROR_DOM_PROP_ACCESS_DENIED;
+    }
+
+    nsCOMPtr<nsPIDOMWindowOuter> win(aAccessor->GetDOMWindow());
+    MOZ_DIAGNOSTIC_ASSERT(win);
+    if (WindowGlobalChild* wgc =
+            win->GetCurrentInnerWindow()->GetWindowGlobalChild()) {
+      wgc->SendInternalLoad(this, aLoadState);
+    }
+  }
+  return NS_OK;
+}
+
 void BrowsingContext::DisplayLoadError(const nsAString& aURI) {
   MOZ_LOG(GetLog(), LogLevel::Debug, ("DisplayLoadError"));
   MOZ_DIAGNOSTIC_ASSERT(!IsDiscarded());
   MOZ_DIAGNOSTIC_ASSERT(mDocShell || XRE_IsParentProcess());
 
   if (mDocShell) {
     bool didDisplayLoadError = false;
     mDocShell->DisplayLoadError(NS_ERROR_MALFORMED_URI, nullptr,
--- a/docshell/base/BrowsingContext.h
+++ b/docshell/base/BrowsingContext.h
@@ -188,16 +188,20 @@ class BrowsingContext : public nsISuppor
   void RestoreChildren(Children&& aChildren, bool aFromIPC = false);
 
   // Triggers a load in the process which currently owns this BrowsingContext.
   // aAccessor is the context which initiated the load, and may be null only for
   // in-process BrowsingContexts.
   nsresult LoadURI(BrowsingContext* aAccessor, nsDocShellLoadState* aLoadState,
                    bool aSetNavigating = false);
 
+  nsresult InternalLoad(BrowsingContext* aAccessor,
+                        nsDocShellLoadState* aLoadState,
+                        nsIDocShell** aDocShell, nsIRequest** aRequest);
+
   void DisplayLoadError(const nsAString& aURI);
 
   // Determine if the current BrowsingContext was 'cached' by the logic in
   // CacheChildren.
   bool IsCached();
 
   // Check that this browsing context is targetable for navigations (i.e. that
   // it is neither closed, cached, nor discarded).
--- a/docshell/base/BrowsingContextFieldList.h
+++ b/docshell/base/BrowsingContextFieldList.h
@@ -7,16 +7,17 @@
 // Fields are, by default, settable by any process and readable by any process.
 // Racy sets will be resolved as-if they occurred in the order the parent
 // process finds out about them.
 //
 // Process restrictions may be added by declaring a method `MaySet{name}` on
 // `BrowsingContext`.
 MOZ_BC_FIELD(Name, nsString)
 MOZ_BC_FIELD(Closed, bool)
+MOZ_BC_FIELD(IsActive, bool)
 MOZ_BC_FIELD(EmbedderPolicy, nsILoadInfo::CrossOriginEmbedderPolicy)
 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)
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -358,17 +358,16 @@ nsDocShell::nsDocShell(BrowsingContext* 
       mAllowContentRetargetingOnChildren(true),
       mUseErrorPages(false),
       mUseStrictSecurityChecks(false),
       mObserveErrorPages(true),
       mCSSErrorReportingEnabled(false),
       mAllowAuth(mItemType == typeContent),
       mAllowKeywordFixup(false),
       mIsOffScreenBrowser(false),
-      mIsActive(true),
       mDisableMetaRefreshWhenInactive(false),
       mIsAppTab(false),
       mUseGlobalHistory(false),
       mUseRemoteTabs(false),
       mUseRemoteSubframes(false),
       mUseTrackingProtection(false),
       mDeviceSizeIsPageSize(false),
       mWindowDraggingAllowed(false),
@@ -1042,18 +1041,19 @@ bool nsDocShell::MaybeInitTiming() {
   }
 
   if (!mTiming) {
     mTiming = new nsDOMNavigationTiming(this);
     canBeReset = true;
   }
 
   mTiming->NotifyNavigationStart(
-      mIsActive ? nsDOMNavigationTiming::DocShellState::eActive
-                : nsDOMNavigationTiming::DocShellState::eInactive);
+      mBrowsingContext->GetIsActive()
+          ? nsDOMNavigationTiming::DocShellState::eActive
+          : nsDOMNavigationTiming::DocShellState::eInactive);
 
   return canBeReset;
 }
 
 void nsDocShell::MaybeResetInitTiming(bool aReset) {
   if (aReset) {
     mTiming = nullptr;
   }
@@ -5015,17 +5015,17 @@ NS_IMETHODIMP
 nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen) {
   *aIsOffScreen = mIsOffScreenBrowser;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetIsActive(bool aIsActive) {
   // Keep track ourselves.
-  mIsActive = aIsActive;
+  mBrowsingContext->SetIsActive(aIsActive);
 
   // Tell the PresShell about it.
   if (RefPtr<PresShell> presShell = GetPresShell()) {
     presShell->SetIsActive(aIsActive);
   }
 
   // Tell the window about it
   if (mScriptGlobal) {
@@ -5071,29 +5071,29 @@ nsDocShell::SetIsActive(bool aIsActive) 
 
     if (!docshell->GetIsMozBrowser()) {
       docshell->SetIsActive(aIsActive);
     }
   }
 
   // Restart or stop meta refresh timers if necessary
   if (mDisableMetaRefreshWhenInactive) {
-    if (mIsActive) {
+    if (mBrowsingContext->GetIsActive()) {
       ResumeRefreshURIs();
     } else {
       SuspendRefreshURIs();
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::GetIsActive(bool* aIsActive) {
-  *aIsActive = mIsActive;
+  *aIsActive = mBrowsingContext->GetIsActive();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetIsAppTab(bool aIsAppTab) {
   mIsAppTab = aIsAppTab;
   return NS_OK;
 }
@@ -5437,17 +5437,17 @@ nsDocShell::RefreshURI(nsIURI* aURI, nsI
 
   BusyFlags busyFlags = GetBusyFlags();
 
   if (!mRefreshURIList) {
     mRefreshURIList = nsArray::Create();
   }
 
   if (busyFlags & BUSY_FLAGS_BUSY ||
-      (!mIsActive && mDisableMetaRefreshWhenInactive)) {
+      (!mBrowsingContext->GetIsActive() && mDisableMetaRefreshWhenInactive)) {
     // We don't  want to create the timer right now. Instead queue up the
     // request and trigger the timer in EndPageLoad() or whenever we become
     // active.
     mRefreshURIList->AppendElement(refreshTimer);
   } else {
     // There is no page loading going on right now.  Create the
     // timer and fire it right away.
     nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
@@ -6330,17 +6330,18 @@ nsresult nsDocShell::EndPageLoad(nsIWebP
     mLSHE->SetLoadType(LOAD_HISTORY);
 
     // Clear the mLSHE reference to indicate document loading is done one
     // way or another.
     SetHistoryEntry(&mLSHE, nullptr);
   }
   // if there's a refresh header in the channel, this method
   // will set it up for us.
-  if (mIsActive || !mDisableMetaRefreshWhenInactive) RefreshURIFromQueue();
+  if (mBrowsingContext->GetIsActive() || !mDisableMetaRefreshWhenInactive)
+    RefreshURIFromQueue();
 
   // Test whether this is the top frame or a subframe
   bool isTopFrame = true;
   nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
   rv = GetInProcessSameTypeParent(getter_AddRefs(targetParentTreeItem));
   if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
     isTopFrame = false;
   }
@@ -7608,17 +7609,17 @@ nsresult nsDocShell::RestoreFromHistory(
     bool allowContentRetargetingOnChildren =
         childShell->GetAllowContentRetargetingOnChildren();
 
     uint32_t defaultLoadFlags;
     childShell->GetDefaultLoadFlags(&defaultLoadFlags);
 
     // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that
     // the child inherits our state. Among other things, this means that the
-    // child inherits our mIsActive mPrivateBrowsingId, which is what we want.
+    // child inherits our mPrivateBrowsingId, which is what we want.
     AddChild(childItem);
 
     contexts.AppendElement(childShell->GetBrowsingContext());
 
     childShell->SetAllowPlugins(allowPlugins);
     childShell->SetAllowJavascript(allowJavascript);
     childShell->SetAllowMetaRedirects(allowRedirects);
     childShell->SetAllowSubframes(allowSubframes);
@@ -8435,41 +8436,39 @@ uint32_t nsDocShell::DetermineContentTyp
 
 nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState,
                                         nsIDocShell** aDocShell,
                                         nsIRequest** aRequest) {
   MOZ_ASSERT(aLoadState, "need a load state!");
   MOZ_ASSERT(!aLoadState->Target().IsEmpty(), "should have a target here!");
 
   nsresult rv = NS_OK;
-  nsCOMPtr<nsIDocShell> targetDocShell;
+  RefPtr<BrowsingContext> targetContext;
 
   // Only _self, _parent, and _top are supported in noopener case.  But we
   // have to be careful to not apply that to the noreferrer case.  See bug
   // 1358469.
   bool allowNamedTarget =
       !aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_NO_OPENER) ||
       aLoadState->HasLoadFlags(INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
   if (allowNamedTarget ||
       aLoadState->Target().LowerCaseEqualsLiteral("_self") ||
       aLoadState->Target().LowerCaseEqualsLiteral("_parent") ||
       aLoadState->Target().LowerCaseEqualsLiteral("_top")) {
-    if (BrowsingContext* context = mBrowsingContext->FindWithName(
-            aLoadState->Target(), /* aUseEntryGlobalForAccessCheck */ false)) {
-      targetDocShell = context->GetDocShell();
-    }
-  }
-
-  if (!targetDocShell) {
-    // If the targetDocShell doesn't exist, then this is a new docShell
-    // and we should consider this a TYPE_DOCUMENT load
+    targetContext = mBrowsingContext->FindWithName(
+        aLoadState->Target(), /* aUseEntryGlobalForAccessCheck */ false);
+  }
+
+  if (!targetContext) {
+    // If the targetContext doesn't exist, then this is a new docShell and we
+    // should consider this a TYPE_DOCUMENT load
     //
     // For example, when target="_blank"
 
-    // If there's no targetDocShell, that means we are about to create a new
+    // If there's no targetContext, that means we are about to create a new
     // window. Perform a content policy check before creating the window. Please
     // note for all other docshell loads content policy checks are performed
     // within the contentSecurityManager when the channel is about to be
     // openend.
     nsISupports* requestingContext = nullptr;
     if (XRE_IsContentProcess()) {
       // In e10s the child process doesn't have access to the element that
       // contains the browsing context (because that element is in the chrome
@@ -8504,20 +8503,20 @@ nsresult nsDocShell::PerformRetargeting(
       if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
         return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
       }
 
       return NS_ERROR_CONTENT_BLOCKED;
     }
   }
 
-  if ((!targetDocShell || targetDocShell == static_cast<nsIDocShell*>(this))) {
+  if (!targetContext || (targetContext == mBrowsingContext)) {
     bool handled;
     rv = MaybeHandleLoadDelegate(aLoadState,
-                                 targetDocShell
+                                 targetContext
                                      ? nsIBrowserDOMWindow::OPEN_CURRENTWINDOW
                                      : nsIBrowserDOMWindow::OPEN_NEWWINDOW,
                                  &handled);
     if (NS_FAILED(rv)) {
       return rv;
     }
     if (handled) {
       return NS_OK;
@@ -8530,17 +8529,17 @@ nsresult nsDocShell::PerformRetargeting(
   // load to it...
   //
 
   // We've already done our owner-inheriting.  Mask out that bit, so we
   // don't try inheriting an owner from the target window if we came up
   // with a null owner above.
   aLoadState->UnsetLoadFlag(INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
 
-  if (!targetDocShell) {
+  if (!targetContext) {
     // If the docshell's document is sandboxed, only open a new window
     // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
     // (i.e. if allow-popups is specified)
     NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
     Document* doc = mContentViewer->GetDocument();
 
     const bool isDocumentAuxSandboxed =
         doc && (doc->GetSandboxFlags() & SANDBOXED_AUXILIARY_NAVIGATION);
@@ -8630,49 +8629,32 @@ nsresult nsDocShell::PerformRetargeting(
     if (piNewWin) {
       RefPtr<Document> newDoc = piNewWin->GetExtantDoc();
       if (!newDoc || newDoc->IsInitialDocument()) {
         aLoadState->SetLoadFlag(INTERNAL_LOAD_FLAGS_FIRST_LOAD);
       }
     }
 
     if (newBC) {
-      targetDocShell = newBC->GetDocShell();
+      targetContext = newBC;
     }
   }
 
   NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(targetDocShell, rv);
+  NS_ENSURE_TRUE(targetContext, rv);
   //
-  // Transfer the load to the target DocShell... Pass empty string as the
+  // Transfer the load to the target BrowsingContext... Pass empty string as the
   // window target name from to prevent recursive retargeting!
   //
-  nsDocShell* docShell = nsDocShell::Cast(targetDocShell);
   // No window target
   aLoadState->SetTarget(EmptyString());
   // No forced download
   aLoadState->SetFileName(VoidString());
-  rv = docShell->InternalLoad(aLoadState, aDocShell, aRequest);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Switch to target tab if we're currently focused window.
-  // Take loadDivertedInBackground into account so the behavior would be
-  // the same as how the tab first opened.
-  bool isTargetActive = false;
-  targetDocShell->GetIsActive(&isTargetActive);
-  nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow();
-  if (mIsActive && !isTargetActive && domWin &&
-      !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false)) {
-    nsFocusManager::FocusWindow(domWin);
-  }
-
-  // Else we ran out of memory, or were a popup and got blocked,
-  // or something.
-
-  return rv;
+  return targetContext->InternalLoad(mBrowsingContext, aLoadState, aDocShell,
+                                     aRequest);
 }
 
 bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
                                           SameDocumentNavigationState& aState) {
   MOZ_ASSERT(aLoadState);
   if (!(aLoadState->LoadType() == LOAD_NORMAL ||
         aLoadState->LoadType() == LOAD_STOP_CONTENT ||
         LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
@@ -9288,17 +9270,17 @@ nsresult nsDocShell::InternalLoad(nsDocS
   // here because orientation is only set on top-level browsing contexts.
   if (OrientationLock() != hal::eScreenOrientation_None) {
 #ifdef DEBUG
     nsCOMPtr<nsIDocShellTreeItem> parent;
     GetInProcessSameTypeParent(getter_AddRefs(parent));
     MOZ_ASSERT(!parent);
 #endif
     SetOrientationLock(hal::eScreenOrientation_None);
-    if (mIsActive) {
+    if (mBrowsingContext->GetIsActive()) {
       ScreenOrientation::UpdateActiveOrientationLock(
           hal::eScreenOrientation_None);
     }
   }
 
   // Check for saving the presentation here, before calling Stop().
   // This is necessary so that we can catch any pending requests.
   // Since the new request has not been created yet, we pass null for the
@@ -9945,17 +9927,17 @@ nsresult nsDocShell::DoURILoad(nsDocShel
         // Let's consider external protocols as popups and let's check if the
         // page is allowed to open them without abuse regardless of allowed
         // events
         if (PopupBlocker::GetPopupControlState() <= PopupBlocker::openBlocked) {
           nsCOMPtr<nsINode> loadingNode =
               mScriptGlobal->GetFrameElementInternal();
           popupBlocked = !PopupBlocker::TryUsePopupOpeningToken(
               loadingNode ? loadingNode->NodePrincipal() : nullptr);
-        } else if (mIsActive &&
+        } else if (mBrowsingContext->GetIsActive() &&
                    PopupBlocker::ConsumeTimerTokenForExternalProtocolIframe()) {
           popupBlocked = false;
         } else {
           nsCOMPtr<nsINode> loadingNode =
               mScriptGlobal->GetFrameElementInternal();
           if (loadingNode) {
             popupBlocked = !PopupBlocker::CanShowPopupByPermission(
                 loadingNode->NodePrincipal());
@@ -10199,18 +10181,18 @@ nsresult nsDocShell::DoURILoad(nsDocShel
   nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
   if (IsFrame() && win) {
     nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
     if (frameElement) {
       initiatorType = &frameElement->LocalName();
     }
   }
 
-  bool isActive =
-      mIsActive || (mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY));
+  bool isActive = mBrowsingContext->GetIsActive() ||
+                  (mLoadType & (LOAD_CMD_NORMAL | LOAD_CMD_HISTORY));
   if (!CreateChannelForLoadState(
           aLoadState, loadInfo, this, this, initiatorType, loadFlags, mLoadType,
           cacheKey, isActive, isTopLevelDoc,
           mBrowsingContext->GetSandboxFlags(), rv, getter_AddRefs(channel))) {
     return rv;
   }
 
   // Make sure to give the caller a channel if we managed to create one
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -1271,17 +1271,16 @@ class nsDocShell final : public nsDocLoa
   bool mAllowContentRetargetingOnChildren : 1;
   bool mUseErrorPages : 1;
   bool mUseStrictSecurityChecks : 1;
   bool mObserveErrorPages : 1;
   bool mCSSErrorReportingEnabled : 1;
   bool mAllowAuth : 1;
   bool mAllowKeywordFixup : 1;
   bool mIsOffScreenBrowser : 1;
-  bool mIsActive : 1;
   bool mDisableMetaRefreshWhenInactive : 1;
   bool mIsAppTab : 1;
   bool mUseGlobalHistory : 1;
   bool mUseRemoteTabs : 1;
   bool mUseRemoteSubframes : 1;
   bool mUseTrackingProtection : 1;
   bool mDeviceSizeIsPageSize : 1;
   bool mWindowDraggingAllowed : 1;
--- a/docshell/test/navigation/mochitest.ini
+++ b/docshell/test/navigation/mochitest.ini
@@ -55,50 +55,44 @@ support-files =
   file_bug1364364-2.html
   file_bug1375833.html
   file_bug1375833-frame1.html
   file_bug1375833-frame2.html
   test_bug145971.html
 
 [test_bug13871.html]
 [test_bug270414.html]
-skip-if = fission # Times out.
 [test_bug278916.html]
 [test_bug279495.html]
 [test_bug344861.html]
 skip-if = toolkit == "android" || toolkit == "windows" # disabled on Windows because of bug 1234520
 [test_bug386782.html]
 [test_bug430624.html]
 [test_bug430723.html]
 skip-if = (!debug && (os == 'mac' || os == 'win')) # Bug 874423
 [test_bug1364364.html]
 skip-if = (os == "android") # Bug 1560378
 [test_bug1375833.html]
 [test_bug1536471.html]
 support-files = file_bug1536471.html
 [test_child.html]
-skip-if = fission # Times out.
 [test_grandchild.html]
-fail-if = fission
 [test_load_history_entry.html]
 [test_not-opener.html]
 skip-if = fission # Times out.
 [test_opener.html]
-skip-if = fission # Times out.
 [test_popup-navigates-children.html]
-skip-if = fission # Times out.
 [test_reserved.html]
 skip-if =
   (debug && e10s) || (os == 'mac' && os_version == '10.14') || # bug 1263213 for debug e10s, macosx1014 due to 1548821
   fission # Times out.
 [test_performance_navigation.html]
 [test_sessionhistory.html]
 skip-if = toolkit == 'android' # RANDOM on android
 support-files = file_bug1379762-1.html
 [test_sibling-matching-parent.html]
-skip-if = fission # Times out.
 [test_sibling-off-domain.html]
 [test_triggeringprincipal_frame_nav.html]
 [test_triggeringprincipal_window_open.html]
 [test_triggeringprincipal_parent_iframe_window_open.html]
 [test_triggeringprincipal_iframe_iframe_window_open.html]
 skip-if = fission && os == 'linux' && debug && webrender #Bug 1586686
 [test_contentpolicy_block_window.html]
--- a/dom/ipc/PWindowGlobal.ipdl
+++ b/dom/ipc/PWindowGlobal.ipdl
@@ -58,27 +58,31 @@ child:
 
   /**
    * Returns the serialized security info associated with this window.
    */
   async GetSecurityInfo() returns(nsCString? serializedSecInfo);
 
   async LoadURIInChild(nsDocShellLoadState aLoadState, bool aSetNavigating);
 
+  async InternalLoadInChild(nsDocShellLoadState aLoadState, bool aTakeFocus);
+
   async DisplayLoadError(nsString aURI);
 
 both:
   async RawMessage(JSWindowActorMessageMeta aMetadata, ClonedMessageData aData);
 
 parent:
   // Load the given URI load state into the current owner process of the given
   // BrowsingContext. aTargetBC must be in the same BrowsingContextGroup as this
   // window global.
   async LoadURI(BrowsingContext aTargetBC, nsDocShellLoadState aLoadState, bool aSetNavigating);
 
+  async InternalLoad(BrowsingContext aTargetBC, nsDocShellLoadState aLoadState);
+
   /// Update the URI of the document in this WindowGlobal.
   async UpdateDocumentURI(nsIURI aUri);
 
   /// Send down initial document bit to the parent.
   async SetIsInitialDocument(bool aIsInitialDocument);
 
   /// Tell the parent if this WindowGlobal has any "beforeunload" event
   /// listeners.
--- a/dom/ipc/WindowGlobalChild.cpp
+++ b/dom/ipc/WindowGlobalChild.cpp
@@ -15,16 +15,17 @@
 #include "mozilla/dom/BrowserBridgeChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/WindowGlobalActorsBinding.h"
 #include "mozilla/dom/WindowGlobalParent.h"
 #include "mozilla/ipc/InProcessChild.h"
 #include "mozilla/ipc/InProcessParent.h"
 #include "nsContentUtils.h"
 #include "nsDocShell.h"
+#include "nsFocusManager.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsGlobalWindowInner.h"
 #include "nsFrameLoaderOwner.h"
 #include "nsQueryObject.h"
 #include "nsSerializationHelper.h"
 #include "nsFrameLoader.h"
 
 #include "mozilla/dom/JSWindowActorBinding.h"
@@ -257,16 +258,49 @@ mozilla::ipc::IPCResult WindowGlobalChil
     CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL,
                                        annotationURI->GetSpecOrDefault());
   }
 #endif
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult WindowGlobalChild::RecvInternalLoadInChild(
+    nsDocShellLoadState* aLoadState, bool aTakeFocus) {
+  nsDocShell::Cast(mWindowGlobal->GetDocShell())
+      ->InternalLoad(aLoadState, nullptr, nullptr);
+
+  if (aTakeFocus) {
+    if (nsCOMPtr<nsPIDOMWindowOuter> domWin =
+            mBrowsingContext->GetDOMWindow()) {
+      nsFocusManager::FocusWindow(domWin);
+    }
+  }
+
+#ifdef MOZ_CRASHREPORTER
+  if (CrashReporter::GetEnabled()) {
+    nsCOMPtr<nsIURI> annotationURI;
+
+    nsresult rv = NS_MutateURI(aLoadState->URI())
+                      .SetUserPass(EmptyCString())
+                      .Finalize(annotationURI);
+
+    if (NS_FAILED(rv)) {
+      // Ignore failures on about: URIs.
+      annotationURI = aLoadState->URI();
+    }
+
+    CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL,
+                                       annotationURI->GetSpecOrDefault());
+  }
+#endif
+
+  return IPC_OK();
+}
+
 mozilla::ipc::IPCResult WindowGlobalChild::RecvDisplayLoadError(
     const nsAString& aURI) {
   bool didDisplayLoadError = false;
   mWindowGlobal->GetDocShell()->DisplayLoadError(
       NS_ERROR_MALFORMED_URI, nullptr, PromiseFlatString(aURI).get(), nullptr,
       &didDisplayLoadError);
   mWindowGlobal->GetBrowserChild()->NotifyNavigationFinished();
   return IPC_OK();
--- a/dom/ipc/WindowGlobalChild.h
+++ b/dom/ipc/WindowGlobalChild.h
@@ -112,16 +112,19 @@ class WindowGlobalChild final : public W
 
   // IPC messages
   mozilla::ipc::IPCResult RecvRawMessage(const JSWindowActorMessageMeta& aMeta,
                                          const ClonedMessageData& aData);
 
   mozilla::ipc::IPCResult RecvLoadURIInChild(nsDocShellLoadState* aLoadState,
                                              bool aSetNavigating);
 
+  mozilla::ipc::IPCResult RecvInternalLoadInChild(
+      nsDocShellLoadState* aLoadState, bool aTakeFocus);
+
   mozilla::ipc::IPCResult RecvDisplayLoadError(const nsAString& aURI);
 
   mozilla::ipc::IPCResult RecvMakeFrameLocal(
       dom::BrowsingContext* aFrameContext, uint64_t aPendingSwitchId);
 
   mozilla::ipc::IPCResult RecvMakeFrameRemote(
       dom::BrowsingContext* aFrameContext,
       ManagedEndpoint<PBrowserBridgeChild>&& aEndpoint, const TabId& aTabId,
--- a/dom/ipc/WindowGlobalParent.cpp
+++ b/dom/ipc/WindowGlobalParent.cpp
@@ -204,16 +204,49 @@ mozilla::ipc::IPCResult WindowGlobalPare
             ("ParentIPC: Target BrowsingContext has no WindowGlobalParent"));
     return IPC_OK();
   }
 
   Unused << wgp->SendLoadURIInChild(aLoadState, aSetNavigating);
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult WindowGlobalParent::RecvInternalLoad(
+    dom::BrowsingContext* aTargetBC, nsDocShellLoadState* aLoadState) {
+  if (!aTargetBC || aTargetBC->IsDiscarded()) {
+    MOZ_LOG(
+        BrowsingContext::GetLog(), LogLevel::Debug,
+        ("ParentIPC: Trying to send a message with dead or detached context"));
+    return IPC_OK();
+  }
+
+  // FIXME: For cross-process loads, we should double check CanAccess() for the
+  // source browsing context in the parent process.
+
+  if (aTargetBC->Group() != BrowsingContext()->Group()) {
+    return IPC_FAIL(this, "Illegal cross-group BrowsingContext load");
+  }
+
+  // FIXME: We should really initiate the load in the parent before bouncing
+  // back down to the child.
+
+  WindowGlobalParent* wgp = aTargetBC->Canonical()->GetCurrentWindowGlobal();
+  if (!wgp) {
+    MOZ_LOG(BrowsingContext::GetLog(), LogLevel::Debug,
+            ("ParentIPC: Target BrowsingContext has no WindowGlobalParent"));
+    return IPC_OK();
+  }
+
+  bool takeFocus =
+      mBrowsingContext->GetIsActive() && !aTargetBC->GetIsActive() &&
+      !Preferences::GetBool("browser.tabs.loadDivertedInBackground", false);
+  Unused << wgp->SendInternalLoadInChild(aLoadState, takeFocus);
+  return IPC_OK();
+}
+
 IPCResult WindowGlobalParent::RecvUpdateDocumentURI(nsIURI* aURI) {
   // XXX(nika): Assert that the URI change was one which makes sense (either
   // about:blank -> a real URI, or a legal push/popstate URI change?)
   mDocumentURI = aURI;
   return IPC_OK();
 }
 
 IPCResult WindowGlobalParent::RecvSetHasBeforeUnload(bool aHasBeforeUnload) {
--- a/dom/ipc/WindowGlobalParent.h
+++ b/dom/ipc/WindowGlobalParent.h
@@ -132,16 +132,18 @@ class WindowGlobalParent final : public 
  protected:
   const nsAString& GetRemoteType() override;
   JSWindowActor::Type GetSide() override { return JSWindowActor::Type::Parent; }
 
   // IPC messages
   mozilla::ipc::IPCResult RecvLoadURI(dom::BrowsingContext* aTargetBC,
                                       nsDocShellLoadState* aLoadState,
                                       bool aSetNavigating);
+  mozilla::ipc::IPCResult RecvInternalLoad(dom::BrowsingContext* aTargetBC,
+                                           nsDocShellLoadState* aLoadState);
   mozilla::ipc::IPCResult RecvUpdateDocumentURI(nsIURI* aURI);
   mozilla::ipc::IPCResult RecvSetIsInitialDocument(bool aIsInitialDocument) {
     mIsInitialDocument = aIsInitialDocument;
     return IPC_OK();
   }
   mozilla::ipc::IPCResult RecvSetHasBeforeUnload(bool aHasBeforeUnload);
   mozilla::ipc::IPCResult RecvBecomeCurrentWindowGlobal();
   mozilla::ipc::IPCResult RecvDestroy();