diff options
Diffstat (limited to 'browser/components/sessionstore/FrameTree.jsm')
-rw-r--r-- | browser/components/sessionstore/FrameTree.jsm | 254 |
1 files changed, 0 insertions, 254 deletions
diff --git a/browser/components/sessionstore/FrameTree.jsm b/browser/components/sessionstore/FrameTree.jsm deleted file mode 100644 index e8ed12a8f..000000000 --- a/browser/components/sessionstore/FrameTree.jsm +++ /dev/null @@ -1,254 +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"; - -this.EXPORTED_SYMBOLS = ["FrameTree"]; - -const Cu = Components.utils; -const Ci = Components.interfaces; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); - -const EXPORTED_METHODS = ["addObserver", "contains", "map", "forEach"]; - -/** - * A FrameTree represents all frames that were reachable when the document - * was loaded. We use this information to ignore frames when collecting - * sessionstore data as we can't currently restore anything for frames that - * have been created dynamically after or at the load event. - * - * @constructor - */ -function FrameTree(chromeGlobal) { - let internal = new FrameTreeInternal(chromeGlobal); - let external = {}; - - for (let method of EXPORTED_METHODS) { - external[method] = internal[method].bind(internal); - } - - return Object.freeze(external); -} - -/** - * The internal frame tree API that the public one points to. - * - * @constructor - */ -function FrameTreeInternal(chromeGlobal) { - // A WeakMap that uses frames (DOMWindows) as keys and their initial indices - // in their parents' child lists as values. Suppose we have a root frame with - // three subframes i.e. a page with three iframes. The WeakMap would have - // four entries and look as follows: - // - // root -> 0 - // subframe1 -> 0 - // subframe2 -> 1 - // subframe3 -> 2 - // - // Should one of the subframes disappear we will stop collecting data for it - // as |this._frames.has(frame) == false|. All other subframes will maintain - // their initial indices to ensure we can restore frame data appropriately. - this._frames = new WeakMap(); - - // The Set of observers that will be notified when the frame changes. - this._observers = new Set(); - - // The chrome global we use to retrieve the current DOMWindow. - this._chromeGlobal = chromeGlobal; - - // Register a web progress listener to be notified about new page loads. - let docShell = chromeGlobal.docShell; - let ifreq = docShell.QueryInterface(Ci.nsIInterfaceRequestor); - let webProgress = ifreq.getInterface(Ci.nsIWebProgress); - webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT); -} - -FrameTreeInternal.prototype = { - - // Returns the docShell's current global. - get content() { - return this._chromeGlobal.content; - }, - - /** - * Adds a given observer |obs| to the set of observers that will be notified - * when the frame tree is reset (when a new document starts loading) or - * recollected (when a document finishes loading). - * - * @param obs (object) - */ - addObserver: function (obs) { - this._observers.add(obs); - }, - - /** - * Notifies all observers that implement the given |method|. - * - * @param method (string) - */ - notifyObservers: function (method) { - for (let obs of this._observers) { - if (obs.hasOwnProperty(method)) { - obs[method](); - } - } - }, - - /** - * Checks whether a given |frame| is contained in the collected frame tree. - * If it is not, this indicates that we should not collect data for it. - * - * @param frame (nsIDOMWindow) - * @return bool - */ - contains: function (frame) { - return this._frames.has(frame); - }, - - /** - * Recursively applies the given function |cb| to the stored frame tree. Use - * this method to collect sessionstore data for all reachable frames stored - * in the frame tree. - * - * If a given function |cb| returns a value, it must be an object. It may - * however return "null" to indicate that there is no data to be stored for - * the given frame. - * - * The object returned by |cb| cannot have any property named "children" as - * that is used to store information about subframes in the tree returned - * by |map()| and might be overridden. - * - * @param cb (function) - * @return object - */ - map: function (cb) { - let frames = this._frames; - - function walk(frame) { - let obj = cb(frame) || {}; - - if (frames.has(frame)) { - let children = []; - - Array.forEach(frame.frames, subframe => { - // Don't collect any data if the frame is not contained in the - // initial frame tree. It's a dynamic frame added later. - if (!frames.has(subframe)) { - return; - } - - // Retrieve the frame's original position in its parent's child list. - let index = frames.get(subframe); - - // Recursively collect data for the current subframe. - let result = walk(subframe, cb); - if (result && Object.keys(result).length) { - children[index] = result; - } - }); - - if (children.length) { - obj.children = children; - } - } - - return Object.keys(obj).length ? obj : null; - } - - return walk(this.content); - }, - - /** - * Applies the given function |cb| to all frames stored in the tree. Use this - * method if |map()| doesn't suit your needs and you want more control over - * how data is collected. - * - * @param cb (function) - * This callback receives the current frame as the only argument. - */ - forEach: function (cb) { - let frames = this._frames; - - function walk(frame) { - cb(frame); - - if (!frames.has(frame)) { - return; - } - - Array.forEach(frame.frames, subframe => { - if (frames.has(subframe)) { - cb(subframe); - } - }); - } - - walk(this.content); - }, - - /** - * Stores a given |frame| and its children in the frame tree. - * - * @param frame (nsIDOMWindow) - * @param index (int) - * The index in the given frame's parent's child list. - */ - collect: function (frame, index = 0) { - // Mark the given frame as contained in the frame tree. - this._frames.set(frame, index); - - // Mark the given frame's subframes as contained in the tree. - Array.forEach(frame.frames, this.collect, this); - }, - - /** - * @see nsIWebProgressListener.onStateChange - * - * We want to be notified about: - * - new documents that start loading to clear the current frame tree; - * - completed document loads to recollect reachable frames. - */ - onStateChange: function (webProgress, request, stateFlags, status) { - // Ignore state changes for subframes because we're only interested in the - // top-document starting or stopping its load. We thus only care about any - // changes to the root of the frame tree, not to any of its nodes/leafs. - if (!webProgress.isTopLevel || webProgress.DOMWindow != this.content) { - return; - } - - // onStateChange will be fired when loading the initial about:blank URI for - // a browser, which we don't actually care about. This is particularly for - // the case of unrestored background tabs, where the content has not yet - // been restored: we don't want to accidentally send any updates to the - // parent when the about:blank placeholder page has loaded. - if (!this._chromeGlobal.docShell.hasLoadedNonBlankURI) { - return; - } - - if (stateFlags & Ci.nsIWebProgressListener.STATE_START) { - // Clear the list of frames until we can recollect it. - this._frames = new WeakMap(); - - // Notify observers that the frame tree has been reset. - this.notifyObservers("onFrameTreeReset"); - } else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) { - // The document and its resources have finished loading. - this.collect(webProgress.DOMWindow); - - // Notify observers that the frame tree has been reset. - this.notifyObservers("onFrameTreeCollected"); - } - }, - - // Unused nsIWebProgressListener methods. - onLocationChange: function () {}, - onProgressChange: function () {}, - onSecurityChange: function () {}, - onStatusChange: function () {}, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference]) -}; |