1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /*
8  * container for information saved in session history when the document
9  * is not
10  */
11 
12 #include "nsILayoutHistoryState.h"
13 #include "nsWeakReference.h"
14 #include "nsClassHashtable.h"
15 #include "nsPresState.h"
16 #include "mozilla/Attributes.h"
17 
18 class nsLayoutHistoryState final : public nsILayoutHistoryState,
19                                    public nsSupportsWeakReference {
20  public:
nsLayoutHistoryState()21   nsLayoutHistoryState() : mScrollPositionOnly(false) {}
22 
23   NS_DECL_ISUPPORTS
24   NS_DECL_NSILAYOUTHISTORYSTATE
25 
26  private:
~nsLayoutHistoryState()27   ~nsLayoutHistoryState() {}
28   bool mScrollPositionOnly;
29 
30   nsClassHashtable<nsCStringHashKey, nsPresState> mStates;
31 };
32 
NS_NewLayoutHistoryState()33 already_AddRefed<nsILayoutHistoryState> NS_NewLayoutHistoryState() {
34   RefPtr<nsLayoutHistoryState> state = new nsLayoutHistoryState();
35   return state.forget();
36 }
37 
NS_IMPL_ISUPPORTS(nsLayoutHistoryState,nsILayoutHistoryState,nsISupportsWeakReference)38 NS_IMPL_ISUPPORTS(nsLayoutHistoryState, nsILayoutHistoryState,
39                   nsISupportsWeakReference)
40 
41 NS_IMETHODIMP
42 nsLayoutHistoryState::GetHasStates(bool* aHasStates) {
43   *aHasStates = HasStates();
44   return NS_OK;
45 }
46 
47 NS_IMETHODIMP
GetKeys(uint32_t * aCount,char *** aKeys)48 nsLayoutHistoryState::GetKeys(uint32_t* aCount, char*** aKeys) {
49   if (!HasStates()) {
50     return NS_ERROR_FAILURE;
51   }
52 
53   char** keys =
54       static_cast<char**>(moz_xmalloc(sizeof(char*) * mStates.Count()));
55   *aCount = mStates.Count();
56   *aKeys = keys;
57 
58   for (auto iter = mStates.Iter(); !iter.Done(); iter.Next()) {
59     *keys = ToNewCString(iter.Key());
60     keys++;
61   }
62 
63   return NS_OK;
64 }
65 
66 NS_IMETHODIMP
GetPresState(const nsACString & aKey,float * aScrollX,float * aScrollY,bool * aAllowScrollOriginDowngrade,float * aRes,bool * aScaleToRes)67 nsLayoutHistoryState::GetPresState(const nsACString& aKey, float* aScrollX,
68                                    float* aScrollY,
69                                    bool* aAllowScrollOriginDowngrade,
70                                    float* aRes, bool* aScaleToRes) {
71   nsPresState* state = GetState(nsCString(aKey));
72 
73   if (!state) {
74     return NS_ERROR_FAILURE;
75   }
76 
77   *aScrollX = state->GetScrollPosition().x;
78   *aScrollY = state->GetScrollPosition().y;
79   *aAllowScrollOriginDowngrade = state->GetAllowScrollOriginDowngrade();
80   *aRes = state->GetResolution();
81   *aScaleToRes = state->GetScaleToResolution();
82 
83   return NS_OK;
84 }
85 
86 NS_IMETHODIMP
AddNewPresState(const nsACString & aKey,float aScrollX,float aScrollY,bool aAllowScrollOriginDowngrade,float aRes,bool aScaleToRes)87 nsLayoutHistoryState::AddNewPresState(const nsACString& aKey, float aScrollX,
88                                       float aScrollY,
89                                       bool aAllowScrollOriginDowngrade,
90                                       float aRes, bool aScaleToRes) {
91   nsPresState* newState = new nsPresState();
92   newState->SetScrollState(nsPoint(aScrollX, aScrollY));
93   newState->SetAllowScrollOriginDowngrade(aAllowScrollOriginDowngrade);
94   newState->SetResolution(aRes);
95   newState->SetScaleToResolution(aScaleToRes);
96 
97   mStates.Put(nsCString(aKey), newState);
98 
99   return NS_OK;
100 }
101 
AddState(const nsCString & aStateKey,nsPresState * aState)102 void nsLayoutHistoryState::AddState(const nsCString& aStateKey,
103                                     nsPresState* aState) {
104   mStates.Put(aStateKey, aState);
105 }
106 
GetState(const nsCString & aKey)107 nsPresState* nsLayoutHistoryState::GetState(const nsCString& aKey) {
108   nsPresState* state = nullptr;
109   bool entryExists = mStates.Get(aKey, &state);
110 
111   if (entryExists && mScrollPositionOnly) {
112     // Ensure any state that shouldn't be restored is removed
113     state->ClearNonScrollState();
114   }
115 
116   return state;
117 }
118 
RemoveState(const nsCString & aKey)119 void nsLayoutHistoryState::RemoveState(const nsCString& aKey) {
120   mStates.Remove(aKey);
121 }
122 
HasStates()123 bool nsLayoutHistoryState::HasStates() { return mStates.Count() != 0; }
124 
SetScrollPositionOnly(const bool aFlag)125 void nsLayoutHistoryState::SetScrollPositionOnly(const bool aFlag) {
126   mScrollPositionOnly = aFlag;
127 }
128 
ResetScrollState()129 void nsLayoutHistoryState::ResetScrollState() {
130   for (auto iter = mStates.Iter(); !iter.Done(); iter.Next()) {
131     nsPresState* state = iter.UserData();
132     if (state) {
133       state->SetScrollState(nsPoint(0, 0));
134     }
135   }
136 }
137