nsSHEntry.cpp 31 KB
Newer Older
1
2
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
4
5
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6

7
#include "nsSHEntry.h"
8
9
10

#include <algorithm>

11
#include "nsIContentSecurityPolicy.h"
12
#include "nsDocShellEditorData.h"
13
#include "nsDocShellLoadTypes.h"
14
#include "nsIContentViewer.h"
15
#include "nsIDocShellTreeItem.h"
16
#include "nsIInputStream.h"
17
#include "nsILayoutHistoryState.h"
18
#include "nsIStructuredCloneContainer.h"
19
#include "nsIURI.h"
20
21
22
#include "nsSHEntryShared.h"
#include "nsSHistory.h"

23
#include "mozilla/Logging.h"
24
#include "nsIReferrerInfo.h"
25

26
27
extern mozilla::LazyLogModule gPageCacheLog;

28
29
namespace dom = mozilla::dom;

30
static uint32_t gEntryID = 0;
31

32
33
nsSHEntry::nsSHEntry(dom::SHEntrySharedParentState* aState)
    : mShared(aState),
34
35
36
37
38
39
40
41
42
43
44
      mLoadType(0),
      mID(gEntryID++),
      mScrollPositionX(0),
      mScrollPositionY(0),
      mParent(nullptr),
      mLoadReplace(false),
      mURIWasModified(false),
      mIsSrcdocEntry(false),
      mScrollRestorationIsManual(false),
      mLoadedInThisProcess(false),
      mPersist(true) {}
45

46
nsSHEntry::nsSHEntry(const nsSHEntry& aOther)
47
48
49
50
    : mShared(aOther.mShared),
      mURI(aOther.mURI),
      mOriginalURI(aOther.mOriginalURI),
      mResultPrincipalURI(aOther.mResultPrincipalURI),
51
      mReferrerInfo(aOther.mReferrerInfo),
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
      mTitle(aOther.mTitle),
      mPostData(aOther.mPostData),
      mLoadType(0)  // XXX why not copy?
      ,
      mID(aOther.mID),
      mScrollPositionX(0)  // XXX why not copy?
      ,
      mScrollPositionY(0)  // XXX why not copy?
      ,
      mParent(aOther.mParent),
      mStateData(aOther.mStateData),
      mSrcdocData(aOther.mSrcdocData),
      mBaseURI(aOther.mBaseURI),
      mLoadReplace(aOther.mLoadReplace),
      mURIWasModified(aOther.mURIWasModified),
      mIsSrcdocEntry(aOther.mIsSrcdocEntry),
      mScrollRestorationIsManual(false),
      mLoadedInThisProcess(aOther.mLoadedInThisProcess),
      mPersist(aOther.mPersist) {}

nsSHEntry::~nsSHEntry() {
73
  // Null out the mParent pointers on all our kids.
74
75
76
77
78
  for (nsISHEntry* entry : mChildren) {
    if (entry) {
      entry->SetParent(nullptr);
    }
  }
79
80
}

81
NS_IMPL_ISUPPORTS(nsSHEntry, nsISHEntry)
82

83
NS_IMETHODIMP
84
nsSHEntry::SetScrollPosition(int32_t aX, int32_t aY) {
85
86
  mScrollPositionX = aX;
  mScrollPositionY = aY;
87
88
89
  return NS_OK;
}

90
NS_IMETHODIMP
91
nsSHEntry::GetScrollPosition(int32_t* aX, int32_t* aY) {
92
93
  *aX = mScrollPositionX;
  *aY = mScrollPositionY;
94
95
  return NS_OK;
}
96

97
NS_IMETHODIMP
98
nsSHEntry::GetURIWasModified(bool* aOut) {
99
100
101
102
  *aOut = mURIWasModified;
  return NS_OK;
}

103
NS_IMETHODIMP
104
nsSHEntry::SetURIWasModified(bool aIn) {
105
106
107
108
  mURIWasModified = aIn;
  return NS_OK;
}

