Bug 636279 - _tabsRestoringCount goes negative if setBrowserState called at browser startup and last session had pinned tab(s); r=zpao
authorTim Taubert <tim.taubert@gmx.de>
Thu, 19 May 2011 23:53:59 +0200
changeset 69758 55062716b8c5b55f9b2214286e6b47ffa030ccf1
parent 69757 24438e77a538253b2a69d274c987a13e2d86020b
child 69759 feee7414083834b46ffb76f944f8c1b7dd5c85a4
push id20097
push usermlamouri@mozilla.com
push dateFri, 20 May 2011 13:58:00 +0000
treeherdermozilla-central@7a74ad0b746e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerszpao
bugs636279
milestone6.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 636279 - _tabsRestoringCount goes negative if setBrowserState called at browser startup and last session had pinned tab(s); r=zpao
browser/components/sessionstore/src/nsSessionStore.js
browser/components/sessionstore/test/browser/Makefile.in
browser/components/sessionstore/test/browser/browser_636279.js
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -3969,17 +3969,18 @@ SessionStoreService.prototype = {
     // We want to decrement window.__SS_tabsToRestore here so that we always
     // decrement it AFTER a tab is done restoring or when a tab gets "reset".
     window.__SS_tabsToRestore--;
 
     // Remove the progress listener if we should.
     this._removeTabsProgressListener(window);
 
     if (previousState == TAB_STATE_RESTORING) {
-      this._tabsRestoringCount--;
+      if (this._tabsRestoringCount)
+        this._tabsRestoringCount--;
     }
     else if (previousState == TAB_STATE_NEEDS_RESTORE) {
       // Make sure the session history listener is removed. This is normally
       // done in restoreTab, but this tab is being removed before that gets called.
       this._removeSHistoryListener(aTab);
 
       // Make sure that the tab is removed from the list of tabs to restore.
       // Again, this is normally done in restoreTab, but that isn't being called
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -140,16 +140,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_607016.js \
 	browser_615394-SSWindowState_events.js \
 	browser_618151.js \
 	browser_623779.js \
 	browser_624727.js \
 	browser_625257.js \
 	browser_628270.js \
 	browser_635418.js \
+	browser_636279.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	$(NULL)
 endif
 
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_636279.js
@@ -0,0 +1,106 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+         getService(Ci.nsISessionStore);
+
+const TAB_STATE_NEEDS_RESTORE = 1;
+const TAB_STATE_RESTORING = 2;
+
+let stateBackup = ss.getBrowserState();
+
+let statePinned = {windows:[{tabs:[
+  {entries:[{url:"http://example.com#1"}], pinned: true}
+]}]};
+
+let state = {windows:[{tabs:[
+  {entries:[{url:"http://example.com#1"}]},
+  {entries:[{url:"http://example.com#2"}]},
+  {entries:[{url:"http://example.com#3"}]}
+]}]};
+
+function test() {
+  waitForExplicitFinish();
+
+  registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.sessionstore.max_concurrent_tabs");
+    TabsProgressListener.uninit();
+    ss.setBrowserState(stateBackup);
+  });
+
+  Services.prefs.setIntPref("browser.sessionstore.max_concurrent_tabs", 2);
+
+  TabsProgressListener.init();
+
+  window.addEventListener("SSWindowStateReady", function onReady() {
+    window.removeEventListener("SSWindowStateReady", onReady, false);
+
+    let firstProgress = true;
+
+    TabsProgressListener.setCallback(function (needsRestore, isRestoring) {
+      if (firstProgress) {
+        firstProgress = false;
+        is(isRestoring, 2, "restoring 2 tabs concurrently");
+      } else {
+        ok(isRestoring < 3, "restoring max. 2 tabs concurrently");
+      }
+
+      if (0 == needsRestore) {
+        TabsProgressListener.unsetCallback();
+        waitForFocus(finish);
+      }
+    });
+
+    ss.setBrowserState(JSON.stringify(state));
+  }, false);
+
+  ss.setBrowserState(JSON.stringify(statePinned));
+}
+
+function countTabs() {
+  let needsRestore = 0, isRestoring = 0;
+  let windowsEnum = Services.wm.getEnumerator("navigator:browser");
+
+  while (windowsEnum.hasMoreElements()) {
+    let window = windowsEnum.getNext();
+    if (window.closed)
+      continue;
+
+    for (let i = 0; i < window.gBrowser.tabs.length; i++) {
+      let browser = window.gBrowser.tabs[i].linkedBrowser;
+      if (browser.__SS_restoreState == TAB_STATE_RESTORING)
+        isRestoring++;
+      else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
+        needsRestore++;
+    }
+  }
+
+  return [needsRestore, isRestoring];
+}
+
+let TabsProgressListener = {
+  init: function () {
+    gBrowser.addTabsProgressListener(this);
+  },
+
+  uninit: function () {
+    this.unsetCallback();
+    gBrowser.removeTabsProgressListener(this);
+ },
+
+  setCallback: function (callback) {
+    this.callback = callback;
+  },
+
+  unsetCallback: function () {
+    delete this.callback;
+  },
+
+  onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
+    if (this.callback && aBrowser.__SS_restoreState == TAB_STATE_RESTORING &&
+        aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
+        aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
+        aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW)
+      this.callback.apply(null, countTabs());
+  }
+}