Coverage Report

Created: 2018-09-25 14:53

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