109
NS_IMETHODIMP
110
nsSHEntry::GetURI(nsIURI** aURI) {
111
112
113
  *aURI = mURI;
  NS_IF_ADDREF(*aURI);
  return NS_OK;
114
}
115

116
NS_IMETHODIMP
117
nsSHEntry::SetURI(nsIURI* aURI) {
118
119
  mURI = aURI;
  return NS_OK;
120
121
}

122
NS_IMETHODIMP
123
nsSHEntry::GetOriginalURI(nsIURI** aOriginalURI) {
124
125
126
127
128
129
  *aOriginalURI = mOriginalURI;
  NS_IF_ADDREF(*aOriginalURI);
  return NS_OK;
}

NS_IMETHODIMP
130
nsSHEntry::SetOriginalURI(nsIURI* aOriginalURI) {
131
132
133
134
  mOriginalURI = aOriginalURI;
  return NS_OK;
}

135
NS_IMETHODIMP
136
nsSHEntry::GetResultPrincipalURI(nsIURI** aResultPrincipalURI) {
137
138
139
140
141
142
  *aResultPrincipalURI = mResultPrincipalURI;
  NS_IF_ADDREF(*aResultPrincipalURI);
  return NS_OK;
}

NS_IMETHODIMP
143
nsSHEntry::SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
144
145
146
147
  mResultPrincipalURI = aResultPrincipalURI;
  return NS_OK;
}

148
NS_IMETHODIMP
149
nsSHEntry::GetLoadReplace(bool* aLoadReplace) {
150
151
152
153
154
  *aLoadReplace = mLoadReplace;
  return NS_OK;
}

NS_IMETHODIMP
155
nsSHEntry::SetLoadReplace(bool aLoadReplace) {
156
157
158
159
  mLoadReplace = aLoadReplace;
  return NS_OK;
}

160
NS_IMETHODIMP
161
162
163
nsSHEntry::GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) {
  *aReferrerInfo = mReferrerInfo;
  NS_IF_ADDREF(*aReferrerInfo);
164
  return NS_OK;
165
166
}

167
NS_IMETHODIMP
168
169
nsSHEntry::SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) {
  mReferrerInfo = aReferrerInfo;
170
171
172
  return NS_OK;
}

173
NS_IMETHODIMP
174
nsSHEntry::SetContentViewer(nsIContentViewer* aViewer) {
175
176
177
178
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
  return NS_OK;
179
180
}

181
NS_IMETHODIMP
182
nsSHEntry::GetContentViewer(nsIContentViewer** aResult) {
183
184
185
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
186
  return NS_OK;
187
188
}

189
NS_IMETHODIMP
190
nsSHEntry::SetSticky(bool aSticky) {
191
  mShared->mSticky = aSticky;
192
193
194
195
  return NS_OK;
}

NS_IMETHODIMP
196
nsSHEntry::GetSticky(bool* aSticky) {
197
  *aSticky = mShared->mSticky;
198
199
200
  return NS_OK;
}

201
NS_IMETHODIMP
202
nsSHEntry::GetTitle(nsAString& aTitle) {
203
204
205
  // Check for empty title...
  if (mTitle.IsEmpty() && mURI) {
    // Default title is the URL.
206
    nsAutoCString spec;
207
    if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
208
      AppendUTF8toUTF16(spec, mTitle);
209
    }
210
  }
211

212
  aTitle = mTitle;
213
  return NS_OK;
214
215
}

216
NS_IMETHODIMP
217
nsSHEntry::SetTitle(const nsAString& aTitle) {
218
219
  mTitle = aTitle;
  return NS_OK;
220
221
}

222
NS_IMETHODIMP
223
nsSHEntry::GetPostData(nsIInputStream** aResult) {
224
225
226
  *aResult = mPostData;
  NS_IF_ADDREF(*aResult);
  return NS_OK;
227
228
}

229
NS_IMETHODIMP
230
nsSHEntry::SetPostData(nsIInputStream* aPostData) {
231
232
  mPostData = aPostData;
  return NS_OK;
233
234
}

