Bug 1456391 - Part 2: Add mapFrameTree to sessionstore's Utils.jsm. r=mikedeboer
authorJan Henning <jh+bugzilla@buttercookie.de>
Wed, 25 Apr 2018 22:04:56 +0200
changeset 472833 f7e91391e09ff508f807c548cd5f4555c7dbf69a
parent 472832 1877b11a8fb6e62e88bbc7cb31517a74fae8f6e9
child 472834 2f83ddb62a8cad47a45c766917a23f1a3d3bb2bd
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer
bugs1456391
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1456391 - Part 2: Add mapFrameTree to sessionstore's Utils.jsm. r=mikedeboer GeckoView has already started using a slightly modified version of mapFrameTree, and since ssu.forEachNonDynamicChildFrame() has vastly simplified the process of correctly using FormData/ScrollPosition.collect() for *all* (non-dynamic) child frames, we want to use mapFrameTree for Fennec's session store as well. Therefore, to avoid further duplication of code, we add a common version to the session store's Utils.jsm module. We base the code on the GeckoView implementation of mapFrameTree, which has gained the ability to use callback *arrays*, however we still use ssu.forEach- NonDynamicChildFrame() like Desktop currently does, instead of simply iterating over *all* frames. MozReview-Commit-ID: 3ilEgNSeCEv
toolkit/modules/sessionstore/Utils.jsm
--- a/toolkit/modules/sessionstore/Utils.jsm
+++ b/toolkit/modules/sessionstore/Utils.jsm
@@ -9,16 +9,19 @@ var EXPORTED_SYMBOLS = ["Utils"];
 ChromeUtils.import("resource://gre/modules/Services.jsm", this);
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this);
 
 ChromeUtils.defineModuleGetter(this, "NetUtil",
                                "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
                                    "@mozilla.org/network/serialization-helper;1",
                                    "nsISerializationHelper");
+XPCOMUtils.defineLazyServiceGetter(this, "ssu",
+                                   "@mozilla.org/browser/sessionstore/utils;1",
+                                   "nsISessionStoreUtils");
 XPCOMUtils.defineLazyGetter(this, "SERIALIZED_SYSTEMPRINCIPAL", function() {
   return Utils.serializePrincipal(Services.scriptSecurityManager.getSystemPrincipal());
 });
 
 function debug(msg) {
   Services.console.logStringMessage("Utils: " + msg);
 }
 
@@ -142,10 +145,56 @@ var Utils = Object.freeze({
     try {
       let principal = serializationHelper.deserializeObject(principal_b64);
       principal.QueryInterface(Ci.nsIPrincipal);
       return principal;
     } catch (e) {
       debug(`Failed to deserialize principal_b64 '${principal_b64}' ${e}`);
     }
     return null;
+  },
+
+  /**
+   * A function that will recursively call |cb| to collect data for all
+   * non-dynamic frames in the current frame/docShell tree.
+   *
+   * @param {mozIDOMWindowProxy} frame A DOM window or content frame for which
+   *                                   data will be collected.
+   * @param {...function} dataCollectors One or more data collection functions
+   *                                     that will be called once for each non-
+   *                                     dynamic frame in the given frame tree,
+   *                                     and which should return the data they
+   *                                     wish to save for that respective frame.
+   * @return {object[]} An array with one entry per dataCollector, containing
+   *                    the collected data as a nested data structure according
+   *                    to the layout of the frame tree, or null if no data was
+   *                    returned by the respective dataCollector.
+   */
+  mapFrameTree(frame, ...dataCollectors) {
+    // Collect data for the current frame.
+    let objs = dataCollectors.map((dataCollector) => dataCollector(frame) || {});
+    let children = dataCollectors.map(() => []);
+
+    // Recurse into child frames.
+    ssu.forEachNonDynamicChildFrame(frame, (subframe, index) => {
+      let results = this.mapFrameTree(subframe, ...dataCollectors);
+      if (!results) {
+        return;
+      }
+
+      for (let j = results.length - 1; j >= 0; --j) {
+        if (!results[j] || !Object.getOwnPropertyNames(results[j]).length) {
+          continue;
+        }
+        children[j][index] = results[j];
+      }
+    });
+
+    for (let i = objs.length - 1; i >= 0; --i) {
+      if (!children[i].length) {
+        continue;
+      }
+      objs[i].children = children[i];
+    }
+
+    return objs.map((obj) => Object.getOwnPropertyNames(obj).length ? obj : null);
   }
 });