author | Dão Gottwald <dao@mozilla.com> |
Fri, 19 Aug 2011 11:07:08 +0200 | |
changeset 76791 | 6181ba4693f9face8f50d367f3de5593b500742d |
parent 76790 | 2578bdcf32ee0727411fd5547600e0686e1d76f6 |
child 76839 | 1881f9b5f8b50fa29a6b4f9885948e9ce632d22b |
push id | 78 |
push user | clegnitto@mozilla.com |
push date | Fri, 16 Dec 2011 17:32:24 +0000 |
treeherder | mozilla-release@79d24e644fdd [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 9.0a1 |
backs out | e68b6ce72fc32ead1ff716e8c21cd46a86627ac2 |
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
|
--- a/browser/base/content/tabview/storage.js +++ b/browser/base/content/tabview/storage.js @@ -180,33 +180,16 @@ let Storage = { } catch (e) { // getWindowValue will fail if the property doesn't exist Utils.log("Error in readGroupItemData: "+e, data); } return existingData; }, // ---------- - // Function: readWindowBusyState - // Returns the current busyState for the given window. - readWindowBusyState: function Storage_readWindowBusyState(win) { - let state; - - try { - let data = this._sessionStore.getWindowState(win); - if (data) - state = JSON.parse(data); - } catch (e) { - Utils.log("Error while parsing window state"); - } - - return (state && state.windows[0].busy); - }, - - // ---------- // Function: saveGroupItemsData // Saves the global data for the <GroupItems> singleton for the given window. saveGroupItemsData: function Storage_saveGroupItemsData(win, data) { this.saveData(win, this.GROUPS_DATA_IDENTIFIER, data); }, // ---------- // Function: readGroupItemsData
--- a/browser/base/content/tabview/ui.js +++ b/browser/base/content/tabview/ui.js @@ -118,19 +118,19 @@ let UI = { // Keeps track of info related to private browsing, including: // transitionMode - whether we're entering or exiting PB // wasInTabView - whether TabView was visible before we went into PB _privateBrowsing: { transitionMode: "", wasInTabView: false }, - // Variable: _storageBusy - // Tells whether the storage is currently busy or not. - _storageBusy: false, + // Variable: _storageBusyCount + // Used to keep track of how many calls to storageBusy vs storageReady. + _storageBusyCount: 0, // Variable: isDOMWindowClosing // Tells wether the parent window is about to close isDOMWindowClosing: false, // Variable: _browserKeys // Used to keep track of allowed browser keys. _browserKeys: null, @@ -164,20 +164,16 @@ let UI = { // initialize the direction of the page this._initPageDirection(); // ___ thumbnail storage ThumbnailStorage.init(); // ___ storage Storage.init(); - - if (Storage.readWindowBusyState(gWindow)) - this.storageBusy(); - let data = Storage.readUIData(gWindow); this._storageSanity(data); this._pageBounds = data.pageBounds; // ___ currentTab this._currentTab = gBrowser.selectedTab; // ___ exit button @@ -611,42 +607,39 @@ let UI = { }, #endif // ---------- // Function: storageBusy // Pauses the storage activity that conflicts with sessionstore updates and // private browsing mode switches. Calls can be nested. storageBusy: function UI_storageBusy() { - if (this._storageBusy) - return; - - this._storageBusy = true; - - TabItems.pauseReconnecting(); - GroupItems.pauseAutoclose(); + if (!this._storageBusyCount) { + TabItems.pauseReconnecting(); + GroupItems.pauseAutoclose(); + } + + this._storageBusyCount++; }, // ---------- // Function: storageReady // Resumes the activity paused by storageBusy, and updates for any new group // information in sessionstore. Calls can be nested. storageReady: function UI_storageReady() { - if (!this._storageBusy) - return; - - this._storageBusy = false; - - let hasGroupItemsData = GroupItems.load(); - if (!hasGroupItemsData) - this.reset(); - - TabItems.resumeReconnecting(); - GroupItems._updateTabBar(); - GroupItems.resumeAutoclose(); + this._storageBusyCount--; + if (!this._storageBusyCount) { + let hasGroupItemsData = GroupItems.load(); + if (!hasGroupItemsData) + this.reset(); + + TabItems.resumeReconnecting(); + GroupItems._updateTabBar(); + GroupItems.resumeAutoclose(); + } }, // ---------- // Function: _addTabActionHandlers // Adds handlers to handle tab actions. _addTabActionHandlers: function UI__addTabActionHandlers() { var self = this; @@ -732,17 +725,17 @@ let UI = { if (self.isTabViewVisible()) { // just closed the selected tab in the TabView interface. if (self._currentTab == tab) self._closedSelectedTabInTabView = true; } else { // If we're currently in the process of entering private browsing, // we don't want to go to the Tab View UI. - if (self._storageBusy) + if (self._storageBusyCount) return; // if not closing the last tab if (gBrowser.tabs.length > 1) { // Don't return to TabView if there are any app tabs for (let a = 0; a < gBrowser._numPinnedTabs; a++) { if (!gBrowser.tabs[a].closing) return;
--- a/browser/base/content/test/tabview/browser_tabview_bug597248.js +++ b/browser/base/content/test/tabview/browser_tabview_bug597248.js @@ -32,30 +32,36 @@ function setupTwo(win) { let numTabsToSave = tabItems.length; // force all canvases to update, and hook in imageData save detection tabItems.forEach(function(tabItem) { contentWindow.TabItems.update(tabItem.tab); tabItem.addSubscriber("savedCachedImageData", function onSaved(item) { item.removeSubscriber("savedCachedImageData", onSaved); - - if (!--numTabsToSave) - restoreWindow(); + --numTabsToSave; }); }); // after the window is closed, restore it. - let restoreWindow = function() { + let xulWindowDestory = function() { + Services.obs.removeObserver( + xulWindowDestory, "xul-window-destroyed", false); + + // "xul-window-destroyed" is just fired just before a XUL window is + // destroyed so restore window and test it after a delay executeSoon(function() { restoredWin = undoCloseWindow(); restoredWin.addEventListener("load", function onLoad(event) { restoredWin.removeEventListener("load", onLoad, false); registerCleanupFunction(function() restoredWin.close()); + + // ensure that closed tabs have been saved + is(numTabsToSave, 0, "All tabs were saved when window was closed."); is(restoredWin.gBrowser.tabs.length, 3, "The total number of tabs is 3"); // setup tab variables and listen to the tabs load progress newTabOne = restoredWin.gBrowser.tabs[0]; newTabTwo = restoredWin.gBrowser.tabs[1]; newTabThree = restoredWin.gBrowser.tabs[2]; restoredWin.gBrowser.addTabsProgressListener(gTabsProgressListener); @@ -92,16 +98,17 @@ function setupTwo(win) { }); } restoredWin.addEventListener( "tabviewframeinitialized", onTabViewFrameInitialized, false); }, false); }); }; + Services.obs.addObserver(xulWindowDestory, "xul-window-destroyed", false); win.close(); } let gTabsProgressListener = { onStateChange: function(browser, webProgress, request, stateFlags, status) { // ensure about:blank doesn't trigger the code if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
--- a/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js +++ b/browser/base/content/test/tabview/browser_tabview_privatebrowsing.js @@ -44,25 +44,21 @@ function onTabViewLoadedAndShown() { // collect the group titles let count = contentWindow.GroupItems.groupItems.length; for (let a = 0; a < count; a++) { let gi = contentWindow.GroupItems.groupItems[a]; groupTitles[a] = gi.getTitle(); } - contentWindow.gPrefBranch.setBoolPref("animate_zoom", false); - // Create a second tab gBrowser.addTab("about:robots"); is(gBrowser.tabs.length, 2, "we now have 2 tabs"); - registerCleanupFunction(function() { gBrowser.removeTab(gBrowser.tabs[1]); - contentWindow.gPrefBranch.clearUserPref("animate_zoom"); }); afterAllTabsLoaded(function() { // Get normal tab urls for (let a = 0; a < gBrowser.tabs.length; a++) normalURLs.push(gBrowser.tabs[a].linkedBrowser.currentURI.spec); // verify that we're all set up for our test
--- a/browser/base/content/test/tabview/head.js +++ b/browser/base/content/test/tabview/head.js @@ -356,19 +356,16 @@ function restoreTab(callback, index, win } // ---------- function togglePrivateBrowsing(callback) { let topic = "private-browsing-transition-complete"; Services.obs.addObserver(function observe() { Services.obs.removeObserver(observe, topic); - - // use executeSoon() to let Panorama load its group data from the session - // before we call afterAllTabsLoaded() - executeSoon(function () afterAllTabsLoaded(callback)); + afterAllTabsLoaded(callback); }, topic, false); let pb = Cc["@mozilla.org/privatebrowsing;1"]. getService(Ci.nsIPrivateBrowsingService); pb.privateBrowsingEnabled = !pb.privateBrowsingEnabled; }
--- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -780,17 +780,17 @@ SessionStoreService.prototype = { if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" || this._loadState == STATE_QUITTING) return; // assign it a unique identifier (timestamp) aWindow.__SSi = "window" + Date.now(); // and create its data object - this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false }; + this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [] }; if (!this._isWindowLoaded(aWindow)) this._windows[aWindow.__SSi]._restoring = true; if (!aWindow.toolbar.visible) this._windows[aWindow.__SSi].isPopup = true; // perform additional initialization when the first window is loading if (this._loadState == STATE_STOPPED) { this._loadState = STATE_RUNNING; @@ -964,19 +964,16 @@ SessionStoreService.prototype = { // Until we decide otherwise elsewhere, this window is part of a series // of closing windows to quit. winData._shouldRestore = true; #endif // save the window if it has multiple tabs or a single saveable tab if (winData.tabs.length > 1 || (winData.tabs.length == 1 && this._shouldSaveTabState(winData.tabs[0]))) { - // we don't want to save the busy state - delete winData.busy; - this._closedWindows.unshift(winData); this._capClosedWindows(); } // clear this window from the list delete this._windows[aWindow.__SSi]; // save the state without this window to disk @@ -1263,33 +1260,33 @@ SessionStoreService.prototype = { }, setTabState: function sss_setTabState(aTab, aState) { var tabState = JSON.parse(aState); if (!tabState.entries || !aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); var window = aTab.ownerDocument.defaultView; - this._setWindowStateBusy(window); + this._sendWindowStateEvent(window, "Busy"); this.restoreHistoryPrecursor(window, [aTab], [tabState], 0, 0, 0); }, duplicateTab: function sss_duplicateTab(aWindow, aTab, aDelta) { if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi || !aWindow.getBrowser) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); var tabState = this._collectTabData(aTab, true); var sourceWindow = aTab.ownerDocument.defaultView; this._updateTextAndScrollDataForTab(sourceWindow, aTab.linkedBrowser, tabState, true); tabState.index += aDelta; tabState.index = Math.max(1, Math.min(tabState.index, tabState.entries.length)); tabState.pinned = false; - this._setWindowStateBusy(aWindow); + this._sendWindowStateEvent(aWindow, "Busy"); let newTab = aTab == aWindow.gBrowser.selectedTab ? aWindow.gBrowser.addTab(null, {relatedToCurrent: true, ownerTab: aTab}) : aWindow.gBrowser.addTab(); this.restoreHistoryPrecursor(aWindow, [newTab], [tabState], 0, 0, 0); return newTab; }, @@ -1322,17 +1319,17 @@ SessionStoreService.prototype = { aIndex = aIndex || 0; if (!(aIndex in closedTabs)) throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); // fetch the data of closed tab, while removing it from the array let closedTab = closedTabs.splice(aIndex, 1).shift(); let closedTabState = closedTab.state; - this._setWindowStateBusy(aWindow); + this._sendWindowStateEvent(aWindow, "Busy"); // create a new tab let browser = aWindow.gBrowser; let tab = browser.addTab(); // restore tab content this.restoreHistoryPrecursor(aWindow, [tab], [closedTabState], 1, 0, 0); // restore the tab's position @@ -2532,17 +2529,17 @@ SessionStoreService.prototype = { catch (ex) { // invalid state object - don't restore anything debug(ex); this._sendRestoreCompletedNotifications(); return; } // We're not returning from this before we end up calling restoreHistoryPrecursor // for this window, so make sure we send the SSWindowStateBusy event. - this._setWindowStateBusy(aWindow); + this._sendWindowStateEvent(aWindow, "Busy"); if (root._closedWindows) this._closedWindows = root._closedWindows; var winData; if (!aState.selectedWindow) { aState.selectedWindow = 0; } @@ -2719,17 +2716,17 @@ SessionStoreService.prototype = { delete this._statesToRestore[aWindow.__SS_restoreID]; delete aWindow.__SS_restoreID; delete this._windows[aWindow.__SSi]._restoring; } if (aTabs.length == 0) { // this is normally done in restoreHistory() but as we're returning early // here we need to take care of it. - this._setWindowStateReady(aWindow); + this._sendWindowStateEvent(aWindow, "Ready"); return; } let unhiddenTabs = aTabData.filter(function (aData) !aData.hidden).length; // if all tabs to be restored are hidden, make the first one visible if (unhiddenTabs == 0) { aTabData[0].hidden = false; @@ -2864,17 +2861,17 @@ SessionStoreService.prototype = { var _this = this; while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) { aTabs.shift(); // this tab got removed before being completely restored aTabData.shift(); } if (aTabs.length == 0) { // At this point we're essentially ready for consumers to read/write data // via the sessionstore API so we'll send the SSWindowStateReady event. - this._setWindowStateReady(aWindow); + this._sendWindowStateEvent(aWindow, "Ready"); return; // no more tabs to restore } var tab = aTabs.shift(); var tabData = aTabData.shift(); var browser = aWindow.gBrowser.getBrowserForTab(tab); var history = browser.webNavigation.sessionHistory; @@ -4010,52 +4007,16 @@ SessionStoreService.prototype = { this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED, ""); this._browserSetState = false; this._restoreCount = -1; }, /** - * Set the given window's busy state - * @param aWindow the window - * @param aValue the window's busy state - */ - _setWindowStateBusyValue: - function sss__changeWindowStateBusyValue(aWindow, aValue) { - - this._windows[aWindow.__SSi].busy = aValue; - - // Keep the to-be-restored state in sync because that is returned by - // getWindowState() as long as the window isn't loaded, yet. - if (!this._isWindowLoaded(aWindow)) { - let stateToRestore = this._statesToRestore[aWindow.__SS_restoreID].windows[0]; - stateToRestore.busy = aValue; - } - }, - - /** - * Set the given window's state to 'not busy'. - * @param aWindow the window - */ - _setWindowStateReady: function sss__setWindowStateReady(aWindow) { - this._setWindowStateBusyValue(aWindow, false); - this._sendWindowStateEvent(aWindow, "Ready"); - }, - - /** - * Set the given window's state to 'busy'. - * @param aWindow the window - */ - _setWindowStateBusy: function sss__setWindowStateBusy(aWindow) { - this._setWindowStateBusyValue(aWindow, true); - this._sendWindowStateEvent(aWindow, "Busy"); - }, - - /** * Dispatch an SSWindowState_____ event for the given window. * @param aWindow the window * @param aType the type of event, SSWindowState will be prepended to this string */ _sendWindowStateEvent: function sss__sendWindowStateEvent(aWindow, aType) { let event = aWindow.document.createEvent("Events"); event.initEvent("SSWindowState" + aType, true, false); aWindow.dispatchEvent(event);
--- a/browser/components/sessionstore/test/browser/Makefile.in +++ b/browser/components/sessionstore/test/browser/Makefile.in @@ -146,17 +146,16 @@ include $(topsrcdir)/config/rules.mk browser_623779.js \ browser_624727.js \ browser_625257.js \ browser_628270.js \ browser_635418.js \ browser_636279.js \ browser_645428.js \ browser_659591.js \ - browser_662812.js \ $(NULL) ifneq ($(OS_ARCH),Darwin) _BROWSER_TEST_FILES += \ browser_597071.js \ browser_625016.js \ $(NULL) endif
--- a/browser/components/sessionstore/test/browser/browser_595601-restore_hidden.js +++ b/browser/components/sessionstore/test/browser/browser_595601-restore_hidden.js @@ -1,117 +1,113 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ const TAB_STATE_NEEDS_RESTORE = 1; const TAB_STATE_RESTORING = 2; +let stateBackup = ss.getBrowserState(); + let state = {windows:[{tabs:[ {entries:[{url:"http://example.com#1"}]}, {entries:[{url:"http://example.com#2"}]}, {entries:[{url:"http://example.com#3"}]}, {entries:[{url:"http://example.com#4"}]}, {entries:[{url:"http://example.com#5"}], hidden: true}, {entries:[{url:"http://example.com#6"}], hidden: true}, {entries:[{url:"http://example.com#7"}], hidden: true}, {entries:[{url:"http://example.com#8"}], hidden: true} ]}]}; function test() { waitForExplicitFinish(); registerCleanupFunction(function () { Services.prefs.clearUserPref("browser.sessionstore.restore_hidden_tabs"); + + TabsProgressListener.uninit(); + + ss.setBrowserState(stateBackup); }); + TabsProgressListener.init(); + // First stage: restoreHiddenTabs = true // Second stage: restoreHiddenTabs = false test_loadTabs(true, function () { - test_loadTabs(false, finish); + test_loadTabs(false, function () { + waitForFocus(finish); + }); }); } function test_loadTabs(restoreHiddenTabs, callback) { Services.prefs.setBoolPref("browser.sessionstore.restore_hidden_tabs", restoreHiddenTabs); let expectedTabs = restoreHiddenTabs ? 8 : 4; + let firstProgress = true; - newWindowWithState(state, function (win, needsRestore, isRestoring) { + TabsProgressListener.setCallback(function (needsRestore, isRestoring) { if (firstProgress) { firstProgress = false; is(isRestoring, 3, "restoring 3 tabs concurrently"); } else { ok(isRestoring < 4, "restoring max. 3 tabs concurrently"); } - if (win.gBrowser.tabs.length - needsRestore == expectedTabs) { - is(win.gBrowser.visibleTabs.length, 4, "only 4 visible tabs"); - - TabsProgressListener.uninit(); + if (gBrowser.tabs.length - needsRestore == expectedTabs) { + TabsProgressListener.unsetCallback(); + is(gBrowser.visibleTabs.length, 4, "only 4 visible tabs"); callback(); } }); + + ss.setBrowserState(JSON.stringify(state)); +} + +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 (win) { - this.window = win; - - this.window.gBrowser.addTabsProgressListener(this); + init: function () { + gBrowser.addTabsProgressListener(this); }, uninit: function () { - this.window.gBrowser.removeTabsProgressListener(this); - - delete this.window; - delete this.callback; + 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, [this.window].concat(this.countTabs())); - }, - - countTabs: function () { - let needsRestore = 0, isRestoring = 0; - - for (let i = 0; i < this.window.gBrowser.tabs.length; i++) { - let browser = this.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]; + this.callback.apply(null, countTabs()); } } - -// ---------- -function whenWindowLoaded(win, callback) { - win.addEventListener("load", function onLoad() { - win.removeEventListener("load", onLoad, false); - executeSoon(callback); - }, false); -} - -// ---------- -function newWindowWithState(state, callback) { - let opts = "chrome,all,dialog=no,height=800,width=800"; - let win = window.openDialog(getBrowserURL(), "_blank", opts); - - registerCleanupFunction(function () win.close()); - - whenWindowLoaded(win, function () { - TabsProgressListener.init(win); - TabsProgressListener.setCallback(callback); - - ss.setWindowState(win, JSON.stringify(state), true); - }); -}
deleted file mode 100644 --- a/browser/components/sessionstore/test/browser/browser_662812.js +++ /dev/null @@ -1,34 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -function test() { - waitForExplicitFinish(); - - window.addEventListener("SSWindowStateBusy", function onBusy() { - window.removeEventListener("SSWindowStateBusy", onBusy, false); - - let state = JSON.parse(ss.getWindowState(window)); - ok(state.windows[0].busy, "window is busy"); - - window.addEventListener("SSWindowStateReady", function onReady() { - window.removeEventListener("SSWindowStateReady", onReady, false); - - let state = JSON.parse(ss.getWindowState(window)); - ok(!state.windows[0].busy, "window is not busy"); - - gBrowser.removeTab(gBrowser.tabs[1]); - executeSoon(finish); - }, false); - }, false); - - // create a new tab - let tab = gBrowser.addTab("about:mozilla"); - let browser = tab.linkedBrowser; - - // close and restore it - browser.addEventListener("load", function onLoad() { - browser.removeEventListener("load", onLoad, true); - gBrowser.removeTab(tab); - ss.undoCloseTab(window, 0); - }, true); -}