Skip to content

Commit

Permalink
Merge m-c to m-i
Browse files Browse the repository at this point in the history
  • Loading branch information
philor committed Apr 22, 2013
2 parents 7f0c97b + 12a533f commit 78cfaae
Show file tree
Hide file tree
Showing 21 changed files with 493 additions and 127 deletions.
1 change: 1 addition & 0 deletions browser/base/content/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,7 @@ var gBrowserInit = {
window.addEventListener("AppCommand", HandleAppCommandEvent, true);

messageManager.loadFrameScript("chrome://browser/content/content.js", true);
messageManager.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);

// initialize observers and listeners
// and give C++ access to gBrowser
Expand Down
40 changes: 40 additions & 0 deletions browser/components/sessionstore/content/content-sessionStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

function debug(msg) {
Services.console.logStringMessage("SessionStoreContent: " + msg);
}

/**
* Listens for and handles content events that we need for the
* session store service to be notified of state changes in content.
*/
let EventListener = {

DOM_EVENTS: [
"pageshow", "change", "input"
],

init: function () {
this.DOM_EVENTS.forEach(e => addEventListener(e, this, true));
},

handleEvent: function (event) {
switch (event.type) {
case "pageshow":
if (event.persisted)
sendAsyncMessage("SessionStore:pageshow");
break;
case "input":
case "change":
sendAsyncMessage("SessionStore:input");
break;
default:
debug("received unknown event '" + event.type + "'");
break;
}
}
};

EventListener.init();
1 change: 1 addition & 0 deletions browser/components/sessionstore/jar.mn
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
browser.jar:
* content/browser/aboutSessionRestore.xhtml (content/aboutSessionRestore.xhtml)
* content/browser/aboutSessionRestore.js (content/aboutSessionRestore.js)
content/browser/content-sessionStore.js (content/content-sessionStore.js)
122 changes: 71 additions & 51 deletions browser/components/sessionstore/src/SessionStore.jsm
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,16 @@ const WINDOW_HIDEABLE_FEATURES = [
"menubar", "toolbar", "locationbar", "personalbar", "statusbar", "scrollbars"
];

/*
docShell capabilities to (re)store
Restored in restoreHistory()
eg: browser.docShell["allow" + aCapability] = false;
XXX keep these in sync with all the attributes starting
with "allow" in /docshell/base/nsIDocShell.idl
*/
const CAPABILITIES = [
"Subframes", "Plugins", "Javascript", "MetaRedirects", "Images",
"DNSPrefetch", "Auth", "WindowControl"
const MESSAGES = [
// The content script tells us that its form data (or that of one of its
// subframes) might have changed. This can be the contents or values of
// standard form fields or of ContentEditables.
"SessionStore:input",

// The content script has received a pageshow event. This happens when a
// page is loaded from bfcache without any network activity, i.e. when
// clicking the back or forward button.
"SessionStore:pageshow"
];

// These are tab events that we listen to.
Expand All @@ -85,6 +84,23 @@ Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", this);
XPCOMUtils.defineLazyServiceGetter(this, "gSessionStartup",
"@mozilla.org/browser/sessionstartup;1", "nsISessionStartup");

// List of docShell capabilities to (re)store. These are automatically
// retrieved from a given docShell if not already collected before.
// This is made so they're automatically in sync with all nsIDocShell.allow*
// properties.
let gDocShellCapabilities = (function () {
let caps;

return docShell => {
if (!caps) {
let keys = Object.keys(docShell);
caps = keys.filter(k => k.startsWith("allow")).map(k => k.slice(5));
}

return caps;
};
})();

XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager",
Expand Down Expand Up @@ -609,6 +625,29 @@ let SessionStoreInternal = {
}
},

/**
* This method handles incoming messages sent by the session store content
* script and thus enables communication with OOP tabs.
*/
receiveMessage: function ssi_receiveMessage(aMessage) {
var browser = aMessage.target;
var win = browser.ownerDocument.defaultView;

switch (aMessage.name) {
case "SessionStore:pageshow":
this.onTabLoad(win, browser);
break;
case "SessionStore:input":
this.onTabInput(win, browser);
break;
default:
debug("received unknown message '" + aMessage.name + "'");
break;
}

this._clearRestoringWindows();
},

