Bug 670040: Make nsISessionStartup.state a jsval to save repeatedly stringifying/parsing the initial state. r=zpao

This commit is contained in:
Dave Townsend
2011-07-15 09:42:21 -07:00
parent f88dea1f9e
commit b26e4854c4
3 changed files with 30 additions and 34 deletions

View File

@@ -43,11 +43,11 @@
* - and allows to restore everything into one window. * - and allows to restore everything into one window.
*/ */
[scriptable, uuid(e7bb7828-0e32-4995-a848-4aa35df603c7)] [scriptable, uuid(170c6857-7f71-46ce-bc9b-185723b1c3a8)]
interface nsISessionStartup: nsISupports interface nsISessionStartup: nsISupports
{ {
// Get session state as string // Get session state
readonly attribute AString state; readonly attribute jsval state;
/** /**
* Determine if session should be restored * Determine if session should be restored

View File

@@ -89,7 +89,7 @@ function SessionStartup() {
SessionStartup.prototype = { SessionStartup.prototype = {
// the state to restore at startup // the state to restore at startup
_iniString: null, _initialState: null,
_sessionType: Ci.nsISessionStartup.NO_SESSION, _sessionType: Ci.nsISessionStartup.NO_SESSION,
/* ........ Global Event Handlers .............. */ /* ........ Global Event Handlers .............. */
@@ -121,31 +121,30 @@ SessionStartup.prototype = {
return; return;
// get string containing session state // get string containing session state
this._iniString = this._readStateFile(sessionFile); let iniString = this._readStateFile(sessionFile);
if (!this._iniString) if (!iniString)
return; return;
// parse the session state into a JS object // parse the session state into a JS object
let initialState;
try { try {
// remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0) // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
if (this._iniString.charAt(0) == '(') if (iniString.charAt(0) == '(')
this._iniString = this._iniString.slice(1, -1); iniString = iniString.slice(1, -1);
try { try {
initialState = JSON.parse(this._iniString); this._initialState = JSON.parse(iniString);
} }
catch (exJSON) { catch (exJSON) {
var s = new Cu.Sandbox("about:blank"); var s = new Cu.Sandbox("about:blank");
initialState = Cu.evalInSandbox("(" + this._iniString + ")", s); this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
this._iniString = JSON.stringify(initialState);
} }
} }
catch (ex) { debug("The session file is invalid: " + ex); } catch (ex) { debug("The session file is invalid: " + ex); }
let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash"); let resumeFromCrash = prefBranch.getBoolPref("sessionstore.resume_from_crash");
let lastSessionCrashed = let lastSessionCrashed =
initialState && initialState.session && initialState.session.state && this._initialState && this._initialState.session &&
initialState.session.state == STATE_RUNNING_STR; this._initialState.session.state &&
this._initialState.session.state == STATE_RUNNING_STR;
// Report shutdown success via telemetry. Shortcoming here are // Report shutdown success via telemetry. Shortcoming here are
// being-killed-by-OS-shutdown-logic, shutdown freezing after // being-killed-by-OS-shutdown-logic, shutdown freezing after
@@ -158,17 +157,17 @@ SessionStartup.prototype = {
this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION; this._sessionType = Ci.nsISessionStartup.RECOVER_SESSION;
else if (!lastSessionCrashed && doResumeSession) else if (!lastSessionCrashed && doResumeSession)
this._sessionType = Ci.nsISessionStartup.RESUME_SESSION; this._sessionType = Ci.nsISessionStartup.RESUME_SESSION;
else if (initialState) else if (this._initialState)
this._sessionType = Ci.nsISessionStartup.DEFER_SESSION; this._sessionType = Ci.nsISessionStartup.DEFER_SESSION;
else else
this._iniString = null; // reset the state string this._initialState = null; // reset the state
// wait for the first browser window to open // wait for the first browser window to open
// Don't reset the initial window's default args (i.e. the home page(s)) // Don't reset the initial window's default args (i.e. the home page(s))
// if all stored tabs are pinned. // if all stored tabs are pinned.
if (this.doRestore() && if (this.doRestore() &&
(!initialState.windows || (!this._initialState.windows ||
!initialState.windows.every(function (win) !this._initialState.windows.every(function (win)
win.tabs.every(function (tab) tab.pinned)))) win.tabs.every(function (tab) tab.pinned))))
Services.obs.addObserver(this, "domwindowopened", true); Services.obs.addObserver(this, "domwindowopened", true);
@@ -204,8 +203,8 @@ SessionStartup.prototype = {
break; break;
case "sessionstore-windows-restored": case "sessionstore-windows-restored":
Services.obs.removeObserver(this, "sessionstore-windows-restored"); Services.obs.removeObserver(this, "sessionstore-windows-restored");
// free _iniString after nsSessionStore is done with it // free _initialState after nsSessionStore is done with it
this._iniString = null; this._initialState = null;
this._sessionType = Ci.nsISessionStartup.NO_SESSION; this._sessionType = Ci.nsISessionStartup.NO_SESSION;
break; break;
} }
@@ -254,7 +253,7 @@ SessionStartup.prototype = {
* Get the session state as a string * Get the session state as a string
*/ */
get state() { get state() {
return this._iniString; return this._initialState;
}, },
/** /**

View File

@@ -304,33 +304,31 @@ SessionStoreService.prototype = {
this._sessionFileBackup.append("sessionstore.bak"); this._sessionFileBackup.append("sessionstore.bak");
// get string containing session state // get string containing session state
var iniString;
var ss = Cc["@mozilla.org/browser/sessionstartup;1"]. var ss = Cc["@mozilla.org/browser/sessionstartup;1"].
getService(Ci.nsISessionStartup); getService(Ci.nsISessionStartup);
try { try {
if (ss.doRestore() || if (ss.doRestore() ||
ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION)
iniString = ss.state; this._initialState = ss.state;
} }
catch(ex) { dump(ex + "\n"); } // no state to restore, which is ok catch(ex) { dump(ex + "\n"); } // no state to restore, which is ok
if (iniString) { if (this._initialState) {
try { try {
// If we're doing a DEFERRED session, then we want to pull pinned tabs // If we're doing a DEFERRED session, then we want to pull pinned tabs
// out so they can be restored. // out so they can be restored.
if (ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) { if (ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) {
let [iniState, remainingState] = this._prepDataForDeferredRestore(iniString); let [iniState, remainingState] = this._prepDataForDeferredRestore(this._initialState);
// If we have a iniState with windows, that means that we have windows // If we have a iniState with windows, that means that we have windows
// with app tabs to restore. // with app tabs to restore.
if (iniState.windows.length) if (iniState.windows.length)
this._initialState = iniState; this._initialState = iniState;
else
this._initialState = null;
if (remainingState.windows.length) if (remainingState.windows.length)
this._lastSessionState = remainingState; this._lastSessionState = remainingState;
} }
else { else {
// parse the session state into JS objects
this._initialState = JSON.parse(iniString);
let lastSessionCrashed = let lastSessionCrashed =
this._initialState.session && this._initialState.session.state && this._initialState.session && this._initialState.session.state &&
this._initialState.session.state == STATE_RUNNING_STR; this._initialState.session.state == STATE_RUNNING_STR;
@@ -342,7 +340,7 @@ SessionStoreService.prototype = {
// replace the crashed session with a restore-page-only session // replace the crashed session with a restore-page-only session
let pageData = { let pageData = {
url: "about:sessionrestore", url: "about:sessionrestore",
formdata: { "#sessionData": iniString } formdata: { "#sessionData": JSON.stringify(this._initialState) }
}; };
this._initialState = { windows: [{ tabs: [{ entries: [pageData] }] }] }; this._initialState = { windows: [{ tabs: [{ entries: [pageData] }] }] };
} }
@@ -811,7 +809,7 @@ SessionStoreService.prototype = {
// We'll cheat a little bit and reuse _prepDataForDeferredRestore // We'll cheat a little bit and reuse _prepDataForDeferredRestore
// even though it wasn't built exactly for this. // even though it wasn't built exactly for this.
let [appTabsState, normalTabsState] = let [appTabsState, normalTabsState] =
this._prepDataForDeferredRestore(JSON.stringify({ windows: [closedWindowState] })); this._prepDataForDeferredRestore({ windows: [closedWindowState] });
// These are our pinned tabs, which we should restore // These are our pinned tabs, which we should restore
if (appTabsState.windows.length) { if (appTabsState.windows.length) {
@@ -3794,12 +3792,11 @@ SessionStoreService.prototype = {
* this._lastSessionState and will be kept in case the user explicitly wants * this._lastSessionState and will be kept in case the user explicitly wants
* to restore the previous session (publicly exposed as restoreLastSession). * to restore the previous session (publicly exposed as restoreLastSession).
* *
* @param stateString * @param state
* The state string, presumably from nsISessionStartup.state * The state, presumably from nsISessionStartup.state
* @returns [defaultState, state] * @returns [defaultState, state]
*/ */
_prepDataForDeferredRestore: function sss__prepDataForDeferredRestore(stateString) { _prepDataForDeferredRestore: function sss__prepDataForDeferredRestore(state) {
let state = JSON.parse(stateString);
let defaultState = { windows: [], selectedWindow: 1 }; let defaultState = { windows: [], selectedWindow: 1 };
state.selectedWindow = state.selectedWindow || 1; state.selectedWindow = state.selectedWindow || 1;