--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -11,16 +11,17 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
// Current version of the format used by Session Restore.
const FORMAT_VERSION = 1;
const TAB_STATE_NEEDS_RESTORE = 1;
const TAB_STATE_RESTORING = 2;
+const TAB_STATE_WILL_RESTORE = 3;
const NOTIFY_WINDOWS_RESTORED = "sessionstore-windows-restored";
const NOTIFY_BROWSER_STATE_RESTORED = "sessionstore-browser-state-restored";
const NOTIFY_LAST_SESSION_CLEARED = "sessionstore-last-session-cleared";
const NOTIFY_TAB_RESTORED = "sessionstore-debug-tab-restored"; // WARNING: debug-only
// Maximum number of tabs to restore simultaneously. Previously controlled by
@@ -1792,26 +1793,24 @@ var SessionStoreInternal = {
* Handler for the event that is fired when a <xul:browser> crashes.
*
* @param aWindow
* The window that the crashed browser belongs to.
* @param aBrowser
* The <xul:browser> that is now in the crashed state.
*/
onBrowserCrashed: function(aWindow, aBrowser) {
+ NS_ASSERT(aBrowser.isRemoteBrowser,
+ "Only remote browsers should be able to crash");
this._crashedBrowsers.add(aBrowser.permanentKey);
- // If we never got around to restoring this tab, clear its state so
- // that we don't try restoring if the user switches to it before
- // reviving the crashed browser. This is throwing away the information
- // that the tab was in a pending state when the browser crashed, which
- // is an explicit choice. For now, when restoring all crashed tabs, based
- // on a user preference we'll either restore all of them at once, or only
- // restore the selected tab and lazily restore the rest. We'll make no
- // efforts at this time to be smart and restore all of the tabs that had
- // been in a restored state at the time of the crash.
+
+ // If we hadn't yet restored, or were still in the midst of
+ // restoring this browser at the time of the crash, we need
+ // to reset its state so that we can try to restore it again
+ // when the user revives the tab from the crash.
if (aBrowser.__SS_restoreState) {
let tab = aWindow.gBrowser.getTabForBrowser(aBrowser);
this._resetLocalTabRestoringState(tab);
}
// The browser crashed so we might never receive flush responses.
// Resolve all pending flush requests for the crashed browser.
TabStateFlusher.resolveAll(aBrowser);
@@ -2346,16 +2345,23 @@ var SessionStoreInternal = {
// Sanity check - the browser to be revived should not be remote
// at this point.
if (browser.isRemoteBrowser) {
throw new Error("SessionStore.reviveCrashedTab: " +
"Somehow a crashed browser is still remote.")
}
+ // We put the browser at about:blank in case the user is
+ // restoring tabs on demand. This way, the user won't see
+ // a flash of the about:tabcrashed page after selecting
+ // the revived tab.
+ aTab.removeAttribute("crashed");
+ browser.loadURI("about:blank", null, null);
+
let data = TabState.collect(aTab);
this.restoreTab(aTab, data);
},
/**
* Revive all crashed tabs and reset the crashed tabs count to 0.
*/
reviveAllCrashedTabs() {
@@ -2413,16 +2419,18 @@ var SessionStoreInternal = {
// Need to reset restoring tabs.
if (tab.linkedBrowser.__SS_restoreState) {
this._resetLocalTabRestoringState(tab);
}
// Restore the state into the tab.
this.restoreTab(tab, tabState, options);
});
+
+ tab.linkedBrowser.__SS_restoreState = TAB_STATE_WILL_RESTORE;
},
/**
* Retrieves the latest session history information for a tab. The cached data
* is returned immediately, but a callback may be provided that supplies
* up-to-date data when or if it is available. The callback is passed a single
* argument with data in the same format as the return value.
*
@@ -2801,17 +2809,20 @@ var SessionStoreInternal = {
if (overwriteTabs && tabbrowser.selectedTab._tPos >= newTabCount)
tabbrowser.moveTabTo(tabbrowser.selectedTab, newTabCount - 1);
let numVisibleTabs = 0;
for (var t = 0; t < newTabCount; t++) {
tabs.push(t < openTabCount ?
tabbrowser.tabs[t] :
- tabbrowser.addTab("about:blank", {skipAnimation: true}));
+ tabbrowser.addTab("about:blank", {
+ skipAnimation: true,
+ forceNotRemote: true,
+ }));
if (winData.tabs[t].pinned)
tabbrowser.pinTab(tabs[t]);
if (winData.tabs[t].hidden) {
tabbrowser.hideTab(tabs[t]);
}
else {
@@ -3109,31 +3120,16 @@ var SessionStoreInternal = {
// Ensure the index is in bounds.
let activeIndex = (tabData.index || tabData.entries.length) - 1;
activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
activeIndex = Math.max(activeIndex, 0);
// Save the index in case we updated it above.
tabData.index = activeIndex + 1;
- // In electrolysis, we may need to change the browser's remote
- // attribute so that it runs in a content process.
- let activePageData = tabData.entries[activeIndex] || null;
- let uri = activePageData ? activePageData.url || null : null;
- if (loadArguments) {
- uri = loadArguments.uri;
- }
- tabbrowser.updateBrowserRemotenessByURL(browser, uri);
-
- // If the restored browser wants to show view source content, start up a
- // view source browser that will load the required frame script.
- if (uri && ViewSourceBrowser.isViewSource(uri)) {
- new ViewSourceBrowser(browser);
- }
-
// Start a new epoch to discard all frame script messages relating to a
// previous epoch. All async messages that are still on their way to chrome
// will be ignored and don't override any tab data set when restoring.
let epoch = this.startNextEpoch(browser);
// keep the data around to prevent dataloss in case
// a tab gets closed before it's been properly restored
browser.__SS_restoreState = TAB_STATE_NEEDS_RESTORE;
@@ -3182,19 +3178,55 @@ var SessionStoreInternal = {
* Kicks off restoring the given tab.
*
* @param aTab
* the tab to restore
* @param aLoadArguments
* optional load arguments used for loadURI()
*/
restoreTabContent: function (aTab, aLoadArguments = null) {
+ let browser = aTab.linkedBrowser;
+ let window = aTab.ownerDocument.defaultView;
+ let tabbrowser = window.gBrowser;
+ let tabData = TabState.clone(aTab);
+ let activeIndex = tabData.index - 1;
+ let activePageData = tabData.entries[activeIndex] || null;
+ let uri = activePageData ? activePageData.url || null : null;
+ if (aLoadArguments) {
+ uri = aLoadArguments.uri;
+ }
+
+ // We have to mark this tab as restoring first, otherwise
+ // the "pending" attribute will be applied to the linked
+ // browser, which removes it from the display list. We cannot
+ // flip the remoteness of any browser that is not being displayed.
this.markTabAsRestoring(aTab);
- let browser = aTab.linkedBrowser;
+ if (tabbrowser.updateBrowserRemotenessByURL(browser, uri)) {
+ // We updated the remoteness, so we need to send the history down again.
+ //
+ // Start a new epoch to discard all frame script messages relating to a
+ // previous epoch. All async messages that are still on their way to chrome
+ // will be ignored and don't override any tab data set when restoring.
+ let epoch = this.startNextEpoch(browser);
+
+ browser.messageManager.sendAsyncMessage("SessionStore:restoreHistory", {
+ tabData: tabData,
+ epoch: epoch,
+ loadArguments: aLoadArguments
+ });
+
+ }
+
+ // If the restored browser wants to show view source content, start up a
+ // view source browser that will load the required frame script.
+ if (uri && ViewSourceBrowser.isViewSource(uri)) {
+ new ViewSourceBrowser(browser);
+ }
+
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
{loadArguments: aLoadArguments});
},
/**
* Marks a given pending tab as restoring.
*
* @param aTab