235
NS_IMETHODIMP
236
nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult) {
237
238
  *aResult = mShared->mLayoutHistoryState;
  NS_IF_ADDREF(*aResult);
239
  return NS_OK;
240
241
}

242
NS_IMETHODIMP
243
nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState) {
244
245
246
247
248
249
250
  MOZ_ASSERT(!mShared->mLayoutHistoryState);
  mShared->mLayoutHistoryState = aState;
  if (mShared->mLayoutHistoryState) {
    mShared->mLayoutHistoryState->SetScrollPositionOnly(
        !mShared->mSaveLayoutState);
  }

251
  return NS_OK;
252
253
}

254
NS_IMETHODIMP
255
nsSHEntry::InitLayoutHistoryState(nsILayoutHistoryState** aState) {
256
257
258
259
260
261
262
263
  if (!mShared->mLayoutHistoryState) {
    nsCOMPtr<nsILayoutHistoryState> historyState;
    historyState = NS_NewLayoutHistoryState();
    SetLayoutHistoryState(historyState);
  }

  nsCOMPtr<nsILayoutHistoryState> state = GetLayoutHistoryState();
  state.forget(aState);
264
  return NS_OK;
265
266
267
}

NS_IMETHODIMP
268
nsSHEntry::GetLoadType(uint32_t* aResult) {
269
270
  *aResult = mLoadType;
  return NS_OK;
271
272
}

273
NS_IMETHODIMP
274
nsSHEntry::SetLoadType(uint32_t aLoadType) {
275
276
  mLoadType = aLoadType;
  return NS_OK;
277
}
278

279
NS_IMETHODIMP
280
nsSHEntry::GetID(uint32_t* aResult) {
281
282
  *aResult = mID;
  return NS_OK;
283
284
}

285
NS_IMETHODIMP
286
nsSHEntry::SetID(uint32_t aID) {
287
288
  mID = aID;
  return NS_OK;
289
290
}

291
NS_IMETHODIMP
292
nsSHEntry::GetIsSubFrame(bool* aFlag) {
293
  *aFlag = mShared->mIsFrameNavigation;
294
  return NS_OK;
295
296
}

297
NS_IMETHODIMP
298
nsSHEntry::SetIsSubFrame(bool aFlag) {
299
  mShared->mIsFrameNavigation = aFlag;
300
  return NS_OK;
301
}
302

303
NS_IMETHODIMP
304
nsSHEntry::GetCacheKey(uint32_t* aResult) {
305
  *aResult = mShared->mCacheKey;
306
  return NS_OK;
307
308
}

309
NS_IMETHODIMP
310
nsSHEntry::SetCacheKey(uint32_t aCacheKey) {
311
  mShared->mCacheKey = aCacheKey;
312
  return NS_OK;
313
314
}

315
NS_IMETHODIMP
316
nsSHEntry::GetSaveLayoutStateFlag(bool* aFlag) {
317
318
319
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
320
  return NS_OK;
321
322
}

323
NS_IMETHODIMP
324
nsSHEntry::SetSaveLayoutStateFlag(bool aFlag) {
325
326
327
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
328
  return NS_OK;
329
330
}

331
NS_IMETHODIMP
332
nsSHEntry::GetExpirationStatus(bool* aFlag) {
333
  *aFlag = mShared->mExpired;
334
  return NS_OK;
335
336
}

337
NS_IMETHODIMP
338
nsSHEntry::SetExpirationStatus(bool aFlag) {
339
  mShared->mExpired = aFlag;
340
  return NS_OK;
341
342
}

343
NS_IMETHODIMP
344
nsSHEntry::GetContentType(nsACString& aContentType) {
345
  aContentType = mShared->mContentType;
346
347
348
  return NS_OK;
}

349
NS_IMETHODIMP
350
nsSHEntry::SetContentType(const nsACString& aContentType) {
351
  mShared->mContentType = aContentType;
352
353
354
  return NS_OK;
}

