Bug 1265818 - Part 3 - Store and restore the LayoutHistoryState through SessionHistoy.jsm. r?mikedeboer draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Sat, 25 Mar 2017 15:32:36 +0100
changeset 551933 501376b6c9e1ff448281d5abd6121ce30345efd5
parent 551932 becc69be73a8f27d56a4f38639f6222142bb141c
child 551934 046a8a18ff691accaa53d3aa29499576263747c8
push id51203
push usermozilla@buttercookie.de
push dateMon, 27 Mar 2017 18:36:19 +0000
reviewersmikedeboer
bugs1265818
milestone55.0a1
Bug 1265818 - Part 3 - Store and restore the LayoutHistoryState through SessionHistoy.jsm. r?mikedeboer Since a LayoutHistoryState is basically just a collection of PresStates, we just save each PresState we can find and then later restore it. MozReview-Commit-ID: A6WpdelseHn
browser/components/sessionstore/content/content-sessionStore.js
toolkit/modules/sessionstore/SessionHistory.jsm
--- a/browser/components/sessionstore/content/content-sessionStore.js
+++ b/browser/components/sessionstore/content/content-sessionStore.js
@@ -321,30 +321,34 @@ var SessionHistoryListener = {
     this.collect();
   },
 
   onFrameTreeReset() {
     this.collect();
   },
 
   OnHistoryNewEntry(newURI, oldIndex) {
+    // We ought to collect the previously current entry as well, see bug 1350567.
     this.collectFrom(oldIndex);
   },
 
   OnHistoryGoBack(backURI) {
+    // We ought to collect the previously current entry as well, see bug 1350567.
     this.collectFrom(kLastIndex);
     return true;
   },
 
   OnHistoryGoForward(forwardURI) {
+    // We ought to collect the previously current entry as well, see bug 1350567.
     this.collectFrom(kLastIndex);
     return true;
   },
 
   OnHistoryGotoIndex(index, gotoURI) {
+    // We ought to collect the previously current entry as well, see bug 1350567.
     this.collectFrom(kLastIndex);
     return true;
   },
 
   OnHistoryPurge(numEntries) {
     this.collect();
     return true;
   },
