--- a/browser/components/sessionstore/ContentRestore.jsm
+++ b/browser/components/sessionstore/ContentRestore.jsm
@@ -16,40 +16,16 @@ ChromeUtils.defineModuleGetter(this, "Se
"resource:///modules/sessionstore/SessionStorage.jsm");
ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/sessionstore/Utils.jsm");
const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
.getService(Ci.nsISessionStoreUtils);
/**
- * Restores frame tree |data|, starting at the given root |frame|. As the
- * function recurses into descendant frames it will call cb(frame, data) for
- * each frame it encounters, starting with the given root.
- */
-function restoreFrameTreeData(frame, data, cb) {
- // Restore data for the root frame.
- // The callback can abort by returning false.
- if (cb(frame, data) === false) {
- return;
- }
-
- if (!data.hasOwnProperty("children")) {
- return;
- }
-
- // Recurse into child frames.
- ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
- if (data.children[index]) {
- restoreFrameTreeData(subframe, data.children[index], cb);
- }
- });
-}
-
-/**
* This module implements the content side of session restoration. The chrome
* side is handled by SessionStore.jsm. The functions in this module are called
* by content-sessionStore.js based on messages received from SessionStore.jsm
* (or, in one case, based on a "load" event). Each tab has its own
* ContentRestore instance, constructed by content-sessionStore.js.
*
* In a typical restore, content-sessionStore.js will call the following based
* on messages and events it receives:
@@ -307,25 +283,25 @@ ContentRestoreInternal.prototype = {
return;
}
let {formdata, scrollPositions} = this._restoringDocument;
this._restoringDocument = null;
let window = this.docShell.domWindow;
// Restore form data.
- restoreFrameTreeData(window, formdata, (frame, data) => {
+ Utils.restoreFrameTreeData(window, formdata, (frame, data) => {
// restore() will return false, and thus abort restoration for the
// current |frame| and its descendants, if |data.url| is given but
// doesn't match the loaded document's URL.
return FormData.restore(frame, data);
});
// Restore scroll data.
- restoreFrameTreeData(window, scrollPositions, (frame, data) => {
+ Utils.restoreFrameTreeData(window, scrollPositions, (frame, data) => {
if (data.scroll) {
ssu.restoreScrollPosition(frame, data.scroll);
}
});
},
/**
* Cancel an ongoing restore. This function can be called any time between
--- a/mobile/android/chrome/geckoview/GeckoViewContent.js
+++ b/mobile/android/chrome/geckoview/GeckoViewContent.js
@@ -6,21 +6,23 @@
ChromeUtils.import("resource://gre/modules/GeckoViewContentModule.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
FormData: "resource://gre/modules/FormData.jsm",
FormLikeFactory: "resource://gre/modules/FormLikeFactory.jsm",
GeckoViewAutoFill: "resource://gre/modules/GeckoViewAutoFill.jsm",
PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.jsm",
- ScrollPosition: "resource://gre/modules/ScrollPosition.jsm",
Services: "resource://gre/modules/Services.jsm",
SessionHistory: "resource://gre/modules/sessionstore/SessionHistory.jsm",
});
+const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
+ .getService(Ci.nsISessionStoreUtils);
+
class GeckoViewContent extends GeckoViewContentModule {
onInit() {
debug `onInit`;
// We don't load this in the global namespace because
// a Utils.jsm in a11y will clobber us.
XPCOMUtils.defineLazyModuleGetters(this, {
Utils: "resource://gre/modules/sessionstore/Utils.jsm",
@@ -81,17 +83,17 @@ class GeckoViewContent extends GeckoView
removeEventListener("MozDOMFullscreen:Exit", this);
removeEventListener("MozDOMFullscreen:Exited", this);
removeEventListener("MozDOMFullscreen:Request", this);
removeEventListener("contextmenu", this, { capture: true });
}
collectSessionState() {
let history = SessionHistory.collect(docShell);
- let [formdata, scrolldata] = this.Utils.mapFrameTree(content, FormData.collect, ScrollPosition.collect);
+ let [formdata, scrolldata] = this.Utils.mapFrameTree(content, FormData.collect, ssu.collectScrollPosition.bind(ssu));
// Save the current document resolution.
let zoom = { value: 1 };
let domWindowUtils = content.windowUtils;
domWindowUtils.getResolution(zoom);
scrolldata = scrolldata || {};
scrolldata.zoom = {};
scrolldata.zoom.resolution = zoom.value;
@@ -196,24 +198,33 @@ class GeckoViewContent extends GeckoView
this._savedState = JSON.parse(aMsg.data.state);
if (this._savedState.history) {
let restoredHistory = SessionHistory.restore(docShell, this._savedState.history);
addEventListener("load", _ => {
const formdata = this._savedState.formdata;
if (formdata) {
- FormData.restoreTree(content, formdata);
+ this.Utils.restoreFrameTreeData(content, formdata, (frame, data) => {
+ // restore() will return false, and thus abort restoration for the
+ // current |frame| and its descendants, if |data.url| is given but
+ // doesn't match the loaded document's URL.
+ return FormData.restore(frame, data);
+ });
}
}, {capture: true, mozSystemGroup: true, once: true});
addEventListener("pageshow", _ => {
const scrolldata = this._savedState.scrolldata;
if (scrolldata) {
- ScrollPosition.restoreTree(content, scrolldata);
+ this.Utils.restoreFrameTreeData(content, scrolldata, (frame, data) => {
+ if (data.scroll) {
+ ssu.restoreScrollPosition(frame, data.scroll);
+ }
+ });
}
delete this._savedState;
}, {capture: true, mozSystemGroup: true, once: true});
if (!this.progressFilter) {
this.progressFilter =
Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
.createInstance(Ci.nsIWebProgress);
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -8,26 +8,28 @@ ChromeUtils.import("resource://gre/modul
ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetters(this, {
EventDispatcher: "resource://gre/modules/Messaging.jsm",
FormData: "resource://gre/modules/FormData.jsm",
OS: "resource://gre/modules/osfile.jsm",
PrivacyFilter: "resource://gre/modules/sessionstore/PrivacyFilter.jsm",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
- ScrollPosition: "resource://gre/modules/ScrollPosition.jsm",
SessionHistory: "resource://gre/modules/sessionstore/SessionHistory.jsm",
SharedPreferences: "resource://gre/modules/SharedPreferences.jsm",
Task: "resource://gre/modules/Task.jsm",
TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm",
Utils: "resource://gre/modules/sessionstore/Utils.jsm",
});
XPCOMUtils.defineLazyModuleGetter(this, "Log", "resource://gre/modules/AndroidLog.jsm", "AndroidLog");
+const ssu = Cc["@mozilla.org/browser/sessionstore/utils;1"]
+ .getService(Ci.nsISessionStoreUtils);
+
function dump(a) {
Services.console.logStringMessage(a);
}
let loggingEnabled = false;
function log(a) {
if (!loggingEnabled) {
@@ -927,17 +929,17 @@ SessionStore.prototype = {
// Neither bother if we're yet to restore the previous scroll position.
if (aBrowser.__SS_restoreDataOnLoad || aBrowser.__SS_restoreDataOnPageshow) {
return;
}
// Save the scroll position itself.
let content = aBrowser.contentWindow;
- let [scrolldata] = Utils.mapFrameTree(content, ScrollPosition.collect);
+ let [scrolldata] = Utils.mapFrameTree(content, ssu.collectScrollPosition.bind(ssu));
scrolldata = scrolldata || {};
// Save the current document resolution.
let zoom = { value: 1 };
content.windowUtils.getResolution(zoom);
scrolldata.zoom = {};
scrolldata.zoom.resolution = zoom.value;
log("onTabScroll() zoom level: " + zoom.value);
@@ -1379,17 +1381,22 @@ SessionStore.prototype = {
},
/**
* Takes serialized form text data and restores it into the given browser.
*/
_restoreTextData: function ss_restoreTextData(aFormData, aBrowser) {
if (aFormData) {
log("_restoreTextData()");
- FormData.restoreTree(aBrowser.contentWindow, aFormData);
+ Utils.restoreFrameTreeData(aBrowser.contentWindow, aFormData, (frame, data) => {
+ // restore() will return false, and thus abort restoration for the
+ // current |frame| and its descendants, if |data.url| is given but
+ // doesn't match the loaded document's URL.
+ return FormData.restore(frame, data);
+ });
}
},
/**
* Restores the zoom level of the window. This needs to be called before
* first paint/load (whichever comes first) to take any effect.
*/
_restoreZoom: function ss_restoreZoom(aScrollData, aBrowser) {
@@ -1406,17 +1413,21 @@ SessionStore.prototype = {
},
/**
* Takes serialized scroll positions and restores them into the given browser.
*/
_restoreScrollPosition: function ss_restoreScrollPosition(aScrollData, aBrowser) {
if (aScrollData) {
log("_restoreScrollPosition()");
- ScrollPosition.restoreTree(aBrowser.contentWindow, aScrollData);
+ Utils.restoreFrameTreeData(aBrowser.contentWindow, aScrollData, (frame, data) => {
+ if (data.scroll) {
+ ssu.restoreScrollPosition(frame, data.scroll);
+ }
+ });
}
},
getBrowserState: function ss_getBrowserState() {
return this._getCurrentState();
},
_restoreWindow: function ss_restoreWindow(aData) {
--- a/toolkit/modules/moz.build
+++ b/toolkit/modules/moz.build
@@ -236,17 +236,16 @@ EXTRA_JS_MODULES += [
'RemoteSecurityUI.jsm',
'RemoteWebProgress.jsm',
'ResetProfile.jsm',
'ResponsivenessMonitor.jsm',
'SelectParentHelper.jsm',
'ServiceRequest.jsm',
'Services.jsm',
'sessionstore/FormData.jsm',
- 'sessionstore/ScrollPosition.jsm',
'ShortcutUtils.jsm',
'Sqlite.jsm',
'Task.jsm',
'Timer.jsm',
'Troubleshoot.jsm',
'UpdateUtils.jsm',
'WebChannel.jsm',
'WebProgressChild.jsm',
deleted file mode 100644
--- a/toolkit/modules/sessionstore/ScrollPosition.jsm
+++ /dev/null
@@ -1,104 +0,0 @@
-/* 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/. */
-
-"use strict";
-
-var EXPORTED_SYMBOLS = ["ScrollPosition"];
-
-/**
- * It provides methods to collect scroll positions from single frames and to
- * restore scroll positions for frame trees.
- *
- * This is a child process module.
- */
-var ScrollPosition = Object.freeze({
- collect(frame) {
- return ScrollPositionInternal.collect(frame);
- },
-
- restore(frame, value) {
- ScrollPositionInternal.restore(frame, value);
- },
-
- restoreTree(root, data) {
- ScrollPositionInternal.restoreTree(root, data);
- },
-});
-
-/**
- * This module's internal API.
- */
-var ScrollPositionInternal = {
- /**
- * Collects scroll position data for any given |frame| in the frame hierarchy.
- *
- * @param frame (DOMWindow)
- *
- * @return {scroll: "x,y"} e.g. {scroll: "100,200"}
- * Returns null when there is no scroll data we want to store for the
- * given |frame|.
- */
- collect(frame) {
- let utils = frame.windowUtils;
- let scrollX = {}, scrollY = {};
- utils.getScrollXY(false /* no layout flush */, scrollX, scrollY);
-
- if (scrollX.value || scrollY.value) {
- return {scroll: scrollX.value + "," + scrollY.value};
- }
-
- return null;
- },
-
- /**
- * Restores scroll position data for any given |frame| in the frame hierarchy.
- *
- * @param frame (DOMWindow)
- * @param value (object, see collect())
- */
- restore(frame, value) {
- let match;
-
- if (value && (match = /(\d+),(\d+)/.exec(value))) {
- frame.scrollTo(match[1], match[2]);
- }
- },
-
- /**
- * Restores scroll position data for the current frame hierarchy starting at
- * |root| using the given scroll position |data|.
- *
- * If the given |root| frame's hierarchy doesn't match that of the given
- * |data| object we will silently discard data for unreachable frames. We
- * may as well assign scroll positions to the wrong frames if some were
- * reordered or removed.
- *
- * @param root (DOMWindow)
- * @param data (object)
- * {
- * scroll: "100,200",
- * children: [
- * {scroll: "100,200"},
- * null,
- * {scroll: "200,300", children: [ ... ]}
- * ]
- * }
- */
- restoreTree(root, data) {
- if (data.hasOwnProperty("scroll")) {
- this.restore(root, data.scroll);
- }
-
- if (!data.hasOwnProperty("children")) {
- return;
- }
-
- let frames = root.frames;
- data.children.forEach((child, index) => {
- if (child && index < frames.length) {
- this.restoreTree(frames[index], child);
- }
- });
- },
-};
--- a/toolkit/modules/sessionstore/Utils.jsm
+++ b/toolkit/modules/sessionstore/Utils.jsm
@@ -194,9 +194,33 @@ var Utils = Object.freeze({
if (!children[i].length) {
continue;
}
objs[i].children = children[i];
}
return objs.map((obj) => Object.getOwnPropertyNames(obj).length ? obj : null);
},
+
+ /**
+ * Restores frame tree |data|, starting at the given root |frame|. As the
+ * function recurses into descendant frames it will call cb(frame, data) for
+ * each frame it encounters, starting with the given root.
+ */
+ restoreFrameTreeData(frame, data, cb) {
+ // Restore data for the root frame.
+ // The callback can abort by returning false.
+ if (cb(frame, data) === false) {
+ return;
+ }
+
+ if (!data.hasOwnProperty("children")) {
+ return;
+ }
+
+ // Recurse into child frames.
+ ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
+ if (data.children[index]) {
+ this.restoreFrameTreeData(subframe, data.children[index], cb);
+ }
+ });
+ },
});