Bug 1054740 - When a session should be restored, don't load the homepage before the session file has been read. r?mikedeboer
MozReview-Commit-ID: 7W4ihQZEeWf
--- a/accessible/tests/mochitest/common.js
+++ b/accessible/tests/mochitest/common.js
@@ -163,17 +163,23 @@ function addA11yLoadEvent(aFunc, aWindow
return waitForDocLoad();
window.setTimeout(aFunc, 0);
},
0
);
}
- SimpleTest.waitForFocus(waitForDocLoad, aWindow);
+ if (aWindow &&
+ aWindow.document.activeElement &&
+ aWindow.document.activeElement.localName == "browser") {
+ waitForDocLoad();
+ } else {
+ SimpleTest.waitForFocus(waitForDocLoad, aWindow);
+ }
}
/**
* Analogy of SimpleTest.is function used to compare objects.
*/
function isObject(aObj, aExpectedObj, aMsg) {
if (aObj == aExpectedObj) {
ok(true, aMsg);
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1374,47 +1374,47 @@ var gBrowserInit = {
document.documentElement.setAttribute("darkwindowframe", "true");
}
}
ToolbarIconColor.init();
gRemoteControl.updateVisualCue(Marionette.running);
- let uriToLoad = this._getUriToLoad();
- gIdentityHandler.initIdentityBlock(uriToLoad);
+ this._uriToLoadPromise.then(uriToLoad => {
+ gIdentityHandler.initIdentityBlock(uriToLoad);
+ });
// Wait until chrome is painted before executing code not critical to making the window visible
- this._boundDelayedStartup = this._delayedStartup.bind(this, uriToLoad);
+ this._boundDelayedStartup = this._delayedStartup.bind(this);
window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
this._loadHandled = true;
},
_cancelDelayedStartup() {
window.removeEventListener("MozAfterPaint", this._boundDelayedStartup);
this._boundDelayedStartup = null;
},
- _delayedStartup(uriToLoad) {
+ _delayedStartup() {
let tmp = {};
Cu.import("resource://gre/modules/TelemetryTimestamps.jsm", tmp);
let TelemetryTimestamps = tmp.TelemetryTimestamps;
TelemetryTimestamps.add("delayedStartupStarted");
this._cancelDelayedStartup();
// We need to set the OfflineApps message listeners up before we
// load homepages, which might need them.
OfflineApps.init();
// This pageshow listener needs to be registered before we may call
// swapBrowsersAndCloseOther() to receive pageshow events fired by that.
- let mm = window.messageManager;
- mm.addMessageListener("PageVisibility:Show", function(message) {
+ window.messageManager.addMessageListener("PageVisibility:Show", function(message) {
if (message.target == gBrowser.selectedBrowser) {
setTimeout(pageShowEventHandlers, 0, message.data.persisted);
}
});
gBrowser.addEventListener("AboutTabCrashedLoad", function(event) {
let ownerDoc = event.originalTarget;
@@ -1435,99 +1435,17 @@ var gBrowserInit = {
gIdentityHandler.refreshIdentityBlock();
});
// Get the service so that it initializes and registers listeners for new
// tab pages in order to be ready for any early-loading about:newtab pages,
// e.g., start/home page, command line / startup uris to load, sessionstore
gAboutNewTabService.QueryInterface(Ci.nsISupports);
- if (uriToLoad && uriToLoad != "about:blank") {
- if (uriToLoad instanceof Ci.nsIArray) {
- let count = uriToLoad.length;
- let specs = [];
- for (let i = 0; i < count; i++) {
- let urisstring = uriToLoad.queryElementAt(i, Ci.nsISupportsString);
- specs.push(urisstring.data);
- }
-
- // This function throws for certain malformed URIs, so use exception handling
- // so that we don't disrupt startup
- try {
- gBrowser.loadTabs(specs, {
- inBackground: false,
- replace: true,
- triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
- });
- } catch (e) {}
- } else if (uriToLoad instanceof XULElement) {
- // swap the given tab with the default about:blank tab and then close
- // the original tab in the other window.
- let tabToOpen = uriToLoad;
-
- // If this tab was passed as a window argument, clear the
- // reference to it from the arguments array.
- if (window.arguments[0] == tabToOpen) {
- window.arguments[0] = null;
- }
-
- // Stop the about:blank load
- gBrowser.stop();
- // make sure it has a docshell
- gBrowser.docShell;
-
- // We must set usercontextid before updateBrowserRemoteness()
- // so that the newly created remote tab child has correct usercontextid
- if (tabToOpen.hasAttribute("usercontextid")) {
- let usercontextid = tabToOpen.getAttribute("usercontextid");
- gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
- }
-
- try {
- // Make sure selectedBrowser has the same remote settings as the one
- // we are swapping in.
- gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser,
- tabToOpen.linkedBrowser.isRemoteBrowser,
- { remoteType: tabToOpen.linkedBrowser.remoteType });
- gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
- } catch (e) {
- Cu.reportError(e);
- }
- } else if (window.arguments.length >= 3) {
- // window.arguments[2]: referrer (nsIURI | string)
- // [3]: postData (nsIInputStream)
- // [4]: allowThirdPartyFixup (bool)
- // [5]: referrerPolicy (int)
- // [6]: userContextId (int)
- // [7]: originPrincipal (nsIPrincipal)
- // [8]: triggeringPrincipal (nsIPrincipal)
- let referrerURI = window.arguments[2];
- if (typeof(referrerURI) == "string") {
- try {
- referrerURI = makeURI(referrerURI);
- } catch (e) {
- referrerURI = null;
- }
- }
- let referrerPolicy = (window.arguments[5] != undefined ?
- window.arguments[5] : Ci.nsIHttpChannel.REFERRER_POLICY_UNSET);
- let userContextId = (window.arguments[6] != undefined ?
- window.arguments[6] : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID);
- loadURI(uriToLoad, referrerURI, window.arguments[3] || null,
- window.arguments[4] || false, referrerPolicy, userContextId,
- // pass the origin principal (if any) and force its use to create
- // an initial about:blank viewer if present:
- window.arguments[7], !!window.arguments[7], window.arguments[8]);
- window.focus();
- } else {
- // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
- // Such callers expect that window.arguments[0] is handled as a single URI.
- loadOneOrMoreURIs(uriToLoad, Services.scriptSecurityManager.getSystemPrincipal());
- }
- }
+ this._handleURIToLoad();
Services.obs.addObserver(gIdentityHandler, "perm-changed");
Services.obs.addObserver(gRemoteControl, "remote-active");
Services.obs.addObserver(gSessionHistoryObserver, "browser:purge-session-history");
Services.obs.addObserver(gStoragePressureObserver, "QuotaManager::StoragePressure");
Services.obs.addObserver(gXPInstallObserver, "addon-install-disabled");
Services.obs.addObserver(gXPInstallObserver, "addon-install-started");
Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked");
@@ -1546,37 +1464,16 @@ var gBrowserInit = {
// Initialize the full zoom setting.
// We do this before the session restore service gets initialized so we can
// apply full zoom settings to tabs restored by the session restore service.
FullZoom.init();
PanelUI.init();
UpdateUrlbarSearchSplitterState();
- if (!(isBlankPageURL(uriToLoad) || uriToLoad == "about:privatebrowsing") ||
- !focusAndSelectUrlBar()) {
- if (gBrowser.selectedBrowser.isRemoteBrowser) {
- // If the initial browser is remote, in order to optimize for first paint,
- // we'll defer switching focus to that browser until it has painted.
- let focusedElement = document.commandDispatcher.focusedElement;
- mm.addMessageListener("Browser:FirstPaint", function onFirstPaint() {
- mm.removeMessageListener("Browser:FirstPaint", onFirstPaint);
- // If focus didn't move while we were waiting for first paint, we're okay
- // to move to the browser.
- if (document.commandDispatcher.focusedElement == focusedElement) {
- gBrowser.selectedBrowser.focus();
- }
- });
- } else {
- // If the initial browser is not remote, we can focus the browser
- // immediately with no paint performance impact.
- gBrowser.selectedBrowser.focus();
- }
- }
-
// Enable/Disable auto-hide tabbar
gBrowser.tabContainer.updateVisibility();
BookmarkingUI.init();
AutoShowBookmarksToolbar.init();
gPrefService.addObserver(gHomeButton.prefDomain, gHomeButton);
@@ -1688,16 +1585,142 @@ var gBrowserInit = {
this._schedulePerWindowIdleTasks();
document.documentElement.setAttribute("sessionrestored", "true");
});
Services.obs.notifyObservers(window, "browser-delayed-startup-finished");
TelemetryTimestamps.add("delayedStartupFinished");
},
+ _handleURIToLoad() {
+ let initiallyFocusedElement = document.commandDispatcher.focusedElement;
+
+ let firstBrowserPaintDeferred = {};
+ firstBrowserPaintDeferred.promise = new Promise(resolve => {
+ firstBrowserPaintDeferred.resolve = resolve;
+ });
+
+ let mm = window.messageManager;
+ mm.addMessageListener("Browser:FirstPaint", function onFirstPaint() {
+ mm.removeMessageListener("Browser:FirstPaint", onFirstPaint);
+ firstBrowserPaintDeferred.resolve();
+ });
+
+ this._uriToLoadPromise.then(uriToLoad => {
+ if (!uriToLoad || uriToLoad == "about:blank") {
+ return;
+ }
+
+ if (uriToLoad instanceof Ci.nsIArray) {
+ let count = uriToLoad.length;
+ let specs = [];
+ for (let i = 0; i < count; i++) {
+ let urisstring = uriToLoad.queryElementAt(i, Ci.nsISupportsString);
+ specs.push(urisstring.data);
+ }
+
+ // This function throws for certain malformed URIs, so use exception handling
+ // so that we don't disrupt startup
+ try {
+ gBrowser.loadTabs(specs, {
+ inBackground: false,
+ replace: true,
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+ });
+ } catch (e) {}
+ } else if (uriToLoad instanceof XULElement) {
+ // swap the given tab with the default about:blank tab and then close
+ // the original tab in the other window.
+ let tabToOpen = uriToLoad;
+
+ // If this tab was passed as a window argument, clear the
+ // reference to it from the arguments array.
+ if (window.arguments[0] == tabToOpen) {
+ window.arguments[0] = null;
+ }
+
+ // Stop the about:blank load
+ gBrowser.stop();
+ // make sure it has a docshell
+ gBrowser.docShell;
+
+ // We must set usercontextid before updateBrowserRemoteness()
+ // so that the newly created remote tab child has correct usercontextid
+ if (tabToOpen.hasAttribute("usercontextid")) {
+ let usercontextid = tabToOpen.getAttribute("usercontextid");
+ gBrowser.selectedBrowser.setAttribute("usercontextid", usercontextid);
+ }
+
+ try {
+ // Make sure selectedBrowser has the same remote settings as the one
+ // we are swapping in.
+ gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser,
+ tabToOpen.linkedBrowser.isRemoteBrowser,
+ { remoteType: tabToOpen.linkedBrowser.remoteType });
+ gBrowser.swapBrowsersAndCloseOther(gBrowser.selectedTab, tabToOpen);
+ } catch (e) {
+ Cu.reportError(e);
+ }
+ } else if (window.arguments.length >= 3) {
+ // window.arguments[2]: referrer (nsIURI | string)
+ // [3]: postData (nsIInputStream)
+ // [4]: allowThirdPartyFixup (bool)
+ // [5]: referrerPolicy (int)
+ // [6]: userContextId (int)
+ // [7]: originPrincipal (nsIPrincipal)
+ // [8]: triggeringPrincipal (nsIPrincipal)
+ let referrerURI = window.arguments[2];
+ if (typeof(referrerURI) == "string") {
+ try {
+ referrerURI = makeURI(referrerURI);
+ } catch (e) {
+ referrerURI = null;
+ }
+ }
+ let referrerPolicy = (window.arguments[5] != undefined ?
+ window.arguments[5] : Ci.nsIHttpChannel.REFERRER_POLICY_UNSET);
+ let userContextId = (window.arguments[6] != undefined ?
+ window.arguments[6] : Ci.nsIScriptSecurityManager.DEFAULT_USER_CONTEXT_ID);
+ loadURI(uriToLoad, referrerURI, window.arguments[3] || null,
+ window.arguments[4] || false, referrerPolicy, userContextId,
+ // pass the origin principal (if any) and force its use to create
+ // an initial about:blank viewer if present:
+ window.arguments[7], !!window.arguments[7], window.arguments[8]);
+ window.focus();
+ } else {
+ // Note: loadOneOrMoreURIs *must not* be called if window.arguments.length >= 3.
+ // Such callers expect that window.arguments[0] is handled as a single URI.
+ loadOneOrMoreURIs(uriToLoad, Services.scriptSecurityManager.getSystemPrincipal());
+ }
+ });
+
+ this._uriToLoadPromise.then(uriToLoad => {
+ if ((isBlankPageURL(uriToLoad) || uriToLoad == "about:privatebrowsing") &&
+ focusAndSelectUrlBar()) {
+ return;
+ }
+
+ if (gBrowser.selectedBrowser.isRemoteBrowser) {
+ // If the initial browser is remote, in order to optimize for first paint,
+ // we'll defer switching focus to that browser until it has painted.
+ firstBrowserPaintDeferred.promise.then(() => {
+ // If focus didn't move while we were waiting for first paint, we're okay
+ // to move to the browser.
+ if (document.commandDispatcher.focusedElement == initiallyFocusedElement) {
+ gBrowser.selectedBrowser.focus();
+ }
+ });
+ } else {
+ // If the initial browser is not remote, we can focus the browser
+ // immediately with no paint performance impact.
+ gBrowser.selectedBrowser.focus();
+ }
+ });
+ },
+
/**
* Use this function as an entry point to schedule tasks that
* need to run once per window after startup, and can be scheduled
* by using an idle callback.
*
* The functions scheduled here will fire from idle callbacks
* once every window has finished being restored by session
* restore, and after the equivalent only-once tasks
@@ -1750,38 +1773,48 @@ var gBrowserInit = {
.DownloadsTaskbar.registerIndicator(window);
} catch (ex) {
Cu.reportError(ex);
}
}, {timeout: 10000});
},
// Returns the URI(s) to load at startup.
- _getUriToLoad() {
- // window.arguments[0]: URI to load (string), or an nsIArray of
- // nsISupportsStrings to load, or a xul:tab of
- // a tabbrowser, which will be replaced by this
- // window (for this case, all other arguments are
- // ignored).
- if (!window.arguments || !window.arguments[0])
- return null;
-
- let uri = window.arguments[0];
- let sessionStartup = Cc["@mozilla.org/browser/sessionstartup;1"]
- .getService(Ci.nsISessionStartup);
- let defaultArgs = Cc["@mozilla.org/browser/clh;1"]
- .getService(Ci.nsIBrowserHandler)
- .defaultArgs;
-
- // If the given URI matches defaultArgs (the default homepage) we want
- // to block its load if we're going to restore a session anyway.
- if (uri == defaultArgs && sessionStartup.willOverrideHomepage)
- return null;
-
- return uri;
+ get _uriToLoadPromise() {
+ delete this._uriToLoadPromise;
+ return this._uriToLoadPromise = new Promise(resolve => {
+ // window.arguments[0]: URI to load (string), or an nsIArray of
+ // nsISupportsStrings to load, or a xul:tab of
+ // a tabbrowser, which will be replaced by this
+ // window (for this case, all other arguments are
+ // ignored).
+ if (!window.arguments || !window.arguments[0]) {
+ resolve(null);
+ return;
+ }
+
+ let uri = window.arguments[0];
+ let defaultArgs = Cc["@mozilla.org/browser/clh;1"]
+ .getService(Ci.nsIBrowserHandler)
+ .defaultArgs;
+
+ // If the given URI is different from the homepage, we want to load it.
+ if (uri != defaultArgs) {
+ resolve(uri);
+ return;
+ }
+
+ // The URI appears to be the the homepage. We want to load it only if
+ // session restore isn't about to override the homepage.
+ let sessionStartup = Cc["@mozilla.org/browser/sessionstartup;1"]
+ .getService(Ci.nsISessionStartup);
+ sessionStartup.willOverrideHomepagePromise.then(willOverrideHomepage => {
+ resolve(willOverrideHomepage ? null : uri);
+ });
+ });
},
onUnload() {
// In certain scenarios it's possible for unload to be fired before onload,
// (e.g. if the window is being closed after browser.js loads but before the
// load completes). In that case, there's nothing to do here.
if (!this._loadHandled)
return;
@@ -7721,16 +7754,21 @@ var gIdentityHandler = {
},
/**
* Used to initialize the identity block before first paint to avoid
* flickering when opening a new window showing a secure internal page
* (eg. about:home)
*/
initIdentityBlock(initialURI) {
+ if (this._uri) {
+ // Apparently we already loaded something, so there's nothing to do here.
+ return;
+ }
+
if ((typeof initialURI != "string") || !initialURI.startsWith("about:"))
return;
let uri = Services.io.newURI(initialURI);
if (this._secureInternalUIWhitelist.test(uri.pathQueryRef)) {
this._isSecureInternalUI = true;
this._ignoreAboutBlankUntilFirstLoad = true;
this.refreshIdentityBlock();
--- a/browser/base/content/test/performance/browser_windowopen_reflows.js
+++ b/browser/base/content/test/performance/browser_windowopen_reflows.js
@@ -12,17 +12,16 @@
* See https://developer.mozilla.org/en-US/Firefox/Performance_best_practices_for_Firefox_fe_engineers
* for tips on how to do that.
*/
const EXPECTED_REFLOWS = [
{
stack: [
"select@chrome://global/content/bindings/textbox.xml",
"focusAndSelectUrlBar@chrome://browser/content/browser.js",
- "_delayedStartup@chrome://browser/content/browser.js",
],
},
];
if (Services.appinfo.OS == "Linux") {
if (gMultiProcessBrowser) {
EXPECTED_REFLOWS.push({
stack: [
--- a/browser/components/sessionstore/nsISessionStartup.idl
+++ b/browser/components/sessionstore/nsISessionStartup.idl
@@ -31,32 +31,21 @@ interface nsISessionStartup: nsISupports
/**
* Determines whether automatic session restoration is enabled for this
* launch of the browser. This does not include crash restoration, and will
* return false if restoration will only be caused by a crash.
*/
boolean isAutomaticRestoreEnabled();
/**
- * Returns whether we will restore a session that ends up replacing the
- * homepage. The browser uses this to not start loading the homepage if
- * we're going to stop its load anyway shortly after.
- *
- * This is meant to be an optimization for the average case that loading the
- * session file finishes before we may want to start loading the default
- * homepage. Should this be called before the session file has been read it
- * will just return false.
- */
- readonly attribute bool willOverrideHomepage;
-
- /**
- * Returns a promise that resolves to a boolean indicating whether we will
- * restore a session that ends up replacing the homepage. The browser uses
- * this to not start loading the homepage if we're going to stop its load
- * anyway shortly after.
+ * Returns a promise that resolves to a boolean, indicating whether we will
+ * restore a session that ends up replacing the homepage. True guarantees
+ * that we'll restore a session; false means that we /probably/ won't do so.
+ * The browser uses this to avoid unnecessarily loading the homepage when
+ * restoring a session.
*/
readonly attribute jsval willOverrideHomepagePromise;
/**
* What type of session we're restoring.
* NO_SESSION There is no data available from the previous session
* RECOVER_SESSION The last session crashed. It will either be restored or
* about:sessionrestore will be shown.
--- a/browser/components/sessionstore/nsSessionStartup.js
+++ b/browser/components/sessionstore/nsSessionStartup.js
@@ -85,32 +85,38 @@ SessionStartup.prototype = {
// the state to restore at startup
_initialState: null,
_sessionType: Ci.nsISessionStartup.NO_SESSION,
_initialized: false,
// Stores whether the previous session crashed.
_previousSessionCrashed: null,
+ _resumeSessionEnabled: null,
+
/* ........ Global Event Handlers .............. */
/**
* Initialize the component
*/
init: function sss_init() {
Services.obs.notifyObservers(null, "sessionstore-init-started");
StartupPerformance.init();
// do not need to initialize anything in auto-started private browsing sessions
if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
this._initialized = true;
gOnceInitializedDeferred.resolve();
return;
}
+ this._resumeSessionEnabled =
+ Services.prefs.getBoolPref("browser.sessionstore.resume_session_once") ||
+ Services.prefs.getIntPref("browser.startup.page") == BROWSER_STARTUP_RESUME_SESSION;
+
SessionFile.read().then(
this._onSessionFileRead.bind(this),
console.error
);
},
// Wrap a string as a nsISupports
_createSupportsString: function ssfi_createSupportsString(aData) {
@@ -161,22 +167,18 @@ SessionStartup.prototype = {
let pinnedTabCount = initialState.windows.reduce((winAcc, win) => {
return winAcc + win.tabs.reduce((tabAcc, tab) => {
return tabAcc + (tab.pinned ? 1 : 0);
}, 0);
}, 0);
Services.telemetry.scalarSet("browser.engagement.restored_pinned_tabs_count", pinnedTabCount);
}, 60000);
- let shouldResumeSessionOnce = Services.prefs.getBoolPref("browser.sessionstore.resume_session_once");
- let shouldResumeSession = shouldResumeSessionOnce ||
- Services.prefs.getIntPref("browser.startup.page") == BROWSER_STARTUP_RESUME_SESSION;
-
// If this is a normal restore then throw away any previous session
- if (!shouldResumeSessionOnce && this._initialState) {
+ if (!this._resumeSessionEnabled && this._initialState) {
delete this._initialState.lastSessionState;
}
let resumeFromCrash = Services.prefs.getBoolPref("browser.sessionstore.resume_from_crash");
CrashMonitor.previousCheckpoints.then(checkpoints => {
if (checkpoints) {
// If the previous session finished writing the final state, we'll
@@ -211,17 +213,17 @@ SessionStartup.prototype = {
// Report shutdown success via telemetry. Shortcoming here are
// being-killed-by-OS-shutdown-logic, shutdown freezing after
// session restore was written, etc.
Services.telemetry.getHistogramById("SHUTDOWN_OK").add(!this._previousSessionCrashed);
// set the startup type
if (this._previousSessionCrashed && resumeFromCrash)
this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
- else if (!this._previousSessionCrashed && shouldResumeSession)
+ else if (!this._previousSessionCrashed && this._resumeSessionEnabled)
this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
else if (this._initialState)
this._sessionType = Ci.nsISessionStartup.DEFER_SESSION;
else
this._initialState = null; // reset the state
Services.obs.addObserver(this, "sessionstore-windows-restored", true);
@@ -307,46 +309,41 @@ SessionStartup.prototype = {
* @returns bool
*/
_willRestore() {
return this._sessionType == Ci.nsISessionStartup.RECOVER_SESSION ||
this._sessionType == Ci.nsISessionStartup.RESUME_SESSION;
},
/**
- * Returns whether we will restore a session that ends up replacing the
- * homepage. The browser uses this to not start loading the homepage if
- * we're going to stop its load anyway shortly after.
- *
- * This is meant to be an optimization for the average case that loading the
- * session file finishes before we may want to start loading the default
- * homepage. Should this be called before the session file has been read it
- * will just return false.
- *
- * @returns bool
- */
- get willOverrideHomepage() {
- if (this._initialState && this._willRestore()) {
- let windows = this._initialState.windows || null;
- // If there are valid windows with not only pinned tabs, signal that we
- // will override the default homepage by restoring a session.
- return windows && windows.some(w => w.tabs.some(t => !t.pinned));
- }
- return false;
- },
-
- /**
- * Returns a promise that resolves to a boolean indicating whether we will
- * restore a session that ends up replacing the homepage. The browser uses
- * this to not start loading the homepage if we're going to stop its load
- * anyway shortly after.
+ * Returns a promise that resolves to a boolean, indicating whether we will
+ * restore a session that ends up replacing the homepage. True guarantees
+ * that we'll restore a session; false means that we /probably/ won't do so.
+ * The browser uses this to avoid unnecessarily loading the homepage when
+ * restoring a session.
*/
get willOverrideHomepagePromise() {
+ // If the session file hasn't been read yet and resuming the session isn't
+ // enabled via prefs, go ahead and load the homepage. We may still replace
+ // it when recovering from a crash, which we'll only know after reading the
+ // session file, but waiting for that would delay loading the homepage in
+ // the non-crash case.
+ if (!this._initialState && !this._resumeSessionEnabled) {
+ return Promise.resolve(false);
+ }
+
return new Promise(resolve => {
- resolve(this.willOverrideHomepage);
+ this.onceInitialized.then(() => {
+ // If there are valid windows with not only pinned tabs, signal that we
+ // will override the default homepage by restoring a session.
+ resolve(this._willRestore() &&
+ this._initialState &&
+ this._initialState.windows &&
+ this._initialState.windows.some(w => w.tabs.some(t => !t.pinned)));
+ });
});
},
/**
* Get the type of pending session store, if any.
*/
get sessionType() {
return this._sessionType;
--- a/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
+++ b/dom/tests/mochitest/localstorage/test_localStorageQuotaPrivateBrowsing_perwindowpb.html
@@ -146,40 +146,34 @@ function onMessageReceived(event, aWindo
break;
// Any other message indicates error or succes message of a test
default:
SimpleTest.ok(!event.data.match(failureRegExp), event.data);
break;
}
}
-function whenDelayedStartupFinished(aWindow, aCallback) {
+function whenDelayedStartupFinished(aCallback) {
Services.obs.addObserver(function observer(aSubject, aTopic) {
- if (aWindow == aSubject) {
- Services.obs.removeObserver(observer, aTopic);
- }
+ Services.obs.removeObserver(observer, aTopic);
- if (aWindow.content == null || aWindow.content.location.href != CONTENT_PAGE ) {
- aWindow.addEventListener("DOMContentLoaded", function() {
- SimpleTest.executeSoon(function() { aCallback(aWindow); });
- }, {capture: true, once: true});
-
- aWindow.gBrowser.loadURI(CONTENT_PAGE);
- }
+ aSubject.addEventListener("DOMContentLoaded", function() {
+ SimpleTest.executeSoon(function() { aCallback(aSubject); });
+ }, {capture: true, once: true});
}, "browser-delayed-startup-finished");
}
function testOnWindow(aIsPrivate, callback) {
var mainWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
- var win = mainWindow.OpenBrowserWindow({private: aIsPrivate});
- whenDelayedStartupFinished(win, function() { callback(win); });
+ mainWindow.openUILinkIn(CONTENT_PAGE, "window", {private: aIsPrivate});
+ whenDelayedStartupFinished(callback);
};
</script>
</head>
<body onload="startTest();">
</body>
</html>