355
NS_IMETHODIMP
356
357
358
359
360
361
362
363
364
nsSHEntry::Create(
    nsIURI* aURI, const nsAString& aTitle, nsIInputStream* aInputStream,
    uint32_t aCacheKey, const nsACString& aContentType,
    nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
    nsIPrincipal* aStoragePrincipalToInherit, nsIContentSecurityPolicy* aCsp,
    const nsID& aDocShellID, bool aDynamicCreation, nsIURI* aOriginalURI,
    nsIURI* aResultPrincipalURI, bool aLoadReplace,
    nsIReferrerInfo* aReferrerInfo, const nsAString& aSrcdocData,
    bool aSrcdocEntry, nsIURI* aBaseURI, bool aSaveLayoutState, bool aExpired) {
365
366
367
  MOZ_ASSERT(
      aTriggeringPrincipal,
      "need a valid triggeringPrincipal to create a session history entry");
368

369
370
371
  mURI = aURI;
  mTitle = aTitle;
  mPostData = aInputStream;
372

373
  // Set the LoadType by default to loadHistory during creation
374
  mLoadType = LOAD_HISTORY;
375

376
377
  mShared->mCacheKey = aCacheKey;
  mShared->mContentType = aContentType;
378
  mShared->mTriggeringPrincipal = aTriggeringPrincipal;
379
  mShared->mPrincipalToInherit = aPrincipalToInherit;
380
  mShared->mStoragePrincipalToInherit = aStoragePrincipalToInherit;
381
  mShared->mCsp = aCsp;
382
383
384
  mShared->mDocShellID = aDocShellID;
  mShared->mDynamicallyCreated = aDynamicCreation;

385
  // By default all entries are set false for subframe flag.
386
387
  // nsDocShell::CloneAndReplace() which creates entries for
  // all subframe navigations, sets the flag to true.
388
  mShared->mIsFrameNavigation = false;
389

390
  mShared->mExpired = aExpired;
391

392
393
394
395
  mIsSrcdocEntry = aSrcdocEntry;
  mSrcdocData = aSrcdocData;

  mBaseURI = aBaseURI;
396

397
398
  mLoadedInThisProcess = true;

399
400
401
402
  mOriginalURI = aOriginalURI;
  mResultPrincipalURI = aResultPrincipalURI;
  mLoadReplace = aLoadReplace;
  mReferrerInfo = aReferrerInfo;
403
  return NS_OK;
404
}
405

406
NS_IMETHODIMP
407
nsSHEntry::Clone(nsISHEntry** aResult) {
408
409
410
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
411
  return NS_OK;
412
413
}

414
NS_IMETHODIMP
415
nsSHEntry::GetParent(nsISHEntry** aResult) {
416
  *aResult = mParent;
417
418
419
420
421
  NS_IF_ADDREF(*aResult);
  return NS_OK;
}

NS_IMETHODIMP
422
nsSHEntry::SetParent(nsISHEntry* aParent) {
423
424
425
426
427
  /* parent not Addrefed on purpose to avoid cyclic reference
   * Null parent is OK
   *
   * XXX this method should not be scriptable if this is the case!!
   */
428
  mParent = aParent;
429
430
431
  return NS_OK;
}

432
NS_IMETHODIMP
433
nsSHEntry::SetWindowState(nsISupports* aState) {
434
435
436
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
437
438
439
440
  return NS_OK;
}

NS_IMETHODIMP
441
nsSHEntry::GetWindowState(nsISupports** aState) {
442
443
444
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
445
446
447
  return NS_OK;
}

448
NS_IMETHODIMP_(void)
449
nsSHEntry::SetViewerBounds(const nsIntRect& aBounds) {
450
  mShared->mViewerBounds = aBounds;
451
452
}

453
NS_IMETHODIMP_(void)
454
nsSHEntry::GetViewerBounds(nsIntRect& aBounds) {
455
  aBounds = mShared->mViewerBounds;
456
457
458
}

