Bug 1318472 - Remove inactive hidden tabs when removing the primary tab, r=ehsan
☠☠ backed out by b2e450275dee ☠ ☠
authorMichael Layzell <michael@thelayzells.com>
Thu, 17 Nov 2016 15:10:52 -0500
changeset 324265 c4669804cc496d815bc7438a19d3ef23459abc2f
parent 324264 2e372790cc3595e78a624224ee05959e2c0817fe
child 324266 9ff1755fa83c99676b53f3858c1ab9375837396b
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersehsan
bugs1318472
milestone53.0a1
Bug 1318472 - Remove inactive hidden tabs when removing the primary tab, r=ehsan MozReview-Commit-ID: KiMsKOljNpE
browser/base/content/tabbrowser.xml
browser/base/content/test/general/browser.ini
browser/base/content/test/general/browser_close_dependent_tabs.js
docshell/shistory/nsIGroupedSHistory.idl
dom/base/GroupedSHistory.cpp
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -2578,16 +2578,23 @@
 
               newTab = true;
             }
 
             aTab.closing = true;
             this._removingTabs.push(aTab);
             this._visibleTabs = null; // invalidate cache
 
+            // Start closing the FrameLoaderOwners which are inactive, so that
+            // they are cleaned up as well.
+            let frameLoader = browser.frameLoader;
+            if (frameLoader && frameLoader.groupedSessionHistory) {
+              frameLoader.groupedSessionHistory.closeInactiveFrameLoaderOwners();
+            }
+
             // Invalidate hovered tab state tracking for this closing tab.
             if (this.tabContainer._hoveredTab == aTab)
               aTab._mouseleave();
 
             if (newTab)
               this.addTab(BROWSER_NEW_TAB_URL, {skipAnimation: true});
             else
               this.tabContainer.updateVisibility();
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -486,8 +486,10 @@ tags = fullscreen
 [browser_menuButtonBadgeManager.js]
 [browser_newTabDrop.js]
 [browser_newWindowDrop.js]
 [browser_csp_block_all_mixedcontent.js]
 tags = mcb
 [browser_newwindow_focus.js]
 skip-if = (os == "linux" && !e10s) # Bug 1263254 - Perma fails on Linux without e10s for some reason.
 [browser_bug1299667.js]
+[browser_close_dependent_tabs.js]
+skip-if = !e10s # GroupedSHistory is e10s-only
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/browser_close_dependent_tabs.js
@@ -0,0 +1,51 @@
+add_task(function* () {
+  yield SpecialPowers.pushPrefEnv({
+    set: [["browser.groupedhistory.enabled", true]]
+  });
+
+  // Wait for a process change and then fulfil the promise.
+  function awaitProcessChange(browser) {
+    return new Promise(resolve => {
+      browser.addEventListener("BrowserChangedProcess", function bcp(e) {
+        browser.removeEventListener("BrowserChangedProcess", bcp);
+        ok(true, "The browser changed process!");
+        resolve();
+      });
+    });
+  }
+
+  let tab2;
+
+  // Test 1: Create prerendered browser, and don't switch to it, then close the tab
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) {
+    // Set up the grouped SHEntry setup
+    tab2 = gBrowser.loadOneTab("data:text/html,b", {
+      referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
+      allowThirdPartyFixup: true,
+      relatedToCurrent: true,
+      isPrerendered: true,
+    });
+  });
+
+  // At this point tab2 should be closed
+  todo(!tab2.linkedBrowser, "The new tab should be closed");
+  yield BrowserTestUtils.removeTab(tab2); // XXX: Shouldn't be needed once the todo is fixed
+
+  // Test 2: Create prerendered browser, switch to it, then close the tab
+  yield BrowserTestUtils.withNewTab({ gBrowser, url: "data:text/html,a" }, function* (browser1) {
+    // Set up the grouped SHEntry setup
+    tab2 = gBrowser.loadOneTab("data:text/html,b", {
+      referrerPolicy: Ci.nsIHttpChannel.REFERRER_POLICY_DEFAULT,
+      allowThirdPartyFixup: true,
+      relatedToCurrent: true,
+      isPrerendered: true,
+    });
+    yield BrowserTestUtils.browserLoaded(tab2.linkedBrowser);
+    browser1.frameLoader.appendPartialSessionHistoryAndSwap(
+      tab2.linkedBrowser.frameLoader);
+    yield awaitProcessChange(browser1);
+  });
+
+  // At this point tab2 should be closed
+  ok(!tab2.linkedBrowser, "The new tab should be closed");
+});
--- a/docshell/shistory/nsIGroupedSHistory.idl
+++ b/docshell/shistory/nsIGroupedSHistory.idl
@@ -39,9 +39,15 @@ interface nsIGroupedSHistory : nsISuppor
    * corresponding to the given global index. Note it doesn't swap frameloaders,
    * but rather return the target loader for the caller to swap.
    *
    * @param aGlobalIndex        The global index to navigate to.
    * @param aTargetLoaderToSwap The owner frameloader of the to-be-navigate
    *                            partial session history.
    */
   void gotoIndex(in unsigned long aGlobalIndex, out nsIFrameLoader aTargetLoaderToSwap);
+
+  /**
+   * Close the FrameLoaderOwners of the inactive PartialSHistories in this GlobalSHistory.
+   * This does not remove the PartialSHistories from the GroupedSHistory.
+   */
+  void closeInactiveFrameLoaderOwners();
 };
--- a/dom/base/GroupedSHistory.cpp
+++ b/dom/base/GroupedSHistory.cpp
@@ -163,10 +163,24 @@ GroupedSHistory::PurgePartialHistories(u
                                      lastIndex - aLastPartialIndexToKeep);
 }
 
 /* static */ bool
 GroupedSHistory::GroupedHistoryEnabled() {
   return Preferences::GetBool("browser.groupedhistory.enabled", false);
 }
 
+NS_IMETHODIMP
+GroupedSHistory::CloseInactiveFrameLoaderOwners()
+{
+  MOZ_ASSERT(mIndexOfActivePartialHistory >= 0);
+  for (uint32_t i = 0; i < mPartialHistories.Length(); ++i) {
+    if (i != static_cast<uint32_t>(mIndexOfActivePartialHistory)) {
+      nsCOMPtr<nsIFrameLoader> loader;
+      mPartialHistories[i]->GetOwnerFrameLoader(getter_AddRefs(loader));
+      loader->RequestFrameLoaderClose();
+    }
+  }
+  return NS_OK;
+}
+
 } // namespace dom
 } // namespace mozilla