Bug 1265818 - Part 2 - Add scriptable methods for getting and setting PresStates from JS. r?jst draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Sat, 25 Mar 2017 14:01:29 +0100
changeset 551932 becc69be73a8f27d56a4f38639f6222142bb141c
parent 551931 fe1ec34d6391fdff1c9a836cb94ce0c8d5cfdd48
child 551933 501376b6c9e1ff448281d5abd6121ce30345efd5
push id51203
push usermozilla@buttercookie.de
push dateMon, 27 Mar 2017 18:36:19 +0000
reviewersjst
bugs1265818
milestone55.0a1
Bug 1265818 - Part 2 - Add scriptable methods for getting and setting PresStates from JS. r?jst This will allow the session store to store and restore scroll positions (and pinch zoom on Android) for past session history entries as well, whereas today only the scroll position of the current page is saved. As a LayoutHistoryState saves its PresStates in a hash table that doesn't allow direct access to its contents if you don't already know the entry's key, we provide a function to iterate over all stored PresStates and retrieve their keys, which can then be used to get access to each individual PresState in turn. Since nsPresState is little more than a fancy struct and we don't want to have to turn it into a full-blown XPCOM-compatible interface, we just pass the scroll/zoom-related values we're interested in as in/out parameters from/to JS via the LayoutHistoryState. We also require a helper method for initialising an SHEntry's LayoutHistoryState, since normally this doesn't happen until the PresShell wants to capture the history state in it. We on the other hand require a LayoutHistoryState to be present immediately after creation of a fresh SHEntry object, so we can feed it the session store data during history restoration. MozReview-Commit-ID: FfZf8KDsVWl ***
docshell/shistory/nsISHEntry.idl
docshell/shistory/nsSHEntry.cpp
layout/base/nsILayoutHistoryState.idl
layout/base/nsLayoutHistoryState.cpp
--- a/docshell/shistory/nsISHEntry.idl
+++ b/docshell/shistory/nsISHEntry.idl
@@ -134,16 +134,22 @@ interface nsISHEntry : nsISupports
     void setTitle(in AString aTitle);
 
     /** Post Data for the document */
     attribute nsIInputStream postData;
 
     /** LayoutHistoryState for scroll position and form values */
     attribute nsILayoutHistoryState layoutHistoryState;
 
+    /**
+     * Initialises the LayoutHistoryState if it doesn't already exist
+     * and returns a reference to it.
+     */
+    nsILayoutHistoryState initLayoutHistoryState();
+
     /** parent of this entry */
     attribute nsISHEntry parent;
 
     /**
      * The loadType for this entry. This is typically loadHistory except
      * when reload is pressed, it has the appropriate reload flag
      */
     attribute unsigned long loadType;