NS_IMETHODIMP
459
nsSHEntry::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal) {
460
  NS_IF_ADDREF(*aTriggeringPrincipal = mShared->mTriggeringPrincipal);
461
462
463
  return NS_OK;
}

464
NS_IMETHODIMP
465
nsSHEntry::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal) {
466
  mShared->mTriggeringPrincipal = aTriggeringPrincipal;
467
  return NS_OK;
468
469
470
}

NS_IMETHODIMP
471
nsSHEntry::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
472
473
474
475
476
  NS_IF_ADDREF(*aPrincipalToInherit = mShared->mPrincipalToInherit);
  return NS_OK;
}

NS_IMETHODIMP
477
nsSHEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
478
479
  mShared->mPrincipalToInherit = aPrincipalToInherit;
  return NS_OK;
480
481
}

482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
NS_IMETHODIMP
nsSHEntry::GetStoragePrincipalToInherit(
    nsIPrincipal** aStoragePrincipalToInherit) {
  NS_IF_ADDREF(*aStoragePrincipalToInherit =
                   mShared->mStoragePrincipalToInherit);
  return NS_OK;
}

NS_IMETHODIMP
nsSHEntry::SetStoragePrincipalToInherit(
    nsIPrincipal* aStoragePrincipalToInherit) {
  mShared->mStoragePrincipalToInherit = aStoragePrincipalToInherit;
  return NS_OK;
}

497
498
499
500
501
502
503
504
505
506
507
508
NS_IMETHODIMP
nsSHEntry::GetCsp(nsIContentSecurityPolicy** aCsp) {
  NS_IF_ADDREF(*aCsp = mShared->mCsp);
  return NS_OK;
}

NS_IMETHODIMP
nsSHEntry::SetCsp(nsIContentSecurityPolicy* aCsp) {
  mShared->mCsp = aCsp;
  return NS_OK;
}

509
bool nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry* aEntry) {
510
511
512
513
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
  return false;
514
515
516
}

NS_IMETHODIMP
517
nsSHEntry::AdoptBFCacheEntry(nsISHEntry* aEntry) {
518
519
  dom::SHEntrySharedParentState* shared =
      static_cast<nsSHEntry*>(aEntry)->mShared;
520
521
522
523
524
525
526
  NS_ENSURE_STATE(shared);

  mShared = shared;
  return NS_OK;
}

NS_IMETHODIMP
527
nsSHEntry::SharesDocumentWith(nsISHEntry* aEntry, bool* aOut) {
528
529
  NS_ENSURE_ARG_POINTER(aOut);

530
  *aOut = mShared == static_cast<nsSHEntry*>(aEntry)->mShared;
531
532
533
534
  return NS_OK;
}

NS_IMETHODIMP
535
nsSHEntry::AbandonBFCacheEntry() {
536
537
538
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
539
540
541
  return NS_OK;
}

542
NS_IMETHODIMP
543
nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry) {
544
545
546
547
548
  *aIsSrcdocEntry = mIsSrcdocEntry;
  return NS_OK;
}

NS_IMETHODIMP
549
nsSHEntry::GetSrcdocData(nsAString& aSrcdocData) {
550
551
552
553
554
  aSrcdocData = mSrcdocData;
  return NS_OK;
}

NS_IMETHODIMP
555
nsSHEntry::SetSrcdocData(const nsAString& aSrcdocData) {
556
557
558
559
560
  mSrcdocData = aSrcdocData;
  mIsSrcdocEntry = true;
  return NS_OK;
}

561
NS_IMETHODIMP
562
nsSHEntry::GetBaseURI(nsIURI** aBaseURI) {
563
564
565
566
  *aBaseURI = mBaseURI;
  NS_IF_ADDREF(*aBaseURI);
  return NS_OK;
}
567

568
NS_IMETHODIMP
569
nsSHEntry::SetBaseURI(nsIURI* aBaseURI) {
570
571
572
  mBaseURI = aBaseURI;
  return NS_OK;
}
573