--- a/toolkit/modules/sessionstore/SessionHistory.jsm
+++ b/toolkit/modules/sessionstore/SessionHistory.jsm
@@ -196,18 +196,31 @@ var SessionHistoryInternal = {
     if (shEntry.contentType)
       entry.contentType = shEntry.contentType;
 
     if (shEntry.scrollRestorationIsManual) {
       entry.scrollRestorationIsManual = true;
     } else {
       let x = {}, y = {};
       shEntry.getScrollPosition(x, y);
-      if (x.value != 0 || y.value != 0)
+      if (x.value !== 0 || y.value !== 0) {
         entry.scroll = x.value + "," + y.value;
+      }
+
+      let layoutHistoryState = shEntry.layoutHistoryState;
+      if (layoutHistoryState && layoutHistoryState.hasStates) {
+        let presStates = layoutHistoryState.getKeys().map(key =>
+          this._getSerializablePresState(layoutHistoryState, key)).filter(presState =>
+            // Only keep presState entries that contain more than the key itself.
+            Object.getOwnPropertyNames(presState).length > 1);
+
+        if (presStates.length > 0) {
+          entry.presState = presStates;
+        }
+      }
     }
 
     // Collect triggeringPrincipal data for the current history entry.
     if (shEntry.principalToInherit) {
       try {
         let principalToInherit = Utils.serializePrincipal(shEntry.principalToInherit);
         if (principalToInherit) {
           entry.principalToInherit_base64 = principalToInherit;
@@ -260,16 +273,46 @@ var SessionHistoryInternal = {
         entry.children = children;
       }
     }
 
     return entry;
   },
 
   /**
+   * Get an object that is a serializable representation of a PresState.
+   *
+   * @param layoutHistoryState
+   *        nsILayoutHistoryState instance
+   * @param stateKey
+   *        The state key of the presState to be retrieved.
+   * @return object
+   */
+  _getSerializablePresState(layoutHistoryState, stateKey) {
+    let presState = { stateKey };
+    let x = {}, y = {}, scrollOriginDowngrade = {}, res = {}, scaleToRes = {};
+
+    layoutHistoryState.getPresState(stateKey, x, y, scrollOriginDowngrade, res, scaleToRes);
+    if (x.value !== 0 || y.value !== 0) {
+      presState.scroll = x.value + "," + y.value;
+    }
+    if (scrollOriginDowngrade.value === false) {
+      presState.scrollOriginDowngrade = scrollOriginDowngrade.value;
+    }
+    if (res.value != 1.0) {
+      presState.res = res.value;
+    }
+    if (scaleToRes.value === true) {
+      presState.scaleToRes = scaleToRes.value;
+    }
+
+    return presState;
+  },
+
+  /**
    * Restores session history data for a given docShell.
    *
    * @param docShell
    *        The docShell that owns the session history.
    * @param tabData
    *        The tabdata including all history entries.
    * @return A reference to the docShell's nsISHistoryInternal interface.
    */
@@ -380,20 +423,28 @@ var SessionHistoryInternal = {
         createInstance(Ci.nsIStructuredCloneContainer);
 
       shEntry.stateData.initFromBase64(entry.structuredCloneState,
                                        entry.structuredCloneVersion);
     }
 
     if (entry.scrollRestorationIsManual) {
       shEntry.scrollRestorationIsManual = true;
-    } else if (entry.scroll) {
-      var scrollPos = (entry.scroll || "0,0").split(",");
-      scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
-      shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
+    } else {
+      if (entry.scroll) {
+        shEntry.setScrollPosition(...this._deserializeScrollPosition(entry.scroll));
+      }
+
+      if (entry.presState) {
+        let layoutHistoryState = shEntry.initLayoutHistoryState();
+
+        for (let presState of entry.presState) {
+          this._deserializePresState(layoutHistoryState, presState);
+        }
+      }
     }
 
     let childDocIdents = {};
     if (entry.docIdentifier) {
       // If we have a serialized document identifier, try to find an SHEntry
       // which matches that doc identifier and adopt that SHEntry's
       // BFCacheEntry.  If we don't find a match, insert shEntry as the match
       // for the document identifier.
@@ -438,9 +489,40 @@ var SessionHistoryInternal = {
         shEntry.AddChild(this.deserializeEntry(entry.children[i], idMap,
                                                childDocIdents), i);
       }
     }
 
     return shEntry;
   },
 
+  /**
+   * Expands serialized PresState data and adds it to the given nsILayoutHistoryState.
+   *
+   * @param layoutHistoryState
+   *        nsILayoutHistoryState instance
+   * @param presState
+   *        Object containing serialized PresState data.
+   */
+  _deserializePresState(layoutHistoryState, presState) {
+    let stateKey = presState.stateKey;
+    let scrollOriginDowngrade =
+      typeof presState.scrollOriginDowngrade == "boolean" ? presState.scrollOriginDowngrade : true;
+    let res = presState.res || 1.0;
+    let scaleToRes = presState.scaleToRes || false;
+
+    layoutHistoryState.addNewPresState(stateKey, ...this._deserializeScrollPosition(presState.scroll),
+                                       scrollOriginDowngrade, res, scaleToRes);
+  },
+
+  /**
+   * Expands serialized scroll position data into an array containing the x and y coordinates,
+   * defaulting to 0,0 if no scroll position was found.
+   *
+   * @param scroll
+   *        Object containing serialized scroll position data.
+   * @return An array containing the scroll position's x and y coordinates.
+   */
+  _deserializeScrollPosition(scroll = "0,0") {
+    return scroll.split(",").map(pos => parseInt(pos, 10) || 0);
+  },
+
 };