Line data Source code
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 : #include "GroupedSHistory.h"
8 :
9 : #include "mozilla/dom/Promise.h"
10 : #include "TabParent.h"
11 : #include "PartialSHistory.h"
12 :
13 : namespace mozilla {
14 : namespace dom {
15 :
16 : NS_IMPL_CYCLE_COLLECTION_CLASS(GroupedSHistory)
17 :
18 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(GroupedSHistory)
19 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mPartialHistories)
20 0 : tmp->mPrerenderingHistories.Clear();
21 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
22 :
23 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(GroupedSHistory)
24 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPartialHistories)
25 0 : for (GroupedSHistory::PrerenderingHistory& h : tmp->mPrerenderingHistories) {
26 0 : ImplCycleCollectionTraverse(cb, h.mPartialHistory, "mPrerenderingHistories[i]->mPartialHistory", 0);
27 : }
28 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
29 :
30 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(GroupedSHistory)
31 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(GroupedSHistory)
32 :
33 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GroupedSHistory)
34 0 : NS_INTERFACE_MAP_ENTRY(nsIGroupedSHistory)
35 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIGroupedSHistory)
36 0 : NS_INTERFACE_MAP_END
37 :
38 0 : GroupedSHistory::GroupedSHistory()
39 : : mCount(0),
40 0 : mIndexOfActivePartialHistory(-1)
41 : {
42 0 : }
43 :
44 : NS_IMETHODIMP
45 0 : GroupedSHistory::GetCount(uint32_t* aResult)
46 : {
47 0 : MOZ_ASSERT(aResult);
48 0 : *aResult = mCount;
49 0 : return NS_OK;
50 : }
51 :
52 : NS_IMETHODIMP
53 0 : GroupedSHistory::AppendPartialSHistory(nsIPartialSHistory* aPartialHistory)
54 : {
55 0 : if (!aPartialHistory) {
56 0 : return NS_ERROR_INVALID_POINTER;
57 : }
58 :
59 0 : nsCOMPtr<nsIPartialSHistory> partialHistory(aPartialHistory);
60 0 : if (!partialHistory || mPartialHistories.Contains(partialHistory)) {
61 0 : return NS_ERROR_FAILURE;
62 : }
63 :
64 : // Remove all items after active one and deactive it, unless it's the first
65 : // call and no active partial history has been set yet.
66 0 : if (mIndexOfActivePartialHistory >= 0) {
67 0 : PurgePartialHistories(mIndexOfActivePartialHistory);
68 : nsCOMPtr<nsIPartialSHistory> prevPartialHistory =
69 0 : mPartialHistories[mIndexOfActivePartialHistory];
70 0 : if (NS_WARN_IF(!prevPartialHistory)) {
71 : // Cycle collected?
72 0 : return NS_ERROR_UNEXPECTED;
73 : }
74 0 : prevPartialHistory->OnDeactive();
75 : }
76 :
77 : // Attach the partial history.
78 0 : uint32_t offset = mCount;
79 0 : mCount += partialHistory->GetCount();
80 0 : mPartialHistories.AppendElement(partialHistory);
81 0 : partialHistory->OnAttachGroupedSHistory(this, offset);
82 0 : mIndexOfActivePartialHistory = mPartialHistories.Count() - 1;
83 :
84 : // Remove the prerendered documents, as there was a history navigation
85 0 : PurgePrerendering();
86 :
87 0 : return NS_OK;
88 : }
89 :
90 : NS_IMETHODIMP
91 0 : GroupedSHistory::HandleSHistoryUpdate(nsIPartialSHistory* aPartial, bool aTruncate)
92 : {
93 0 : if (!aPartial) {
94 0 : return NS_ERROR_INVALID_POINTER;
95 : }
96 0 : nsCOMPtr<nsIPartialSHistory> partialHistory = aPartial;
97 :
98 0 : int32_t index = partialHistory->GetGlobalIndex();
99 : // Get the lower and upper bounds for the viewer window
100 0 : int32_t lower = index - nsISHistory::VIEWER_WINDOW;
101 0 : int32_t upper = index + nsISHistory::VIEWER_WINDOW;
102 0 : for (uint32_t i = 0; i < mPartialHistories.Length(); ++i) {
103 0 : nsIPartialSHistory* pHistory = mPartialHistories[i];
104 : // Skip the active partial history.
105 0 : if (pHistory == partialHistory) {
106 0 : continue;
107 : }
108 :
109 : // Check if the given partialshistory entry is too far away in history, and
110 : // if it is, close it.
111 0 : int32_t thisCount = pHistory->GetCount();
112 0 : int32_t thisOffset = pHistory->GetGlobalIndexOffset();
113 0 : if ((thisOffset > upper) || ((thisCount + thisOffset) < lower)) {
114 0 : nsCOMPtr<nsIFrameLoader> loader;
115 0 : pHistory->GetOwnerFrameLoader(getter_AddRefs(loader));
116 0 : if (loader && !loader->GetIsDead()) {
117 0 : loader->RequestFrameLoaderClose();
118 : }
119 : }
120 : }
121 :
122 : // Remove the prerendered documents, as there was a history navigation
123 0 : PurgePrerendering();
124 :
125 : // If we should be truncating, make sure to purge any partialSHistories which
126 : // follow the one being updated.
127 0 : if (aTruncate) {
128 0 : int32_t index = mPartialHistories.IndexOf(partialHistory);
129 0 : if (NS_WARN_IF(index != mIndexOfActivePartialHistory) ||
130 0 : NS_WARN_IF(index < 0)) {
131 : // Non-active or not attached partialHistory
132 0 : return NS_ERROR_UNEXPECTED;
133 : }
134 :
135 0 : PurgePartialHistories(index);
136 :
137 : // Update global count.
138 0 : uint32_t count = partialHistory->GetCount();
139 0 : uint32_t offset = partialHistory->GetGlobalIndexOffset();
140 0 : mCount = count + offset;
141 : }
142 :
143 0 : return NS_OK;
144 : }
145 :
146 : NS_IMETHODIMP
147 0 : GroupedSHistory::GotoIndex(uint32_t aGlobalIndex,
148 : nsIFrameLoader** aTargetLoaderToSwap)
149 : {
150 0 : MOZ_ASSERT(aTargetLoaderToSwap);
151 0 : *aTargetLoaderToSwap = nullptr;
152 :
153 : nsCOMPtr<nsIPartialSHistory> currentPartialHistory =
154 0 : mPartialHistories[mIndexOfActivePartialHistory];
155 0 : if (!currentPartialHistory) {
156 : // Cycle collected?
157 0 : return NS_ERROR_UNEXPECTED;
158 : }
159 :
160 0 : for (uint32_t i = 0; i < mPartialHistories.Length(); i++) {
161 0 : nsCOMPtr<nsIPartialSHistory> partialHistory = mPartialHistories[i];
162 0 : if (NS_WARN_IF(!partialHistory)) {
163 : // Cycle collected?
164 0 : return NS_ERROR_UNEXPECTED;
165 : }
166 :
167 : // Examine index range.
168 0 : uint32_t offset = partialHistory->GetGlobalIndexOffset();
169 0 : uint32_t count = partialHistory->GetCount();
170 0 : if (offset <= aGlobalIndex && (offset + count) > aGlobalIndex) {
171 0 : uint32_t targetIndex = aGlobalIndex - offset;
172 :
173 : // Check if we are trying to swap to a dead frameloader, and return
174 : // NS_ERROR_NOT_AVAILABLE if we are.
175 0 : nsCOMPtr<nsIFrameLoader> frameLoader;
176 0 : partialHistory->GetOwnerFrameLoader(getter_AddRefs(frameLoader));
177 0 : if (!frameLoader || frameLoader->GetIsDead()) {
178 0 : return NS_ERROR_NOT_AVAILABLE;
179 : }
180 :
181 0 : if ((size_t)mIndexOfActivePartialHistory == i) {
182 0 : return NS_OK;
183 : }
184 0 : mIndexOfActivePartialHistory = i;
185 0 : if (NS_FAILED(currentPartialHistory->OnDeactive()) ||
186 0 : NS_FAILED(partialHistory->OnActive(mCount, targetIndex))) {
187 0 : return NS_ERROR_FAILURE;
188 : }
189 :
190 : // Return the target frameloader to the caller.
191 0 : frameLoader.forget(aTargetLoaderToSwap);
192 0 : return NS_OK;
193 : }
194 : }
195 :
196 : // Index not found.
197 0 : NS_WARNING("Out of index request!");
198 0 : return NS_ERROR_FAILURE;
199 : }
200 :
201 : void
202 0 : GroupedSHistory::PurgePartialHistories(uint32_t aLastPartialIndexToKeep)
203 : {
204 0 : uint32_t lastIndex = mPartialHistories.Length() - 1;
205 0 : if (aLastPartialIndexToKeep >= lastIndex) {
206 : // Nothing to remove.
207 0 : return;
208 : }
209 :
210 : // Close tabs.
211 0 : for (uint32_t i = lastIndex; i > aLastPartialIndexToKeep; i--) {
212 0 : nsCOMPtr<nsIPartialSHistory> partialHistory = mPartialHistories[i];
213 0 : if (!partialHistory) {
214 : // Cycle collected?
215 0 : return;
216 : }
217 :
218 0 : nsCOMPtr<nsIFrameLoader> loader;
219 0 : partialHistory->GetOwnerFrameLoader(getter_AddRefs(loader));
220 0 : loader->RequestFrameLoaderClose();
221 : }
222 :
223 : // Remove references.
224 0 : mPartialHistories.RemoveElementsAt(aLastPartialIndexToKeep + 1,
225 0 : lastIndex - aLastPartialIndexToKeep);
226 : }
227 :
228 : /* static */ bool
229 2 : GroupedSHistory::GroupedHistoryEnabled() {
230 : static bool sGroupedSHistoryEnabled = false;
231 : static bool sGroupedSHistoryPrefCached = false;
232 2 : if (!sGroupedSHistoryPrefCached) {
233 2 : sGroupedSHistoryPrefCached = true;
234 : Preferences::AddBoolVarCache(&sGroupedSHistoryEnabled,
235 : "browser.groupedhistory.enabled",
236 2 : false);
237 : }
238 :
239 2 : return sGroupedSHistoryEnabled;
240 : }
241 :
242 : void
243 0 : GroupedSHistory::PurgePrerendering()
244 : {
245 0 : nsTArray<PrerenderingHistory> histories = Move(mPrerenderingHistories);
246 : // Remove the frameloaders which are owned by the prerendering history, and
247 : // remove them from mPrerenderingHistories.
248 0 : for (uint32_t i = 0; i < histories.Length(); ++i) {
249 0 : nsCOMPtr<nsIFrameLoader> loader;
250 0 : histories[i].mPartialHistory->GetOwnerFrameLoader(getter_AddRefs(loader));
251 0 : if (loader) {
252 0 : loader->RequestFrameLoaderClose();
253 : }
254 : }
255 0 : MOZ_ASSERT(mPrerenderingHistories.IsEmpty());
256 0 : }
257 :
258 : NS_IMETHODIMP
259 0 : GroupedSHistory::CloseInactiveFrameLoaderOwners()
260 : {
261 0 : MOZ_ASSERT(mIndexOfActivePartialHistory >= 0);
262 : // Remove inactive frameloaders which are participating in the grouped shistory
263 0 : for (uint32_t i = 0; i < mPartialHistories.Length(); ++i) {
264 0 : if (i != static_cast<uint32_t>(mIndexOfActivePartialHistory)) {
265 0 : nsCOMPtr<nsIFrameLoader> loader;
266 0 : mPartialHistories[i]->GetOwnerFrameLoader(getter_AddRefs(loader));
267 0 : loader->RequestFrameLoaderClose();
268 : }
269 : }
270 :
271 0 : PurgePrerendering();
272 :
273 0 : return NS_OK;
274 : }
275 :
276 : NS_IMETHODIMP
277 0 : GroupedSHistory::AddPrerenderingPartialSHistory(nsIPartialSHistory* aPrerendering, int32_t aId)
278 : {
279 0 : NS_ENSURE_TRUE(aPrerendering && aId, NS_ERROR_UNEXPECTED);
280 0 : aPrerendering->SetActiveState(nsIPartialSHistory::STATE_PRERENDER);
281 0 : PrerenderingHistory history = { aPrerendering, aId };
282 0 : mPrerenderingHistories.AppendElement(history);
283 0 : return NS_OK;
284 : }
285 :
286 : NS_IMETHODIMP
287 0 : GroupedSHistory::GetActiveFrameLoader(nsIFrameLoader** aFrameLoader)
288 : {
289 0 : if (mIndexOfActivePartialHistory >= 0) {
290 0 : return mPartialHistories[mIndexOfActivePartialHistory]->GetOwnerFrameLoader(aFrameLoader);
291 : }
292 0 : return NS_ERROR_NOT_AVAILABLE;
293 : }
294 :
295 : NS_IMETHODIMP
296 0 : GroupedSHistory::ActivatePrerendering(int32_t aId, JSContext* aCx, nsISupports** aPromise)
297 : {
298 0 : NS_ENSURE_TRUE(aId && aCx && aPromise, NS_ERROR_UNEXPECTED);
299 :
300 : // Look for an entry with the given aId in mPrerenderingHistories.
301 0 : for (uint32_t i = 0; i < mPrerenderingHistories.Length(); ++i) {
302 0 : if (mPrerenderingHistories[i].mId == aId) {
303 0 : nsCOMPtr<nsIPartialSHistory> partialHistory = mPrerenderingHistories[i].mPartialHistory;
304 0 : mPrerenderingHistories.RemoveElementAt(i);
305 :
306 0 : nsCOMPtr<nsIFrameLoader> fl;
307 0 : partialHistory->GetOwnerFrameLoader(getter_AddRefs(fl));
308 0 : NS_ENSURE_TRUE(fl, NS_ERROR_FAILURE);
309 :
310 0 : nsCOMPtr<nsIFrameLoader> activeFl;
311 0 : GetActiveFrameLoader(getter_AddRefs(activeFl));
312 0 : NS_ENSURE_TRUE(activeFl, NS_ERROR_FAILURE);
313 :
314 0 : nsresult rv = fl->MakePrerenderedLoaderActive();
315 0 : NS_ENSURE_SUCCESS(rv, rv);
316 :
317 0 : return activeFl->AppendPartialSHistoryAndSwap(fl, aPromise);
318 : }
319 : }
320 :
321 : // Generate a rejected promise as the entry was not found.
322 0 : nsCOMPtr<nsIGlobalObject> go = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
323 0 : if (NS_WARN_IF(!go)) {
324 0 : return NS_ERROR_FAILURE;
325 : }
326 0 : ErrorResult rv;
327 0 : RefPtr<Promise> promise = Promise::Reject(go, aCx, JS::UndefinedHandleValue, rv);
328 0 : if (NS_WARN_IF(rv.Failed())) {
329 0 : return NS_ERROR_FAILURE;
330 : }
331 0 : promise.forget(aPromise);
332 0 : return NS_OK;
333 : }
334 :
335 : NS_IMETHODIMP
336 0 : GroupedSHistory::CancelPrerendering(int32_t aId)
337 : {
338 0 : for (uint32_t i = 0; i < mPrerenderingHistories.Length(); ++i) {
339 0 : if (mPrerenderingHistories[i].mId == aId) {
340 0 : nsCOMPtr<nsIPartialSHistory> partialHistory = mPrerenderingHistories[i].mPartialHistory;
341 0 : nsCOMPtr<nsIFrameLoader> fl;
342 0 : partialHistory->GetOwnerFrameLoader(getter_AddRefs(fl));
343 0 : if (fl) {
344 0 : fl->RequestFrameLoaderClose();
345 : }
346 0 : mPrerenderingHistories.RemoveElementAt(i);
347 : }
348 : }
349 :
350 0 : return NS_OK;
351 : }
352 :
353 : } // namespace dom
354 9 : } // namespace mozilla
|