574
NS_IMETHODIMP
575
nsSHEntry::GetScrollRestorationIsManual(bool* aIsManual) {
576
577
578
579
580
  *aIsManual = mScrollRestorationIsManual;
  return NS_OK;
}

NS_IMETHODIMP
581
nsSHEntry::SetScrollRestorationIsManual(bool aIsManual) {
582
583
584
585
  mScrollRestorationIsManual = aIsManual;
  return NS_OK;
}

586
NS_IMETHODIMP
587
nsSHEntry::GetLoadedInThisProcess(bool* aLoadedInThisProcess) {
588
589
590
591
  *aLoadedInThisProcess = mLoadedInThisProcess;
  return NS_OK;
}

592
NS_IMETHODIMP
593
nsSHEntry::GetChildCount(int32_t* aCount) {
594
595
  *aCount = mChildren.Count();
  return NS_OK;
596
597
598
}

NS_IMETHODIMP
599
600
nsSHEntry::AddChild(nsISHEntry* aChild, int32_t aOffset,
                    bool aUseRemoteSubframes) {
601
602
603
  if (aChild) {
    NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
  }
604

605
606
607
608
  if (aOffset < 0) {
    mChildren.AppendObject(aChild);
    return NS_OK;
  }
609

610
611
612
613
614
615
616
617
618
  //
  // Bug 52670: Ensure children are added in order.
  //
  //  Later frames in the child list may load faster and get appended
  //  before earlier frames, causing session history to be scrambled.
  //  By growing the list here, they are added to the right position.
  //
  //  Assert that aOffset will not be so high as to grow us a lot.
  //
619
  NS_ASSERTION(aOffset < (mChildren.Count() + 1023), "Large frames array!\n");
620

621
  bool newChildIsDyn = aChild ? aChild->IsDynamicallyAdded() : false;
622

623
624
625
  // If the new child is dynamically added, try to add it to aOffset, but if
  // there are non-dynamically added children, the child must be after those.
  if (newChildIsDyn) {
626
627
    int32_t lastNonDyn = aOffset - 1;
    for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
628
629
      nsISHEntry* entry = mChildren[i];
      if (entry) {
630
        if (entry->IsDynamicallyAdded()) {
631
632
633
634
635
636
637
638
639
640
641
642
643
644
          break;
        } else {
          lastNonDyn = i;
        }
      }
    }
    // InsertObjectAt allows only appending one object.
    // If aOffset is larger than Count(), we must first manually
    // set the capacity.
    if (aOffset > mChildren.Count()) {
      mChildren.SetCount(aOffset);
    }
    if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
      NS_WARNING("Adding a child failed!");
645
      aChild->SetParent(nullptr);
646
647
648
649
650
651
652
      return NS_ERROR_FAILURE;
    }
  } else {
    // If the new child isn't dynamically added, it should be set to aOffset.
    // If there are dynamically added children before that, those must be
    // moved to be after aOffset.
    if (mChildren.Count() > 0) {
653
      int32_t start = std::min(mChildren.Count() - 1, aOffset);
654
      int32_t dynEntryIndex = -1;
655
      nsISHEntry* dynEntry = nullptr;
656
      for (int32_t i = start; i >= 0; --i) {
657
658
        nsISHEntry* entry = mChildren[i];
        if (entry) {
659
          if (entry->IsDynamicallyAdded()) {
660
661
662
663
664
665
666
            dynEntryIndex = i;
            dynEntry = entry;
          } else {
            break;
          }
        }
      }
667

668
669
670
671
672
673
674
675
676
677
678
679
      if (dynEntry) {
        nsCOMArray<nsISHEntry> tmp;
        tmp.SetCount(aOffset - dynEntryIndex + 1);
        mChildren.InsertObjectsAt(tmp, dynEntryIndex);
        NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
      }
    }

    // Make sure there isn't anything at aOffset.
    if (aOffset < mChildren.Count()) {
      nsISHEntry* oldChild = mChildren[aOffset];
      if (oldChild && oldChild != aChild) {
680
681
682
683
684
685
686
687
688
689
        // Under Fission, this can happen when a network-created iframe starts
        // out in-process, moves out-of-process, and then switches back. At that
        // point, we'll create a new network-created DocShell at the same index
        // where we already have an entry for the original network-created
        // DocShell.
        //
        // This should ideally stop being an issue once the Fission-aware
        // session history rewrite is complete.
        NS_ASSERTION(
            aUseRemoteSubframes,
690
            "Adding a child where we already have a child? This may misbehave");
691
        oldChild->SetParent(nullptr);
692
693
694
      }
    }

695
    mChildren.ReplaceObjectAt(aChild, aOffset);
696
  }