/* ........ Window Event Handlers .............. */

/**
Expand All @@ -621,16 +660,10 @@ let SessionStoreInternal = {
// If __SS_restore_data is set, then we need to restore the document
// (form data, scrolling, etc.). This will only happen when a tab is
// first restored.
if (aEvent.currentTarget.__SS_restore_data)
this.restoreDocument(win, aEvent.currentTarget, aEvent);
// We still need to call onTabLoad, so fall through to "pageshow" case.
case "pageshow":
this.onTabLoad(win, aEvent.currentTarget, aEvent);
break;
case "change":
case "input":
case "DOMAutoComplete":
this.onTabInput(win, aEvent.currentTarget);
let browser = aEvent.currentTarget;
if (browser.__SS_restore_data)
this.restoreDocument(win, browser, aEvent);
this.onTabLoad(win, browser);
break;
case "TabOpen":
this.onTabAdd(win, aEvent.originalTarget);
Expand Down Expand Up @@ -1193,10 +1226,9 @@ let SessionStoreInternal = {
onTabAdd: function ssi_onTabAdd(aWindow, aTab, aNoNotification) {
let browser = aTab.linkedBrowser;
browser.addEventListener("load", this, true);
browser.addEventListener("pageshow", this, true);
browser.addEventListener("change", this, true);
browser.addEventListener("input", this, true);
browser.addEventListener("DOMAutoComplete", this, true);

let mm = browser.messageManager;
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));

if (!aNoNotification) {
this.saveStateDelayed(aWindow);
Expand All @@ -1217,10 +1249,9 @@ let SessionStoreInternal = {
onTabRemove: function ssi_onTabRemove(aWindow, aTab, aNoNotification) {
let browser = aTab.linkedBrowser;
browser.removeEventListener("load", this, true);
browser.removeEventListener("pageshow", this, true);
browser.removeEventListener("change", this, true);
browser.removeEventListener("input", this, true);
browser.removeEventListener("DOMAutoComplete", this, true);

let mm = browser.messageManager;
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));

delete browser.__SS_data;
delete browser.__SS_tabStillLoading;
Expand Down Expand Up @@ -1289,17 +1320,14 @@ let SessionStoreInternal = {
* Window reference
* @param aBrowser
* Browser reference
* @param aEvent
* Event obj
*/
onTabLoad: function ssi_onTabLoad(aWindow, aBrowser, aEvent) {
onTabLoad: function ssi_onTabLoad(aWindow, aBrowser) {
// react on "load" and solitary "pageshow" events (the first "pageshow"
// following "load" is too late for deleting the data caches)
// It's possible to get a load event after calling stop on a browser (when
// overwriting tabs). We want to return early if the tab hasn't been restored yet.
if ((aEvent.type != "load" && !aEvent.persisted) ||
(aBrowser.__SS_restoreState &&
aBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)) {
if (aBrowser.__SS_restoreState &&
aBrowser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE) {
return;
}

Expand Down Expand Up @@ -1959,9 +1987,9 @@ let SessionStoreInternal = {
tabData.hidden = aTab.hidden;

var disallow = [];
for (var i = 0; i < CAPABILITIES.length; i++)
if (!browser.docShell["allow" + CAPABILITIES[i]])
disallow.push(CAPABILITIES[i]);
for (let cap of gDocShellCapabilities(browser.docShell))
if (!browser.docShell["allow" + cap])
disallow.push(cap);
if (disallow.length > 0)
tabData.disallow = disallow.join(",");
else if (tabData.disallow)
Expand Down Expand Up @@ -2236,16 +2264,8 @@ let SessionStoreInternal = {
}

// designMode is undefined e.g. for XUL documents (as about:config)
if ((aContent.document.designMode || "") == "on" && aContent.document.body) {
if (aData.innerHTML === undefined && !aFullData) {
// we get no "input" events from iframes - listen for keypress here
let _this = this;
aContent.addEventListener("keypress", function(aEvent) {
_this.saveStateDelayed(aWindow, 3000);
}, true);
}
if ((aContent.document.designMode || "") == "on" && aContent.document.body)
aData.innerHTML = aContent.document.body.innerHTML;
}
}

// get scroll position from nsIDOMWindowUtils, since it allows avoiding a
Expand Down Expand Up @@ -3090,10 +3110,10 @@ let SessionStoreInternal = {
}

// make sure to reset the capabilities and attributes, in case this tab gets reused
var disallow = (tabData.disallow)?tabData.disallow.split(","):[];
CAPABILITIES.forEach(function(aCapability) {
browser.docShell["allow" + aCapability] = disallow.indexOf(aCapability) == -1;
});
let disallow = new Set(tabData.disallow && tabData.disallow.split(","));
for (let cap of gDocShellCapabilities(browser.docShell))
browser.docShell["allow" + cap] = !disallow.has(cap);

for (let name in this.xulAttributes)
tab.removeAttribute(name);
for (let name in tabData.attributes)
Expand Down
5 changes: 4 additions & 1 deletion browser/components/sessionstore/test/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ XPCSHELL_TESTS = \

MOCHITEST_BROWSER_FILES = \
head.js \
browser_capabilities.js \
browser_form_restore_events.js \
browser_form_restore_events_sample.html \
browser_formdata_format.js \
browser_formdata_format_sample.html \
browser_input.js \
browser_input_sample.html \
browser_pageshow.js \
browser_248970_b_perwindowpb.js \
browser_248970_b_sample.html \
browser_339445.js \
Expand Down Expand Up @@ -73,7 +77,6 @@ MOCHITEST_BROWSER_FILES = \
browser_490040.js \
browser_491168.js \
browser_491577.js \
browser_493467.js \
browser_495495.js \
browser_500328.js \
browser_514751.js \
Expand Down
35 changes: 0 additions & 35 deletions browser/components/sessionstore/test/browser_493467.js

This file was deleted.

37 changes: 21 additions & 16 deletions browser/components/sessionstore/test/browser_819510_perwindowpb.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ function test_2() {

forceWriteState(function(state) {
is(state.windows.length, 1,
"sessionstore state: 1 windows in data being writted to disk");
"sessionstore state: 1 windows in data being written to disk");
is (state.selectedWindow, 1,
"Selected window is updated to match one of the saved windows");
is(state._closedWindows.length, 0,
"sessionstore state: no closed windows in data being writted to disk");
"sessionstore state: no closed windows in data being written to disk");
runNextTest();
});
});
Expand All @@ -114,20 +114,25 @@ function test_3() {
is(curState.selectedWindow, 4, "Last window opened is the one selected");

waitForWindowClose(normalWindow, function() {
forceWriteState(function(state) {
is(state.windows.length, 2,
"sessionstore state: 2 windows in data being writted to disk");
is(state.selectedWindow, 2,
"Selected window is updated to match one of the saved windows");
state.windows.forEach(function(win) {
is(!win.isPrivate, true, "Saved window is not private");
// Load another tab before checking the written state so that
// the list of restoring windows gets cleared. Otherwise the
// window we just closed would be marked as not closed.
waitForTabLoad(aWindow, "http://www.example.com/", function() {
forceWriteState(function(state) {
is(state.windows.length, 2,
"sessionstore state: 2 windows in data being written to disk");
is(state.selectedWindow, 2,
"Selected window is updated to match one of the saved windows");
state.windows.forEach(function(win) {
is(!win.isPrivate, true, "Saved window is not private");
});
is(state._closedWindows.length, 1,
"sessionstore state: 1 closed window in data being written to disk");
state._closedWindows.forEach(function(win) {
is(!win.isPrivate, true, "Closed window is not private");
});
runNextTest();
});
is(state._closedWindows.length, 1,
"sessionstore state: 1 closed window in data being writted to disk");
state._closedWindows.forEach(function(win) {
is(!win.isPrivate, true, "Closed window is not private");
});
runNextTest();
});
});
});
Expand Down Expand Up @@ -178,7 +183,7 @@ function testOnWindow(aIsPrivate, aCallback) {
function waitForTabLoad(aWin, aURL, aCallback) {
aWin.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
aWin.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
aCallback();
executeSoon(aCallback);
}, true);
aWin.gBrowser.selectedBrowser.loadURI(aURL);
}
Loading

0 comments on commit 78cfaae

Please sign in to comment.