--- a/docshell/shistory/nsSHEntry.cpp
+++ b/docshell/shistory/nsSHEntry.cpp
@@ -288,16 +288,29 @@ nsSHEntry::SetLayoutHistoryState(nsILayo
     mShared->mLayoutHistoryState->SetScrollPositionOnly(
       !mShared->mSaveLayoutState);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsSHEntry::InitLayoutHistoryState(nsILayoutHistoryState** aState)
+{
+  if (!mShared->mLayoutHistoryState) {
+    nsCOMPtr<nsILayoutHistoryState> historyState;
+    historyState = NS_NewLayoutHistoryState();
+    nsresult rv = SetLayoutHistoryState(historyState);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return GetLayoutHistoryState(aState);
+}
+
+NS_IMETHODIMP
 nsSHEntry::GetLoadType(uint32_t* aResult)
 {
   *aResult = mLoadType;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHEntry::SetLoadType(uint32_t aLoadType)
--- a/layout/base/nsILayoutHistoryState.idl
+++ b/layout/base/nsILayoutHistoryState.idl
@@ -17,19 +17,49 @@ interface nsPresState;
 native constBool(const bool);
 
 %{C++
 #include "nsStringFwd.h"
 
 template<typename> struct already_AddRefed;
 %}
 
-[uuid(aef27cb3-4df9-4eeb-b0b0-ac56cf861d04)]
+[scriptable, uuid(aef27cb3-4df9-4eeb-b0b0-ac56cf861d04)]
 interface nsILayoutHistoryState : nsISupports
 {
+  /**
+  * Whether this LayoutHistoryState contains any PresStates.
+  */
+  readonly attribute boolean hasStates;
+
+  /**
+  * Get the keys of all PresStates held by this LayoutHistoryState.
+  * Note: Check hasStates first.
+  */
+  void getKeys([optional] out uint32_t aCount,
+               [array, size_is(aCount), retval] out string aKeys);
+
+  /*
+  * Attempts to get the data of the PresState corresponding to
+  * the passed key. Throws if no data could be found.
+  */
+  void getPresState(in ACString aKey,
+                    out float aScrollX, out float aScrollY,
+                    out boolean aAllowScrollOriginDowngrade,
+                    out float aRes, out boolean aScaleToRes);
+
+  /**
+   * Constructs a new nsPresState object based on the supplied data
+   * and adds it to the LayoutHistoryState.
+   */
+  void addNewPresState(in ACString aKey,
+                   in float aScrollX, in float aScrollY,
+                   in boolean aAllowScrollOriginDowngrade,
+                   in float aRes, in boolean aScaleToRes);
+
   // Native only interface, converted from the original nsILayoutHistoryState.h
 
   /**
    * Set |aState| as the state object for |aKey|.
    * This _transfers_ownership_ of |aState| to the LayoutHistoryState.
    * It will be freed when RemoveState() is called or when the
    * LayoutHistoryState is destroyed.
    */
--- a/layout/base/nsLayoutHistoryState.cpp
+++ b/layout/base/nsLayoutHistoryState.cpp
@@ -40,16 +40,81 @@ NS_NewLayoutHistoryState()
   RefPtr<nsLayoutHistoryState> state = new nsLayoutHistoryState();
   return state.forget();
 }
 
 NS_IMPL_ISUPPORTS(nsLayoutHistoryState,
                   nsILayoutHistoryState,
                   nsISupportsWeakReference)
 
+NS_IMETHODIMP
+nsLayoutHistoryState::GetHasStates(bool* aHasStates)
+{
+  *aHasStates = HasStates();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLayoutHistoryState::GetKeys(uint32_t* aCount, char*** aKeys)
+{
+  if (!HasStates()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  char** keys =
+    static_cast<char**>(moz_xmalloc(sizeof(char*) * mStates.Count()));
+  *aCount = mStates.Count();
+  *aKeys = keys;
+
+  for (auto iter = mStates.Iter(); !iter.Done(); iter.Next()) {
+    *keys = ToNewCString(iter.Key());
+    keys++;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLayoutHistoryState::GetPresState(const nsACString& aKey,
+                                   float* aScrollX, float* aScrollY,
+                                   bool* aAllowScrollOriginDowngrade,
+                                   float* aRes, bool* aScaleToRes)
+{
+  nsPresState* state = GetState(nsCString(aKey));
+
+  if (!state) {
+    return NS_ERROR_FAILURE;
+  }
+
+  *aScrollX = state->GetScrollPosition().x;
+  *aScrollY = state->GetScrollPosition().y;
+  *aAllowScrollOriginDowngrade = state->GetAllowScrollOriginDowngrade();
+  *aRes = state->GetResolution();
+  *aScaleToRes = state->GetScaleToResolution();
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsLayoutHistoryState::AddNewPresState(const nsACString& aKey,
+                                      float aScrollX, float aScrollY,
+                                      bool aAllowScrollOriginDowngrade,
+                                      float aRes, bool aScaleToRes)
+{
+  nsPresState* newState = new nsPresState();
+  newState->SetScrollState(nsPoint(aScrollX, aScrollY));
+  newState->SetAllowScrollOriginDowngrade(aAllowScrollOriginDowngrade);
+  newState->SetResolution(aRes);
+  newState->SetScaleToResolution(aScaleToRes);
+
+  mStates.Put(nsCString(aKey), newState);
+
+  return NS_OK;
+}
+
 void
 nsLayoutHistoryState::AddState(const nsCString& aStateKey, nsPresState* aState)
 {
   mStates.Put(aStateKey, aState);
 }
 
 nsPresState*
 nsLayoutHistoryState::GetState(const nsCString& aKey)