697

698
  return NS_OK;
699
700
701
}

NS_IMETHODIMP
702
nsSHEntry::RemoveChild(nsISHEntry* aChild) {
703
  NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
704
  bool childRemoved = false;
705
  if (aChild->IsDynamicallyAdded()) {
706
707
    childRemoved = mChildren.RemoveObject(aChild);
  } else {
708
    int32_t index = mChildren.IndexOfObject(aChild);
709
    if (index >= 0) {
710
711
      // Other alive non-dynamic child docshells still keep mChildOffset,
      // so we don't want to change the indices here.
712
713
      mChildren.ReplaceObjectAt(nullptr, index);
      childRemoved = true;
714
715
    }
  }
716
  if (childRemoved) {
717
    aChild->SetParent(nullptr);
718
719

    // reduce the child count, i.e. remove empty children at the end
720
    for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
721
722
723
724
725
      if (!mChildren.RemoveObjectAt(i)) {
        break;
      }
    }
  }
726
  return NS_OK;
727
728
729
}

NS_IMETHODIMP
730
nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry** aResult) {
731
732
  if (aIndex >= 0 && aIndex < mChildren.Count()) {
    *aResult = mChildren[aIndex];
733
734
735
    // yes, mChildren can have holes in it.  AddChild's offset parameter makes
    // that possible.
    NS_IF_ADDREF(*aResult);
736
  } else {
737
    *aResult = nullptr;
738
739
  }
  return NS_OK;
740
}
741

742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
NS_IMETHODIMP_(void)
nsSHEntry::GetChildSHEntryIfHasNoDynamicallyAddedChild(int32_t aChildOffset,
                                                       nsISHEntry** aChild) {
  *aChild = nullptr;

  bool dynamicallyAddedChild = false;
  HasDynamicallyAddedChild(&dynamicallyAddedChild);
  if (dynamicallyAddedChild) {
    return;
  }

  // If the user did a shift-reload on this frameset page,
  // we don't want to load the subframes from history.
  if (IsForceReloadType(mLoadType) || mLoadType == LOAD_REFRESH) {
    return;
  }

  /* Before looking for the subframe's url, check
   * the expiration status of the parent. If the parent
   * has expired from cache, then subframes will not be
   * loaded from history in certain situations.
   * If the user pressed reload and the parent frame has expired
   *  from cache, we do not want to load the child frame from history.
   */
  if (mShared->mExpired && (mLoadType == LOAD_RELOAD_NORMAL)) {
    // The parent has expired. Return null.
    *aChild = nullptr;
    return;
  }
  // Get the child subframe from session history.
  GetChildAt(aChildOffset, aChild);
  if (*aChild) {
    // Set the parent's Load Type on the child
    (*aChild)->SetLoadType(mLoadType);
  }
}

779
NS_IMETHODIMP
780
nsSHEntry::ReplaceChild(nsISHEntry* aNewEntry) {
781
782
  NS_ENSURE_STATE(aNewEntry);

783
784
  nsID docshellID;
  aNewEntry->GetDocshellID(docshellID);
785
786

  for (int32_t i = 0; i < mChildren.Count(); ++i) {
787
788
789
790
791
792
793
794
795
    if (mChildren[i]) {
      nsID childDocshellID;
      nsresult rv = mChildren[i]->GetDocshellID(childDocshellID);
      NS_ENSURE_SUCCESS(rv, rv);
      if (docshellID == childDocshellID) {
        mChildren[i]->SetParent(nullptr);
        mChildren.ReplaceObjectAt(aNewEntry, i);
        return aNewEntry->SetParent(this);
      }
796
797
798
799
800
    }
  }
  return NS_ERROR_FAILURE;
}

