Bug 1456391 - Part 2: Add mapFrameTree to sessionstore's Utils.jsm. r?mikedeboer draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Wed, 25 Apr 2018 22:04:56 +0200
changeset 790279 73d50b41543f7ed9cf9287939eb6dcf0c28c30e6
parent 789935 278ac46959e918e3f26194a04776d6a218f15f5b
child 790280 8606c20b9bace9ca42df7e99d230c2bbb3025ee5
push id108477
push usermozilla@buttercookie.de
push dateTue, 01 May 2018 20:41:38 +0000
reviewersmikedeboer
bugs1456391
milestone61.0a1
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);
   }
 });