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 "nsSHEntry.h"
8 :
9 : #include <algorithm>
10 :
11 : #include "nsDocShellEditorData.h"
12 : #include "nsIContentViewer.h"
13 : #include "nsIDocShellLoadInfo.h"
14 : #include "nsIDocShellTreeItem.h"
15 : #include "nsIInputStream.h"
16 : #include "nsILayoutHistoryState.h"
17 : #include "nsIStructuredCloneContainer.h"
18 : #include "nsIURI.h"
19 : #include "nsSHEntryShared.h"
20 : #include "nsSHistory.h"
21 :
22 : #include "mozilla/net/ReferrerPolicy.h"
23 :
24 : namespace dom = mozilla::dom;
25 :
26 : static uint32_t gEntryID = 0;
27 :
28 1 : nsSHEntry::nsSHEntry()
29 1 : : mShared(new nsSHEntryShared())
30 : , mReferrerPolicy(mozilla::net::RP_Unset)
31 : , mLoadType(0)
32 1 : , mID(gEntryID++)
33 : , mScrollPositionX(0)
34 : , mScrollPositionY(0)
35 : , mParent(nullptr)
36 : , mLoadReplace(false)
37 : , mURIWasModified(false)
38 : , mIsSrcdocEntry(false)
39 : , mScrollRestorationIsManual(false)
40 3 : , mLoadedInThisProcess(false)
41 : {
42 1 : }
43 :
44 0 : nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
45 : : mShared(aOther.mShared)
46 : , mURI(aOther.mURI)
47 : , mOriginalURI(aOther.mOriginalURI)
48 : , mReferrerURI(aOther.mReferrerURI)
49 0 : , mReferrerPolicy(aOther.mReferrerPolicy)
50 : , mTitle(aOther.mTitle)
51 : , mPostData(aOther.mPostData)
52 : , mLoadType(0) // XXX why not copy?
53 0 : , mID(aOther.mID)
54 : , mScrollPositionX(0) // XXX why not copy?
55 : , mScrollPositionY(0) // XXX why not copy?
56 0 : , mParent(aOther.mParent)
57 : , mStateData(aOther.mStateData)
58 : , mSrcdocData(aOther.mSrcdocData)
59 : , mBaseURI(aOther.mBaseURI)
60 0 : , mLoadReplace(aOther.mLoadReplace)
61 0 : , mURIWasModified(aOther.mURIWasModified)
62 0 : , mIsSrcdocEntry(aOther.mIsSrcdocEntry)
63 : , mScrollRestorationIsManual(false)
64 0 : , mLoadedInThisProcess(aOther.mLoadedInThisProcess)
65 : {
66 0 : }
67 :
68 0 : nsSHEntry::~nsSHEntry()
69 : {
70 : // Null out the mParent pointers on all our kids.
71 0 : for (nsISHEntry* entry : mChildren) {
72 0 : if (entry) {
73 0 : entry->SetParent(nullptr);
74 : }
75 : }
76 0 : }
77 :
78 77 : NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry, nsISHEntryInternal)
79 :
80 : NS_IMETHODIMP
81 0 : nsSHEntry::SetScrollPosition(int32_t aX, int32_t aY)
82 : {
83 0 : mScrollPositionX = aX;
84 0 : mScrollPositionY = aY;
85 0 : return NS_OK;
86 : }
87 :
88 : NS_IMETHODIMP
89 2 : nsSHEntry::GetScrollPosition(int32_t* aX, int32_t* aY)
90 : {
91 2 : *aX = mScrollPositionX;
92 2 : *aY = mScrollPositionY;
93 2 : return NS_OK;
94 : }
95 :
96 : NS_IMETHODIMP
97 0 : nsSHEntry::GetURIWasModified(bool* aOut)
98 : {
99 0 : *aOut = mURIWasModified;
100 0 : return NS_OK;
101 : }
102 :
103 : NS_IMETHODIMP
104 0 : nsSHEntry::SetURIWasModified(bool aIn)
105 : {
106 0 : mURIWasModified = aIn;
107 0 : return NS_OK;
108 : }
109 :
110 : NS_IMETHODIMP
111 5 : nsSHEntry::GetURI(nsIURI** aURI)
112 : {
113 5 : *aURI = mURI;
114 5 : NS_IF_ADDREF(*aURI);
115 5 : return NS_OK;
116 : }
117 :
118 : NS_IMETHODIMP
119 0 : nsSHEntry::SetURI(nsIURI* aURI)
120 : {
121 0 : mURI = aURI;
122 0 : return NS_OK;
123 : }
124 :
125 : NS_IMETHODIMP
126 4 : nsSHEntry::GetOriginalURI(nsIURI** aOriginalURI)
127 : {
128 4 : *aOriginalURI = mOriginalURI;
129 4 : NS_IF_ADDREF(*aOriginalURI);
130 4 : return NS_OK;
131 : }
132 :
133 : NS_IMETHODIMP
134 1 : nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI)
135 : {
136 1 : mOriginalURI = aOriginalURI;
137 1 : return NS_OK;
138 : }
139 :
140 : NS_IMETHODIMP
141 2 : nsSHEntry::GetResultPrincipalURI(nsIURI** aResultPrincipalURI)
142 : {
143 2 : *aResultPrincipalURI = mResultPrincipalURI;
144 2 : NS_IF_ADDREF(*aResultPrincipalURI);
145 2 : return NS_OK;
146 : }
147 :
148 : NS_IMETHODIMP
149 1 : nsSHEntry::SetResultPrincipalURI(nsIURI* aResultPrincipalURI)
150 : {
151 1 : mResultPrincipalURI = aResultPrincipalURI;
152 1 : return NS_OK;
153 : }
154 :
155 : NS_IMETHODIMP
156 2 : nsSHEntry::GetLoadReplace(bool* aLoadReplace)
157 : {
158 2 : *aLoadReplace = mLoadReplace;
159 2 : return NS_OK;
160 : }
161 :
162 : NS_IMETHODIMP
163 1 : nsSHEntry::SetLoadReplace(bool aLoadReplace)
164 : {
165 1 : mLoadReplace = aLoadReplace;
166 1 : return NS_OK;
167 : }
168 :
169 : NS_IMETHODIMP
170 2 : nsSHEntry::GetReferrerURI(nsIURI** aReferrerURI)
171 : {
172 2 : *aReferrerURI = mReferrerURI;
173 2 : NS_IF_ADDREF(*aReferrerURI);
174 2 : return NS_OK;
175 : }
176 :
177 : NS_IMETHODIMP
178 1 : nsSHEntry::SetReferrerURI(nsIURI* aReferrerURI)
179 : {
180 1 : mReferrerURI = aReferrerURI;
181 1 : return NS_OK;
182 : }
183 :
184 : NS_IMETHODIMP
185 0 : nsSHEntry::GetReferrerPolicy(uint32_t* aReferrerPolicy)
186 : {
187 0 : *aReferrerPolicy = mReferrerPolicy;
188 0 : return NS_OK;
189 : }
190 :
191 : NS_IMETHODIMP
192 1 : nsSHEntry::SetReferrerPolicy(uint32_t aReferrerPolicy)
193 : {
194 1 : mReferrerPolicy = aReferrerPolicy;
195 1 : return NS_OK;
196 : }
197 :
198 : NS_IMETHODIMP
199 0 : nsSHEntry::SetContentViewer(nsIContentViewer* aViewer)
200 : {
201 0 : return mShared->SetContentViewer(aViewer);
202 : }
203 :
204 : NS_IMETHODIMP
205 3 : nsSHEntry::GetContentViewer(nsIContentViewer** aResult)
206 : {
207 3 : *aResult = mShared->mContentViewer;
208 3 : NS_IF_ADDREF(*aResult);
209 3 : return NS_OK;
210 : }
211 :
212 : NS_IMETHODIMP
213 3 : nsSHEntry::GetAnyContentViewer(nsISHEntry** aOwnerEntry,
214 : nsIContentViewer** aResult)
215 : {
216 : // Find a content viewer in the root node or any of its children,
217 : // assuming that there is only one content viewer total in any one
218 : // nsSHEntry tree
219 3 : GetContentViewer(aResult);
220 3 : if (*aResult) {
221 : #ifdef DEBUG_PAGE_CACHE
222 : printf("Found content viewer\n");
223 : #endif
224 0 : *aOwnerEntry = this;
225 0 : NS_ADDREF(*aOwnerEntry);
226 0 : return NS_OK;
227 : }
228 : // The root SHEntry doesn't have a ContentViewer, so check child nodes
229 3 : for (int32_t i = 0; i < mChildren.Count(); i++) {
230 0 : nsISHEntry* child = mChildren[i];
231 0 : if (child) {
232 : #ifdef DEBUG_PAGE_CACHE
233 : printf("Evaluating SHEntry child %d\n", i);
234 : #endif
235 0 : child->GetAnyContentViewer(aOwnerEntry, aResult);
236 0 : if (*aResult) {
237 0 : return NS_OK;
238 : }
239 : }
240 : }
241 3 : return NS_OK;
242 : }
243 :
244 : NS_IMETHODIMP
245 0 : nsSHEntry::SetSticky(bool aSticky)
246 : {
247 0 : mShared->mSticky = aSticky;
248 0 : return NS_OK;
249 : }
250 :
251 : NS_IMETHODIMP
252 0 : nsSHEntry::GetSticky(bool* aSticky)
253 : {
254 0 : *aSticky = mShared->mSticky;
255 0 : return NS_OK;
256 : }
257 :
258 : NS_IMETHODIMP
259 2 : nsSHEntry::GetTitle(char16_t** aTitle)
260 : {
261 : // Check for empty title...
262 2 : if (mTitle.IsEmpty() && mURI) {
263 : // Default title is the URL.
264 4 : nsAutoCString spec;
265 2 : if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
266 2 : AppendUTF8toUTF16(spec, mTitle);
267 : }
268 : }
269 :
270 2 : *aTitle = ToNewUnicode(mTitle);
271 2 : return NS_OK;
272 : }
273 :
274 : NS_IMETHODIMP
275 1 : nsSHEntry::SetTitle(const nsAString& aTitle)
276 : {
277 1 : mTitle = aTitle;
278 1 : return NS_OK;
279 : }
280 :
281 : NS_IMETHODIMP
282 0 : nsSHEntry::GetPostData(nsIInputStream** aResult)
283 : {
284 0 : *aResult = mPostData;
285 0 : NS_IF_ADDREF(*aResult);
286 0 : return NS_OK;
287 : }
288 :
289 : NS_IMETHODIMP
290 0 : nsSHEntry::SetPostData(nsIInputStream* aPostData)
291 : {
292 0 : mPostData = aPostData;
293 0 : return NS_OK;
294 : }
295 :
296 : NS_IMETHODIMP
297 6 : nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult)
298 : {
299 6 : *aResult = mShared->mLayoutHistoryState;
300 6 : NS_IF_ADDREF(*aResult);
301 6 : return NS_OK;
302 : }
303 :
304 : NS_IMETHODIMP
305 1 : nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState)
306 : {
307 1 : mShared->mLayoutHistoryState = aState;
308 1 : if (mShared->mLayoutHistoryState) {
309 2 : mShared->mLayoutHistoryState->SetScrollPositionOnly(
310 2 : !mShared->mSaveLayoutState);
311 : }
312 :
313 1 : return NS_OK;
314 : }
315 :
316 : NS_IMETHODIMP
317 0 : nsSHEntry::InitLayoutHistoryState(nsILayoutHistoryState** aState)
318 : {
319 0 : if (!mShared->mLayoutHistoryState) {
320 0 : nsCOMPtr<nsILayoutHistoryState> historyState;
321 0 : historyState = NS_NewLayoutHistoryState();
322 0 : nsresult rv = SetLayoutHistoryState(historyState);
323 0 : NS_ENSURE_SUCCESS(rv, rv);
324 : }
325 :
326 0 : return GetLayoutHistoryState(aState);
327 : }
328 :
329 : NS_IMETHODIMP
330 0 : nsSHEntry::GetLoadType(uint32_t* aResult)
331 : {
332 0 : *aResult = mLoadType;
333 0 : return NS_OK;
334 : }
335 :
336 : NS_IMETHODIMP
337 1 : nsSHEntry::SetLoadType(uint32_t aLoadType)
338 : {
339 1 : mLoadType = aLoadType;
340 1 : return NS_OK;
341 : }
342 :
343 : NS_IMETHODIMP
344 2 : nsSHEntry::GetID(uint32_t* aResult)
345 : {
346 2 : *aResult = mID;
347 2 : return NS_OK;
348 : }
349 :
350 : NS_IMETHODIMP
351 0 : nsSHEntry::SetID(uint32_t aID)
352 : {
353 0 : mID = aID;
354 0 : return NS_OK;
355 : }
356 :
357 : nsSHEntryShared*
358 0 : nsSHEntry::GetSharedState()
359 : {
360 0 : return mShared;
361 : }
362 :
363 : NS_IMETHODIMP
364 3 : nsSHEntry::GetIsSubFrame(bool* aFlag)
365 : {
366 3 : *aFlag = mShared->mIsFrameNavigation;
367 3 : return NS_OK;
368 : }
369 :
370 : NS_IMETHODIMP
371 0 : nsSHEntry::SetIsSubFrame(bool aFlag)
372 : {
373 0 : mShared->mIsFrameNavigation = aFlag;
374 0 : return NS_OK;
375 : }
376 :
377 : NS_IMETHODIMP
378 2 : nsSHEntry::GetCacheKey(nsISupports** aResult)
379 : {
380 2 : *aResult = mShared->mCacheKey;
381 2 : NS_IF_ADDREF(*aResult);
382 2 : return NS_OK;
383 : }
384 :
385 : NS_IMETHODIMP
386 0 : nsSHEntry::SetCacheKey(nsISupports* aCacheKey)
387 : {
388 0 : mShared->mCacheKey = aCacheKey;
389 0 : return NS_OK;
390 : }
391 :
392 : NS_IMETHODIMP
393 0 : nsSHEntry::GetSaveLayoutStateFlag(bool* aFlag)
394 : {
395 0 : *aFlag = mShared->mSaveLayoutState;
396 0 : return NS_OK;
397 : }
398 :
399 : NS_IMETHODIMP
400 0 : nsSHEntry::SetSaveLayoutStateFlag(bool aFlag)
401 : {
402 0 : mShared->mSaveLayoutState = aFlag;
403 0 : if (mShared->mLayoutHistoryState) {
404 0 : mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
405 : }
406 :
407 0 : return NS_OK;
408 : }
409 :
410 : NS_IMETHODIMP
411 0 : nsSHEntry::GetExpirationStatus(bool* aFlag)
412 : {
413 0 : *aFlag = mShared->mExpired;
414 0 : return NS_OK;
415 : }
416 :
417 : NS_IMETHODIMP
418 0 : nsSHEntry::SetExpirationStatus(bool aFlag)
419 : {
420 0 : mShared->mExpired = aFlag;
421 0 : return NS_OK;
422 : }
423 :
424 : NS_IMETHODIMP
425 2 : nsSHEntry::GetContentType(nsACString& aContentType)
426 : {
427 2 : aContentType = mShared->mContentType;
428 2 : return NS_OK;
429 : }
430 :
431 : NS_IMETHODIMP
432 0 : nsSHEntry::SetContentType(const nsACString& aContentType)
433 : {
434 0 : mShared->mContentType = aContentType;
435 0 : return NS_OK;
436 : }
437 :
438 : NS_IMETHODIMP
439 1 : nsSHEntry::Create(nsIURI* aURI, const nsAString& aTitle,
440 : nsIInputStream* aInputStream,
441 : nsILayoutHistoryState* aLayoutHistoryState,
442 : nsISupports* aCacheKey, const nsACString& aContentType,
443 : nsIPrincipal* aTriggeringPrincipal,
444 : nsIPrincipal* aPrincipalToInherit,
445 : const nsID& aDocShellID,
446 : bool aDynamicCreation)
447 : {
448 1 : MOZ_ASSERT(aTriggeringPrincipal,
449 : "need a valid triggeringPrincipal to create a session history entry");
450 :
451 1 : mURI = aURI;
452 1 : mTitle = aTitle;
453 1 : mPostData = aInputStream;
454 :
455 : // Set the LoadType by default to loadHistory during creation
456 1 : mLoadType = (uint32_t)nsIDocShellLoadInfo::loadHistory;
457 :
458 1 : mShared->mCacheKey = aCacheKey;
459 1 : mShared->mContentType = aContentType;
460 1 : mShared->mTriggeringPrincipal = aTriggeringPrincipal;
461 1 : mShared->mPrincipalToInherit = aPrincipalToInherit;
462 1 : mShared->mDocShellID = aDocShellID;
463 1 : mShared->mDynamicallyCreated = aDynamicCreation;
464 :
465 : // By default all entries are set false for subframe flag.
466 : // nsDocShell::CloneAndReplace() which creates entries for
467 : // all subframe navigations, sets the flag to true.
468 1 : mShared->mIsFrameNavigation = false;
469 :
470 : // By default we save LayoutHistoryState
471 1 : mShared->mSaveLayoutState = true;
472 1 : mShared->mLayoutHistoryState = aLayoutHistoryState;
473 :
474 : // By default the page is not expired
475 1 : mShared->mExpired = false;
476 :
477 1 : mIsSrcdocEntry = false;
478 1 : mSrcdocData = NullString();
479 :
480 1 : mLoadedInThisProcess = true;
481 :
482 1 : return NS_OK;
483 : }
484 :
485 : NS_IMETHODIMP
486 0 : nsSHEntry::Clone(nsISHEntry** aResult)
487 : {
488 0 : *aResult = new nsSHEntry(*this);
489 0 : NS_ADDREF(*aResult);
490 0 : return NS_OK;
491 : }
492 :
493 : NS_IMETHODIMP
494 1 : nsSHEntry::GetParent(nsISHEntry** aResult)
495 : {
496 1 : NS_ENSURE_ARG_POINTER(aResult);
497 1 : *aResult = mParent;
498 1 : NS_IF_ADDREF(*aResult);
499 1 : return NS_OK;
500 : }
501 :
502 : NS_IMETHODIMP
503 0 : nsSHEntry::SetParent(nsISHEntry* aParent)
504 : {
505 : /* parent not Addrefed on purpose to avoid cyclic reference
506 : * Null parent is OK
507 : *
508 : * XXX this method should not be scriptable if this is the case!!
509 : */
510 0 : mParent = aParent;
511 0 : return NS_OK;
512 : }
513 :
514 : NS_IMETHODIMP
515 0 : nsSHEntry::SetWindowState(nsISupports* aState)
516 : {
517 0 : mShared->mWindowState = aState;
518 0 : return NS_OK;
519 : }
520 :
521 : NS_IMETHODIMP
522 0 : nsSHEntry::GetWindowState(nsISupports** aState)
523 : {
524 0 : NS_IF_ADDREF(*aState = mShared->mWindowState);
525 0 : return NS_OK;
526 : }
527 :
528 : NS_IMETHODIMP
529 0 : nsSHEntry::SetViewerBounds(const nsIntRect& aBounds)
530 : {
531 0 : mShared->mViewerBounds = aBounds;
532 0 : return NS_OK;
533 : }
534 :
535 : NS_IMETHODIMP
536 0 : nsSHEntry::GetViewerBounds(nsIntRect& aBounds)
537 : {
538 0 : aBounds = mShared->mViewerBounds;
539 0 : return NS_OK;
540 : }
541 :
542 : NS_IMETHODIMP
543 4 : nsSHEntry::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
544 : {
545 4 : NS_IF_ADDREF(*aTriggeringPrincipal = mShared->mTriggeringPrincipal);
546 4 : return NS_OK;
547 : }
548 :
549 : NS_IMETHODIMP
550 0 : nsSHEntry::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
551 : {
552 0 : mShared->mTriggeringPrincipal = aTriggeringPrincipal;
553 0 : return NS_OK;
554 : }
555 :
556 : NS_IMETHODIMP
557 2 : nsSHEntry::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit)
558 : {
559 2 : NS_IF_ADDREF(*aPrincipalToInherit = mShared->mPrincipalToInherit);
560 2 : return NS_OK;
561 : }
562 :
563 : NS_IMETHODIMP
564 0 : nsSHEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit)
565 : {
566 0 : mShared->mPrincipalToInherit = aPrincipalToInherit;
567 0 : return NS_OK;
568 : }
569 :
570 : NS_IMETHODIMP
571 2 : nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry** aEntry)
572 : {
573 2 : NS_ENSURE_ARG_POINTER(aEntry);
574 2 : NS_IF_ADDREF(*aEntry = mShared);
575 2 : return NS_OK;
576 : }
577 :
578 : bool
579 0 : nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry* aEntry)
580 : {
581 0 : return static_cast<nsIBFCacheEntry*>(mShared) == aEntry;
582 : }
583 :
584 : NS_IMETHODIMP
585 0 : nsSHEntry::AdoptBFCacheEntry(nsISHEntry* aEntry)
586 : {
587 0 : nsCOMPtr<nsISHEntryInternal> shEntry = do_QueryInterface(aEntry);
588 0 : NS_ENSURE_STATE(shEntry);
589 :
590 0 : nsSHEntryShared* shared = shEntry->GetSharedState();
591 0 : NS_ENSURE_STATE(shared);
592 :
593 0 : mShared = shared;
594 0 : return NS_OK;
595 : }
596 :
597 : NS_IMETHODIMP
598 0 : nsSHEntry::SharesDocumentWith(nsISHEntry* aEntry, bool* aOut)
599 : {
600 0 : NS_ENSURE_ARG_POINTER(aOut);
601 :
602 0 : nsCOMPtr<nsISHEntryInternal> internal = do_QueryInterface(aEntry);
603 0 : NS_ENSURE_STATE(internal);
604 :
605 0 : *aOut = mShared == internal->GetSharedState();
606 0 : return NS_OK;
607 : }
608 :
609 : NS_IMETHODIMP
610 0 : nsSHEntry::AbandonBFCacheEntry()
611 : {
612 0 : mShared = nsSHEntryShared::Duplicate(mShared);
613 0 : return NS_OK;
614 : }
615 :
616 : NS_IMETHODIMP
617 2 : nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry)
618 : {
619 2 : *aIsSrcdocEntry = mIsSrcdocEntry;
620 2 : return NS_OK;
621 : }
622 :
623 : NS_IMETHODIMP
624 2 : nsSHEntry::GetSrcdocData(nsAString& aSrcdocData)
625 : {
626 2 : aSrcdocData = mSrcdocData;
627 2 : return NS_OK;
628 : }
629 :
630 : NS_IMETHODIMP
631 0 : nsSHEntry::SetSrcdocData(const nsAString& aSrcdocData)
632 : {
633 0 : mSrcdocData = aSrcdocData;
634 0 : mIsSrcdocEntry = true;
635 0 : return NS_OK;
636 : }
637 :
638 : NS_IMETHODIMP
639 2 : nsSHEntry::GetBaseURI(nsIURI** aBaseURI)
640 : {
641 2 : *aBaseURI = mBaseURI;
642 2 : NS_IF_ADDREF(*aBaseURI);
643 2 : return NS_OK;
644 : }
645 :
646 : NS_IMETHODIMP
647 0 : nsSHEntry::SetBaseURI(nsIURI* aBaseURI)
648 : {
649 0 : mBaseURI = aBaseURI;
650 0 : return NS_OK;
651 : }
652 :
653 : NS_IMETHODIMP
654 2 : nsSHEntry::GetScrollRestorationIsManual(bool* aIsManual)
655 : {
656 2 : *aIsManual = mScrollRestorationIsManual;
657 2 : return NS_OK;
658 : }
659 :
660 : NS_IMETHODIMP
661 0 : nsSHEntry::SetScrollRestorationIsManual(bool aIsManual)
662 : {
663 0 : mScrollRestorationIsManual = aIsManual;
664 0 : return NS_OK;
665 : }
666 :
667 : NS_IMETHODIMP
668 0 : nsSHEntry::GetLoadedInThisProcess(bool* aLoadedInThisProcess)
669 : {
670 0 : *aLoadedInThisProcess = mLoadedInThisProcess;
671 0 : return NS_OK;
672 : }
673 :
674 : NS_IMETHODIMP
675 2 : nsSHEntry::GetChildCount(int32_t* aCount)
676 : {
677 2 : *aCount = mChildren.Count();
678 2 : return NS_OK;
679 : }
680 :
681 : NS_IMETHODIMP
682 0 : nsSHEntry::AddChild(nsISHEntry* aChild, int32_t aOffset)
683 : {
684 0 : if (aChild) {
685 0 : NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
686 : }
687 :
688 0 : if (aOffset < 0) {
689 0 : mChildren.AppendObject(aChild);
690 0 : return NS_OK;
691 : }
692 :
693 : //
694 : // Bug 52670: Ensure children are added in order.
695 : //
696 : // Later frames in the child list may load faster and get appended
697 : // before earlier frames, causing session history to be scrambled.
698 : // By growing the list here, they are added to the right position.
699 : //
700 : // Assert that aOffset will not be so high as to grow us a lot.
701 : //
702 0 : NS_ASSERTION(aOffset < (mChildren.Count() + 1023), "Large frames array!\n");
703 :
704 0 : bool newChildIsDyn = false;
705 0 : if (aChild) {
706 0 : aChild->IsDynamicallyAdded(&newChildIsDyn);
707 : }
708 :
709 : // If the new child is dynamically added, try to add it to aOffset, but if
710 : // there are non-dynamically added children, the child must be after those.
711 0 : if (newChildIsDyn) {
712 0 : int32_t lastNonDyn = aOffset - 1;
713 0 : for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
714 0 : nsISHEntry* entry = mChildren[i];
715 0 : if (entry) {
716 0 : bool dyn = false;
717 0 : entry->IsDynamicallyAdded(&dyn);
718 0 : if (dyn) {
719 0 : break;
720 : } else {
721 0 : lastNonDyn = i;
722 : }
723 : }
724 : }
725 : // InsertObjectAt allows only appending one object.
726 : // If aOffset is larger than Count(), we must first manually
727 : // set the capacity.
728 0 : if (aOffset > mChildren.Count()) {
729 0 : mChildren.SetCount(aOffset);
730 : }
731 0 : if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
732 0 : NS_WARNING("Adding a child failed!");
733 0 : aChild->SetParent(nullptr);
734 0 : return NS_ERROR_FAILURE;
735 : }
736 : } else {
737 : // If the new child isn't dynamically added, it should be set to aOffset.
738 : // If there are dynamically added children before that, those must be
739 : // moved to be after aOffset.
740 0 : if (mChildren.Count() > 0) {
741 0 : int32_t start = std::min(mChildren.Count() - 1, aOffset);
742 0 : int32_t dynEntryIndex = -1;
743 0 : nsISHEntry* dynEntry = nullptr;
744 0 : for (int32_t i = start; i >= 0; --i) {
745 0 : nsISHEntry* entry = mChildren[i];
746 0 : if (entry) {
747 0 : bool dyn = false;
748 0 : entry->IsDynamicallyAdded(&dyn);
749 0 : if (dyn) {
750 0 : dynEntryIndex = i;
751 0 : dynEntry = entry;
752 : } else {
753 0 : break;
754 : }
755 : }
756 : }
757 :
758 0 : if (dynEntry) {
759 0 : nsCOMArray<nsISHEntry> tmp;
760 0 : tmp.SetCount(aOffset - dynEntryIndex + 1);
761 0 : mChildren.InsertObjectsAt(tmp, dynEntryIndex);
762 0 : NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
763 : }
764 : }
765 :
766 : // Make sure there isn't anything at aOffset.
767 0 : if (aOffset < mChildren.Count()) {
768 0 : nsISHEntry* oldChild = mChildren[aOffset];
769 0 : if (oldChild && oldChild != aChild) {
770 0 : NS_ERROR("Adding a child where we already have a child? This may misbehave");
771 0 : oldChild->SetParent(nullptr);
772 : }
773 : }
774 :
775 0 : mChildren.ReplaceObjectAt(aChild, aOffset);
776 : }
777 :
778 0 : return NS_OK;
779 : }
780 :
781 : NS_IMETHODIMP
782 0 : nsSHEntry::RemoveChild(nsISHEntry* aChild)
783 : {
784 0 : NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
785 0 : bool childRemoved = false;
786 0 : bool dynamic = false;
787 0 : aChild->IsDynamicallyAdded(&dynamic);
788 0 : if (dynamic) {
789 0 : childRemoved = mChildren.RemoveObject(aChild);
790 : } else {
791 0 : int32_t index = mChildren.IndexOfObject(aChild);
792 0 : if (index >= 0) {
793 : // Other alive non-dynamic child docshells still keep mChildOffset,
794 : // so we don't want to change the indices here.
795 0 : mChildren.ReplaceObjectAt(nullptr, index);
796 0 : childRemoved = true;
797 : }
798 : }
799 0 : if (childRemoved) {
800 0 : aChild->SetParent(nullptr);
801 :
802 : // reduce the child count, i.e. remove empty children at the end
803 0 : for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
804 0 : if (!mChildren.RemoveObjectAt(i)) {
805 0 : break;
806 : }
807 : }
808 : }
809 0 : return NS_OK;
810 : }
811 :
812 : NS_IMETHODIMP
813 0 : nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry** aResult)
814 : {
815 0 : if (aIndex >= 0 && aIndex < mChildren.Count()) {
816 0 : *aResult = mChildren[aIndex];
817 : // yes, mChildren can have holes in it. AddChild's offset parameter makes
818 : // that possible.
819 0 : NS_IF_ADDREF(*aResult);
820 : } else {
821 0 : *aResult = nullptr;
822 : }
823 0 : return NS_OK;
824 : }
825 :
826 : NS_IMETHODIMP
827 0 : nsSHEntry::ReplaceChild(nsISHEntry* aNewEntry)
828 : {
829 0 : NS_ENSURE_STATE(aNewEntry);
830 :
831 0 : nsID docshellID = aNewEntry->DocshellID();
832 :
833 0 : for (int32_t i = 0; i < mChildren.Count(); ++i) {
834 0 : if (mChildren[i] && docshellID == mChildren[i]->DocshellID()) {
835 0 : mChildren[i]->SetParent(nullptr);
836 0 : mChildren.ReplaceObjectAt(aNewEntry, i);
837 0 : return aNewEntry->SetParent(this);
838 : }
839 : }
840 0 : return NS_ERROR_FAILURE;
841 : }
842 :
843 : NS_IMETHODIMP
844 0 : nsSHEntry::AddChildShell(nsIDocShellTreeItem* aShell)
845 : {
846 0 : NS_ASSERTION(aShell, "Null child shell added to history entry");
847 0 : mShared->mChildShells.AppendObject(aShell);
848 0 : return NS_OK;
849 : }
850 :
851 : NS_IMETHODIMP
852 0 : nsSHEntry::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem** aShell)
853 : {
854 0 : NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex));
855 0 : return NS_OK;
856 : }
857 :
858 : NS_IMETHODIMP
859 0 : nsSHEntry::ClearChildShells()
860 : {
861 0 : mShared->mChildShells.Clear();
862 0 : return NS_OK;
863 : }
864 :
865 : NS_IMETHODIMP
866 0 : nsSHEntry::GetRefreshURIList(nsIMutableArray** aList)
867 : {
868 0 : NS_IF_ADDREF(*aList = mShared->mRefreshURIList);
869 0 : return NS_OK;
870 : }
871 :
872 : NS_IMETHODIMP
873 0 : nsSHEntry::SetRefreshURIList(nsIMutableArray* aList)
874 : {
875 0 : mShared->mRefreshURIList = aList;
876 0 : return NS_OK;
877 : }
878 :
879 : NS_IMETHODIMP
880 0 : nsSHEntry::SyncPresentationState()
881 : {
882 0 : return mShared->SyncPresentationState();
883 : }
884 :
885 : void
886 0 : nsSHEntry::RemoveFromBFCacheSync()
887 : {
888 0 : mShared->RemoveFromBFCacheSync();
889 0 : }
890 :
891 : void
892 0 : nsSHEntry::RemoveFromBFCacheAsync()
893 : {
894 0 : mShared->RemoveFromBFCacheAsync();
895 0 : }
896 :
897 : nsDocShellEditorData*
898 0 : nsSHEntry::ForgetEditorData()
899 : {
900 : // XXX jlebar Check how this is used.
901 0 : return mShared->mEditorData.forget();
902 : }
903 :
904 : void
905 0 : nsSHEntry::SetEditorData(nsDocShellEditorData* aData)
906 : {
907 0 : NS_ASSERTION(!(aData && mShared->mEditorData),
908 : "We're going to overwrite an owning ref!");
909 0 : if (mShared->mEditorData != aData) {
910 0 : mShared->mEditorData = aData;
911 : }
912 0 : }
913 :
914 : bool
915 1 : nsSHEntry::HasDetachedEditor()
916 : {
917 1 : return mShared->mEditorData != nullptr;
918 : }
919 :
920 : NS_IMETHODIMP
921 3 : nsSHEntry::GetStateData(nsIStructuredCloneContainer** aContainer)
922 : {
923 3 : NS_ENSURE_ARG_POINTER(aContainer);
924 3 : NS_IF_ADDREF(*aContainer = mStateData);
925 3 : return NS_OK;
926 : }
927 :
928 : NS_IMETHODIMP
929 0 : nsSHEntry::SetStateData(nsIStructuredCloneContainer* aContainer)
930 : {
931 0 : mStateData = aContainer;
932 0 : return NS_OK;
933 : }
934 :
935 : NS_IMETHODIMP
936 0 : nsSHEntry::IsDynamicallyAdded(bool* aAdded)
937 : {
938 0 : *aAdded = mShared->mDynamicallyCreated;
939 0 : return NS_OK;
940 : }
941 :
942 : NS_IMETHODIMP
943 0 : nsSHEntry::HasDynamicallyAddedChild(bool* aAdded)
944 : {
945 0 : *aAdded = false;
946 0 : for (int32_t i = 0; i < mChildren.Count(); ++i) {
947 0 : nsISHEntry* entry = mChildren[i];
948 0 : if (entry) {
949 0 : entry->IsDynamicallyAdded(aAdded);
950 0 : if (*aAdded) {
951 0 : break;
952 : }
953 : }
954 : }
955 0 : return NS_OK;
956 : }
957 :
958 : NS_IMETHODIMP
959 2 : nsSHEntry::GetDocshellID(nsID** aID)
960 : {
961 2 : *aID = static_cast<nsID*>(nsMemory::Clone(&mShared->mDocShellID, sizeof(nsID)));
962 2 : return NS_OK;
963 : }
964 :
965 : const nsID
966 0 : nsSHEntry::DocshellID()
967 : {
968 0 : return mShared->mDocShellID;
969 : }
970 :
971 : NS_IMETHODIMP
972 1 : nsSHEntry::SetDocshellID(const nsID* aID)
973 : {
974 1 : mShared->mDocShellID = *aID;
975 1 : return NS_OK;
976 : }
977 :
978 : NS_IMETHODIMP
979 0 : nsSHEntry::GetLastTouched(uint32_t* aLastTouched)
980 : {
981 0 : *aLastTouched = mShared->mLastTouched;
982 0 : return NS_OK;
983 : }
984 :
985 : NS_IMETHODIMP
986 0 : nsSHEntry::SetLastTouched(uint32_t aLastTouched)
987 : {
988 0 : mShared->mLastTouched = aLastTouched;
989 0 : return NS_OK;
990 : }
991 :
992 : NS_IMETHODIMP
993 1 : nsSHEntry::GetSHistory(nsISHistory** aSHistory)
994 : {
995 2 : nsCOMPtr<nsISHistory> shistory(do_QueryReferent(mShared->mSHistory));
996 1 : shistory.forget(aSHistory);
997 2 : return NS_OK;
998 : }
999 :
1000 : NS_IMETHODIMP
1001 1 : nsSHEntry::SetSHistory(nsISHistory* aSHistory)
1002 : {
1003 2 : nsWeakPtr shistory = do_GetWeakReference(aSHistory);
1004 : // mSHistory can not be changed once it's set
1005 1 : MOZ_ASSERT(!mShared->mSHistory || (mShared->mSHistory == shistory));
1006 1 : mShared->mSHistory = shistory;
1007 2 : return NS_OK;
1008 : }
|