801
802
803
804
805
806
807
808
809
810
NS_IMETHODIMP_(void) nsSHEntry::ClearEntry() {
  int32_t childCount = GetChildCount();
  // Remove all children of this entry
  for (int32_t i = childCount - 1; i >= 0; i--) {
    nsCOMPtr<nsISHEntry> child;
    GetChildAt(i, getter_AddRefs(child));
    RemoveChild(child);
  }
}

811
NS_IMETHODIMP_(void)
812
nsSHEntry::AddChildShell(nsIDocShellTreeItem* aShell) {
813
814
815
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
816
817
818
}

NS_IMETHODIMP
819
nsSHEntry::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem** aShell) {
820
821
822
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
823
824
825
  return NS_OK;
}

826
NS_IMETHODIMP_(void)
827
828
829
830
831
nsSHEntry::ClearChildShells() {
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
}
832
833

NS_IMETHODIMP
834
nsSHEntry::GetRefreshURIList(nsIMutableArray** aList) {
835
836
837
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
838
839
840
841
  return NS_OK;
}

NS_IMETHODIMP
842
nsSHEntry::SetRefreshURIList(nsIMutableArray* aList) {
843
844
845
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
846
847
848
  return NS_OK;
}

849
NS_IMETHODIMP_(void)
850
851
852
853
854
nsSHEntry::SyncPresentationState() {
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
}
855

856
nsDocShellEditorData* nsSHEntry::ForgetEditorData() {
857
858
859
860
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
  return nullptr;
861
862
}

863
void nsSHEntry::SetEditorData(nsDocShellEditorData* aData) {
864
865
866
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
867
868
}

869
870
871
872
873
874
bool nsSHEntry::HasDetachedEditor() {
  MOZ_CRASH(
      "Classes inheriting from nsSHEntry should implement this. "
      "Bug 1546344 will clean this up.");
  return false;
}
875

876
NS_IMETHODIMP
877
nsSHEntry::GetStateData(nsIStructuredCloneContainer** aContainer) {
878
  NS_IF_ADDREF(*aContainer = mStateData);
879
880
881
882
  return NS_OK;
}

NS_IMETHODIMP
883
nsSHEntry::SetStateData(nsIStructuredCloneContainer* aContainer) {
884
  mStateData = aContainer;
885
886
887
  return NS_OK;
}

888
NS_IMETHODIMP_(bool)
889
nsSHEntry::IsDynamicallyAdded() { return mShared->mDynamicallyCreated; }
890
891

NS_IMETHODIMP
892
nsSHEntry::HasDynamicallyAddedChild(bool* aAdded) {
893
  *aAdded = false;
894
  for (int32_t i = 0; i < mChildren.Count(); ++i) {
895
896
    nsISHEntry* entry = mChildren[i];
    if (entry) {
897
      *aAdded = entry->IsDynamicallyAdded();
898
899
900
901
902
903
904
905
906
      if (*aAdded) {
        break;
      }
    }
  }
  return NS_OK;
}

NS_IMETHODIMP
907
908
nsSHEntry::GetDocshellID(nsID& aID) {
  aID = mShared->mDocShellID;
909
910
911
912
  return NS_OK;
}

NS_IMETHODIMP
913
914
nsSHEntry::SetDocshellID(const nsID& aID) {
  mShared->mDocShellID = aID;
915
916
917
  return NS_OK;
}

918
NS_IMETHODIMP
919
nsSHEntry::GetLastTouched(uint32_t* aLastTouched) {
920
  *aLastTouched = mShared->mLastTouched;
921
922
923
924
  return NS_OK;
}

NS_IMETHODIMP
925
nsSHEntry::SetLastTouched(uint32_t aLastTouched) {