docshell/shistory/src/nsSHEntry.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/docshell/shistory/src/nsSHEntry.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,835 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +// Local Includes
    1.10 +#include "nsSHEntry.h"
    1.11 +#include "nsIDocShellLoadInfo.h"
    1.12 +#include "nsIDocShellTreeItem.h"
    1.13 +#include "nsDocShellEditorData.h"
    1.14 +#include "nsSHEntryShared.h"
    1.15 +#include "nsILayoutHistoryState.h"
    1.16 +#include "nsIContentViewer.h"
    1.17 +#include "nsISupportsArray.h"
    1.18 +#include "nsIStructuredCloneContainer.h"
    1.19 +#include "nsIInputStream.h"
    1.20 +#include "nsIURI.h"
    1.21 +#include <algorithm>
    1.22 +
    1.23 +namespace dom = mozilla::dom;
    1.24 +
    1.25 +static uint32_t gEntryID = 0;
    1.26 +
    1.27 +//*****************************************************************************
    1.28 +//***    nsSHEntry: Object Management
    1.29 +//*****************************************************************************
    1.30 +
    1.31 +
    1.32 +nsSHEntry::nsSHEntry()
    1.33 +  : mLoadType(0)
    1.34 +  , mID(gEntryID++)
    1.35 +  , mScrollPositionX(0)
    1.36 +  , mScrollPositionY(0)
    1.37 +  , mParent(nullptr)
    1.38 +  , mURIWasModified(false)
    1.39 +  , mIsSrcdocEntry(false)
    1.40 +{
    1.41 +  mShared = new nsSHEntryShared();
    1.42 +}
    1.43 +
    1.44 +nsSHEntry::nsSHEntry(const nsSHEntry &other)
    1.45 +  : mShared(other.mShared)
    1.46 +  , mURI(other.mURI)
    1.47 +  , mReferrerURI(other.mReferrerURI)
    1.48 +  , mTitle(other.mTitle)
    1.49 +  , mPostData(other.mPostData)
    1.50 +  , mLoadType(0)         // XXX why not copy?
    1.51 +  , mID(other.mID)
    1.52 +  , mScrollPositionX(0)  // XXX why not copy?
    1.53 +  , mScrollPositionY(0)  // XXX why not copy?
    1.54 +  , mParent(other.mParent)
    1.55 +  , mURIWasModified(other.mURIWasModified)
    1.56 +  , mStateData(other.mStateData)
    1.57 +  , mIsSrcdocEntry(other.mIsSrcdocEntry)
    1.58 +  , mSrcdocData(other.mSrcdocData)
    1.59 +  , mBaseURI(other.mBaseURI)
    1.60 +{
    1.61 +}
    1.62 +
    1.63 +static bool
    1.64 +ClearParentPtr(nsISHEntry* aEntry, void* /* aData */)
    1.65 +{
    1.66 +  if (aEntry) {
    1.67 +    aEntry->SetParent(nullptr);
    1.68 +  }
    1.69 +  return true;
    1.70 +}
    1.71 +
    1.72 +nsSHEntry::~nsSHEntry()
    1.73 +{
    1.74 +  // Null out the mParent pointers on all our kids.
    1.75 +  mChildren.EnumerateForwards(ClearParentPtr, nullptr);
    1.76 +}
    1.77 +
    1.78 +//*****************************************************************************
    1.79 +//    nsSHEntry: nsISupports
    1.80 +//*****************************************************************************
    1.81 +
    1.82 +NS_IMPL_ISUPPORTS(nsSHEntry, nsISHContainer, nsISHEntry, nsISHEntryInternal)
    1.83 +
    1.84 +//*****************************************************************************
    1.85 +//    nsSHEntry: nsISHEntry
    1.86 +//*****************************************************************************
    1.87 +
    1.88 +NS_IMETHODIMP nsSHEntry::SetScrollPosition(int32_t x, int32_t y)
    1.89 +{
    1.90 +  mScrollPositionX = x;
    1.91 +  mScrollPositionY = y;
    1.92 +  return NS_OK;
    1.93 +}
    1.94 +
    1.95 +NS_IMETHODIMP nsSHEntry::GetScrollPosition(int32_t *x, int32_t *y)
    1.96 +{
    1.97 +  *x = mScrollPositionX;
    1.98 +  *y = mScrollPositionY;
    1.99 +  return NS_OK;
   1.100 +}
   1.101 +
   1.102 +NS_IMETHODIMP nsSHEntry::GetURIWasModified(bool* aOut)
   1.103 +{
   1.104 +  *aOut = mURIWasModified;
   1.105 +  return NS_OK;
   1.106 +}
   1.107 +
   1.108 +NS_IMETHODIMP nsSHEntry::SetURIWasModified(bool aIn)
   1.109 +{
   1.110 +  mURIWasModified = aIn;
   1.111 +  return NS_OK;
   1.112 +}
   1.113 +
   1.114 +NS_IMETHODIMP nsSHEntry::GetURI(nsIURI** aURI)
   1.115 +{
   1.116 +  *aURI = mURI;
   1.117 +  NS_IF_ADDREF(*aURI);
   1.118 +  return NS_OK;
   1.119 +}
   1.120 +
   1.121 +NS_IMETHODIMP nsSHEntry::SetURI(nsIURI* aURI)
   1.122 +{
   1.123 +  mURI = aURI;
   1.124 +  return NS_OK;
   1.125 +}
   1.126 +
   1.127 +NS_IMETHODIMP nsSHEntry::GetReferrerURI(nsIURI **aReferrerURI)
   1.128 +{
   1.129 +  *aReferrerURI = mReferrerURI;
   1.130 +  NS_IF_ADDREF(*aReferrerURI);
   1.131 +  return NS_OK;
   1.132 +}
   1.133 +
   1.134 +NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
   1.135 +{
   1.136 +  mReferrerURI = aReferrerURI;
   1.137 +  return NS_OK;
   1.138 +}
   1.139 +
   1.140 +NS_IMETHODIMP
   1.141 +nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
   1.142 +{
   1.143 +  return mShared->SetContentViewer(aViewer);
   1.144 +}
   1.145 +
   1.146 +NS_IMETHODIMP
   1.147 +nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
   1.148 +{
   1.149 +  *aResult = mShared->mContentViewer;
   1.150 +  NS_IF_ADDREF(*aResult);
   1.151 +  return NS_OK;
   1.152 +}
   1.153 +
   1.154 +NS_IMETHODIMP
   1.155 +nsSHEntry::GetAnyContentViewer(nsISHEntry **aOwnerEntry,
   1.156 +                               nsIContentViewer **aResult)
   1.157 +{
   1.158 +  // Find a content viewer in the root node or any of its children,
   1.159 +  // assuming that there is only one content viewer total in any one
   1.160 +  // nsSHEntry tree
   1.161 +  GetContentViewer(aResult);
   1.162 +  if (*aResult) {
   1.163 +#ifdef DEBUG_PAGE_CACHE 
   1.164 +    printf("Found content viewer\n");
   1.165 +#endif
   1.166 +    *aOwnerEntry = this;
   1.167 +    NS_ADDREF(*aOwnerEntry);
   1.168 +    return NS_OK;
   1.169 +  }
   1.170 +  // The root SHEntry doesn't have a ContentViewer, so check child nodes
   1.171 +  for (int32_t i = 0; i < mChildren.Count(); i++) {
   1.172 +    nsISHEntry* child = mChildren[i];
   1.173 +    if (child) {
   1.174 +#ifdef DEBUG_PAGE_CACHE
   1.175 +      printf("Evaluating SHEntry child %d\n", i);
   1.176 +#endif
   1.177 +      child->GetAnyContentViewer(aOwnerEntry, aResult);
   1.178 +      if (*aResult) {
   1.179 +        return NS_OK;
   1.180 +      }
   1.181 +    }
   1.182 +  }
   1.183 +  return NS_OK;
   1.184 +}
   1.185 +
   1.186 +NS_IMETHODIMP
   1.187 +nsSHEntry::SetSticky(bool aSticky)
   1.188 +{
   1.189 +  mShared->mSticky = aSticky;
   1.190 +  return NS_OK;
   1.191 +}
   1.192 +
   1.193 +NS_IMETHODIMP
   1.194 +nsSHEntry::GetSticky(bool *aSticky)
   1.195 +{
   1.196 +  *aSticky = mShared->mSticky;
   1.197 +  return NS_OK;
   1.198 +}
   1.199 +
   1.200 +NS_IMETHODIMP nsSHEntry::GetTitle(char16_t** aTitle)
   1.201 +{
   1.202 +  // Check for empty title...
   1.203 +  if (mTitle.IsEmpty() && mURI) {
   1.204 +    // Default title is the URL.
   1.205 +    nsAutoCString spec;
   1.206 +    if (NS_SUCCEEDED(mURI->GetSpec(spec)))
   1.207 +      AppendUTF8toUTF16(spec, mTitle);
   1.208 +  }
   1.209 +
   1.210 +  *aTitle = ToNewUnicode(mTitle);
   1.211 +  return NS_OK;
   1.212 +}
   1.213 +
   1.214 +NS_IMETHODIMP nsSHEntry::SetTitle(const nsAString &aTitle)
   1.215 +{
   1.216 +  mTitle = aTitle;
   1.217 +  return NS_OK;
   1.218 +}
   1.219 +
   1.220 +NS_IMETHODIMP nsSHEntry::GetPostData(nsIInputStream** aResult)
   1.221 +{
   1.222 +  *aResult = mPostData;
   1.223 +  NS_IF_ADDREF(*aResult);
   1.224 +  return NS_OK;
   1.225 +}
   1.226 +
   1.227 +NS_IMETHODIMP nsSHEntry::SetPostData(nsIInputStream* aPostData)
   1.228 +{
   1.229 +  mPostData = aPostData;
   1.230 +  return NS_OK;
   1.231 +}
   1.232 +
   1.233 +NS_IMETHODIMP nsSHEntry::GetLayoutHistoryState(nsILayoutHistoryState** aResult)
   1.234 +{
   1.235 +  *aResult = mShared->mLayoutHistoryState;
   1.236 +  NS_IF_ADDREF(*aResult);
   1.237 +  return NS_OK;
   1.238 +}
   1.239 +
   1.240 +NS_IMETHODIMP nsSHEntry::SetLayoutHistoryState(nsILayoutHistoryState* aState)
   1.241 +{
   1.242 +  mShared->mLayoutHistoryState = aState;
   1.243 +  if (mShared->mLayoutHistoryState) {
   1.244 +    mShared->mLayoutHistoryState->
   1.245 +      SetScrollPositionOnly(!mShared->mSaveLayoutState);
   1.246 +  }
   1.247 +
   1.248 +  return NS_OK;
   1.249 +}
   1.250 +
   1.251 +NS_IMETHODIMP nsSHEntry::GetLoadType(uint32_t * aResult)
   1.252 +{
   1.253 +  *aResult = mLoadType;
   1.254 +  return NS_OK;
   1.255 +}
   1.256 +
   1.257 +NS_IMETHODIMP nsSHEntry::SetLoadType(uint32_t  aLoadType)
   1.258 +{
   1.259 +  mLoadType = aLoadType;
   1.260 +  return NS_OK;
   1.261 +}
   1.262 +
   1.263 +NS_IMETHODIMP nsSHEntry::GetID(uint32_t * aResult)
   1.264 +{
   1.265 +  *aResult = mID;
   1.266 +  return NS_OK;
   1.267 +}
   1.268 +
   1.269 +NS_IMETHODIMP nsSHEntry::SetID(uint32_t  aID)
   1.270 +{
   1.271 +  mID = aID;
   1.272 +  return NS_OK;
   1.273 +}
   1.274 +
   1.275 +nsSHEntryShared* nsSHEntry::GetSharedState()
   1.276 +{
   1.277 +  return mShared;
   1.278 +}
   1.279 +
   1.280 +NS_IMETHODIMP nsSHEntry::GetIsSubFrame(bool * aFlag)
   1.281 +{
   1.282 +  *aFlag = mShared->mIsFrameNavigation;
   1.283 +  return NS_OK;
   1.284 +}
   1.285 +
   1.286 +NS_IMETHODIMP nsSHEntry::SetIsSubFrame(bool    aFlag)
   1.287 +{
   1.288 +  mShared->mIsFrameNavigation = aFlag;
   1.289 +  return NS_OK;
   1.290 +}
   1.291 +
   1.292 +NS_IMETHODIMP nsSHEntry::GetCacheKey(nsISupports** aResult)
   1.293 +{
   1.294 +  *aResult = mShared->mCacheKey;
   1.295 +  NS_IF_ADDREF(*aResult);
   1.296 +  return NS_OK;
   1.297 +}
   1.298 +
   1.299 +NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey)
   1.300 +{
   1.301 +  mShared->mCacheKey = aCacheKey;
   1.302 +  return NS_OK;
   1.303 +}
   1.304 +
   1.305 +NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(bool * aFlag)
   1.306 +{
   1.307 +  *aFlag = mShared->mSaveLayoutState;
   1.308 +  return NS_OK;
   1.309 +}
   1.310 +
   1.311 +NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(bool    aFlag)
   1.312 +{
   1.313 +  mShared->mSaveLayoutState = aFlag;
   1.314 +  if (mShared->mLayoutHistoryState) {
   1.315 +    mShared->mLayoutHistoryState->SetScrollPositionOnly(!aFlag);
   1.316 +  }
   1.317 +
   1.318 +  return NS_OK;
   1.319 +}
   1.320 +
   1.321 +NS_IMETHODIMP nsSHEntry::GetExpirationStatus(bool * aFlag)
   1.322 +{
   1.323 +  *aFlag = mShared->mExpired;
   1.324 +  return NS_OK;
   1.325 +}
   1.326 +
   1.327 +NS_IMETHODIMP nsSHEntry::SetExpirationStatus(bool    aFlag)
   1.328 +{
   1.329 +  mShared->mExpired = aFlag;
   1.330 +  return NS_OK;
   1.331 +}
   1.332 +
   1.333 +NS_IMETHODIMP nsSHEntry::GetContentType(nsACString& aContentType)
   1.334 +{
   1.335 +  aContentType = mShared->mContentType;
   1.336 +  return NS_OK;
   1.337 +}
   1.338 +
   1.339 +NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType)
   1.340 +{
   1.341 +  mShared->mContentType = aContentType;
   1.342 +  return NS_OK;
   1.343 +}
   1.344 +
   1.345 +NS_IMETHODIMP
   1.346 +nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle,
   1.347 +                  nsIInputStream * aInputStream,
   1.348 +                  nsILayoutHistoryState * aLayoutHistoryState,
   1.349 +                  nsISupports * aCacheKey, const nsACString& aContentType,
   1.350 +                  nsISupports* aOwner,
   1.351 +                  uint64_t aDocShellID, bool aDynamicCreation)
   1.352 +{
   1.353 +  mURI = aURI;
   1.354 +  mTitle = aTitle;
   1.355 +  mPostData = aInputStream;
   1.356 +
   1.357 +  // Set the LoadType by default to loadHistory during creation
   1.358 +  mLoadType = (uint32_t) nsIDocShellLoadInfo::loadHistory;
   1.359 +
   1.360 +  mShared->mCacheKey = aCacheKey;
   1.361 +  mShared->mContentType = aContentType;
   1.362 +  mShared->mOwner = aOwner;
   1.363 +  mShared->mDocShellID = aDocShellID;
   1.364 +  mShared->mDynamicallyCreated = aDynamicCreation;
   1.365 +
   1.366 +  // By default all entries are set false for subframe flag. 
   1.367 +  // nsDocShell::CloneAndReplace() which creates entries for
   1.368 +  // all subframe navigations, sets the flag to true.
   1.369 +  mShared->mIsFrameNavigation = false;
   1.370 +
   1.371 +  // By default we save LayoutHistoryState
   1.372 +  mShared->mSaveLayoutState = true;
   1.373 +  mShared->mLayoutHistoryState = aLayoutHistoryState;
   1.374 +
   1.375 +  //By default the page is not expired
   1.376 +  mShared->mExpired = false;
   1.377 +
   1.378 +  mIsSrcdocEntry = false;
   1.379 +  mSrcdocData = NullString();
   1.380 +
   1.381 +  return NS_OK;
   1.382 +}
   1.383 +
   1.384 +NS_IMETHODIMP
   1.385 +nsSHEntry::Clone(nsISHEntry ** aResult)
   1.386 +{
   1.387 +  *aResult = new nsSHEntry(*this);
   1.388 +  NS_ADDREF(*aResult);
   1.389 +  return NS_OK;
   1.390 +}
   1.391 +
   1.392 +NS_IMETHODIMP
   1.393 +nsSHEntry::GetParent(nsISHEntry ** aResult)
   1.394 +{
   1.395 +  NS_ENSURE_ARG_POINTER(aResult);
   1.396 +  *aResult = mParent;
   1.397 +  NS_IF_ADDREF(*aResult);
   1.398 +  return NS_OK;
   1.399 +}
   1.400 +
   1.401 +NS_IMETHODIMP
   1.402 +nsSHEntry::SetParent(nsISHEntry * aParent)
   1.403 +{
   1.404 +  /* parent not Addrefed on purpose to avoid cyclic reference
   1.405 +   * Null parent is OK
   1.406 +   *
   1.407 +   * XXX this method should not be scriptable if this is the case!!
   1.408 +   */
   1.409 +  mParent = aParent;
   1.410 +  return NS_OK;
   1.411 +}
   1.412 +
   1.413 +NS_IMETHODIMP
   1.414 +nsSHEntry::SetWindowState(nsISupports *aState)
   1.415 +{
   1.416 +  mShared->mWindowState = aState;
   1.417 +  return NS_OK;
   1.418 +}
   1.419 +
   1.420 +NS_IMETHODIMP
   1.421 +nsSHEntry::GetWindowState(nsISupports **aState)
   1.422 +{
   1.423 +  NS_IF_ADDREF(*aState = mShared->mWindowState);
   1.424 +  return NS_OK;
   1.425 +}
   1.426 +
   1.427 +NS_IMETHODIMP
   1.428 +nsSHEntry::SetViewerBounds(const nsIntRect &aBounds)
   1.429 +{
   1.430 +  mShared->mViewerBounds = aBounds;
   1.431 +  return NS_OK;
   1.432 +}
   1.433 +
   1.434 +NS_IMETHODIMP
   1.435 +nsSHEntry::GetViewerBounds(nsIntRect &aBounds)
   1.436 +{
   1.437 +  aBounds = mShared->mViewerBounds;
   1.438 +  return NS_OK;
   1.439 +}
   1.440 +
   1.441 +NS_IMETHODIMP
   1.442 +nsSHEntry::GetOwner(nsISupports **aOwner)
   1.443 +{
   1.444 +  NS_IF_ADDREF(*aOwner = mShared->mOwner);
   1.445 +  return NS_OK;
   1.446 +}
   1.447 +
   1.448 +NS_IMETHODIMP
   1.449 +nsSHEntry::SetOwner(nsISupports *aOwner)
   1.450 +{
   1.451 +  mShared->mOwner = aOwner;
   1.452 +  return NS_OK;
   1.453 +}
   1.454 +
   1.455 +NS_IMETHODIMP
   1.456 +nsSHEntry::GetBFCacheEntry(nsIBFCacheEntry **aEntry)
   1.457 +{
   1.458 +  NS_ENSURE_ARG_POINTER(aEntry);
   1.459 +  NS_IF_ADDREF(*aEntry = mShared);
   1.460 +  return NS_OK;
   1.461 +}
   1.462 +
   1.463 +bool
   1.464 +nsSHEntry::HasBFCacheEntry(nsIBFCacheEntry *aEntry)
   1.465 +{
   1.466 +  return static_cast<nsIBFCacheEntry*>(mShared) == aEntry;
   1.467 +}
   1.468 +
   1.469 +NS_IMETHODIMP
   1.470 +nsSHEntry::AdoptBFCacheEntry(nsISHEntry *aEntry)
   1.471 +{
   1.472 +  nsCOMPtr<nsISHEntryInternal> shEntry = do_QueryInterface(aEntry);
   1.473 +  NS_ENSURE_STATE(shEntry);
   1.474 +
   1.475 +  nsSHEntryShared *shared = shEntry->GetSharedState();
   1.476 +  NS_ENSURE_STATE(shared);
   1.477 +
   1.478 +  mShared = shared;
   1.479 +  return NS_OK;
   1.480 +}
   1.481 +
   1.482 +NS_IMETHODIMP
   1.483 +nsSHEntry::SharesDocumentWith(nsISHEntry *aEntry, bool *aOut)
   1.484 +{
   1.485 +  NS_ENSURE_ARG_POINTER(aOut);
   1.486 +
   1.487 +  nsCOMPtr<nsISHEntryInternal> internal = do_QueryInterface(aEntry); 
   1.488 +  NS_ENSURE_STATE(internal);
   1.489 +
   1.490 +  *aOut = mShared == internal->GetSharedState();
   1.491 +  return NS_OK;
   1.492 +}
   1.493 +
   1.494 +NS_IMETHODIMP
   1.495 +nsSHEntry::AbandonBFCacheEntry()
   1.496 +{
   1.497 +  mShared = nsSHEntryShared::Duplicate(mShared);
   1.498 +  return NS_OK;
   1.499 +}
   1.500 +
   1.501 +NS_IMETHODIMP
   1.502 +nsSHEntry::GetIsSrcdocEntry(bool* aIsSrcdocEntry)
   1.503 +{
   1.504 +  *aIsSrcdocEntry = mIsSrcdocEntry;
   1.505 +  return NS_OK;
   1.506 +}
   1.507 +
   1.508 +NS_IMETHODIMP
   1.509 +nsSHEntry::GetSrcdocData(nsAString &aSrcdocData)
   1.510 +{
   1.511 +  aSrcdocData = mSrcdocData;
   1.512 +  return NS_OK;
   1.513 +}
   1.514 +
   1.515 +NS_IMETHODIMP
   1.516 +nsSHEntry::SetSrcdocData(const nsAString &aSrcdocData)
   1.517 +{
   1.518 +  mSrcdocData = aSrcdocData;
   1.519 +  mIsSrcdocEntry = true;
   1.520 +  return NS_OK;
   1.521 +}
   1.522 +
   1.523 +NS_IMETHODIMP
   1.524 +nsSHEntry::GetBaseURI(nsIURI **aBaseURI)
   1.525 +{
   1.526 +  *aBaseURI = mBaseURI;
   1.527 +  NS_IF_ADDREF(*aBaseURI);
   1.528 +  return NS_OK;
   1.529 +}
   1.530 +
   1.531 +NS_IMETHODIMP
   1.532 +nsSHEntry::SetBaseURI(nsIURI *aBaseURI)
   1.533 +{
   1.534 +  mBaseURI = aBaseURI;
   1.535 +  return NS_OK;
   1.536 +}
   1.537 +
   1.538 +//*****************************************************************************
   1.539 +//    nsSHEntry: nsISHContainer
   1.540 +//*****************************************************************************
   1.541 +
   1.542 +NS_IMETHODIMP 
   1.543 +nsSHEntry::GetChildCount(int32_t * aCount)
   1.544 +{
   1.545 +  *aCount = mChildren.Count();
   1.546 +  return NS_OK;
   1.547 +}
   1.548 +
   1.549 +NS_IMETHODIMP
   1.550 +nsSHEntry::AddChild(nsISHEntry * aChild, int32_t aOffset)
   1.551 +{
   1.552 +  if (aChild) {
   1.553 +    NS_ENSURE_SUCCESS(aChild->SetParent(this), NS_ERROR_FAILURE);
   1.554 +  }
   1.555 +
   1.556 +  if (aOffset < 0) {
   1.557 +    mChildren.AppendObject(aChild);
   1.558 +    return NS_OK;
   1.559 +  }
   1.560 +
   1.561 +  //
   1.562 +  // Bug 52670: Ensure children are added in order.
   1.563 +  //
   1.564 +  //  Later frames in the child list may load faster and get appended
   1.565 +  //  before earlier frames, causing session history to be scrambled.
   1.566 +  //  By growing the list here, they are added to the right position.
   1.567 +  //
   1.568 +  //  Assert that aOffset will not be so high as to grow us a lot.
   1.569 +  //
   1.570 +  NS_ASSERTION(aOffset < (mChildren.Count()+1023), "Large frames array!\n");
   1.571 +
   1.572 +  bool newChildIsDyn = false;
   1.573 +  if (aChild) {
   1.574 +    aChild->IsDynamicallyAdded(&newChildIsDyn);
   1.575 +  }
   1.576 +
   1.577 +  // If the new child is dynamically added, try to add it to aOffset, but if
   1.578 +  // there are non-dynamically added children, the child must be after those.
   1.579 +  if (newChildIsDyn) {
   1.580 +    int32_t lastNonDyn = aOffset - 1;
   1.581 +    for (int32_t i = aOffset; i < mChildren.Count(); ++i) {
   1.582 +      nsISHEntry* entry = mChildren[i];
   1.583 +      if (entry) {
   1.584 +        bool dyn = false;
   1.585 +        entry->IsDynamicallyAdded(&dyn);
   1.586 +        if (dyn) {
   1.587 +          break;
   1.588 +        } else {
   1.589 +          lastNonDyn = i;
   1.590 +        }
   1.591 +      }
   1.592 +    }
   1.593 +    // InsertObjectAt allows only appending one object.
   1.594 +    // If aOffset is larger than Count(), we must first manually
   1.595 +    // set the capacity.
   1.596 +    if (aOffset > mChildren.Count()) {
   1.597 +      mChildren.SetCount(aOffset);
   1.598 +    }
   1.599 +    if (!mChildren.InsertObjectAt(aChild, lastNonDyn + 1)) {
   1.600 +      NS_WARNING("Adding a child failed!");
   1.601 +      aChild->SetParent(nullptr);
   1.602 +      return NS_ERROR_FAILURE;
   1.603 +    }
   1.604 +  } else {
   1.605 +    // If the new child isn't dynamically added, it should be set to aOffset.
   1.606 +    // If there are dynamically added children before that, those must be
   1.607 +    // moved to be after aOffset.
   1.608 +    if (mChildren.Count() > 0) {
   1.609 +      int32_t start = std::min(mChildren.Count() - 1, aOffset);
   1.610 +      int32_t dynEntryIndex = -1;
   1.611 +      nsISHEntry* dynEntry = nullptr;
   1.612 +      for (int32_t i = start; i >= 0; --i) {
   1.613 +        nsISHEntry* entry = mChildren[i];
   1.614 +        if (entry) {
   1.615 +          bool dyn = false;
   1.616 +          entry->IsDynamicallyAdded(&dyn);
   1.617 +          if (dyn) {
   1.618 +            dynEntryIndex = i;
   1.619 +            dynEntry = entry;
   1.620 +          } else {
   1.621 +            break;
   1.622 +          }
   1.623 +        }
   1.624 +      }
   1.625 +  
   1.626 +      if (dynEntry) {
   1.627 +        nsCOMArray<nsISHEntry> tmp;
   1.628 +        tmp.SetCount(aOffset - dynEntryIndex + 1);
   1.629 +        mChildren.InsertObjectsAt(tmp, dynEntryIndex);
   1.630 +        NS_ASSERTION(mChildren[aOffset + 1] == dynEntry, "Whaat?");
   1.631 +      }
   1.632 +    }
   1.633 +    
   1.634 +
   1.635 +    // Make sure there isn't anything at aOffset.
   1.636 +    if (aOffset < mChildren.Count()) {
   1.637 +      nsISHEntry* oldChild = mChildren[aOffset];
   1.638 +      if (oldChild && oldChild != aChild) {
   1.639 +        NS_ERROR("Adding a child where we already have a child? This may misbehave");
   1.640 +        oldChild->SetParent(nullptr);
   1.641 +      }
   1.642 +    }
   1.643 +
   1.644 +    if (!mChildren.ReplaceObjectAt(aChild, aOffset)) {
   1.645 +      NS_WARNING("Adding a child failed!");
   1.646 +      aChild->SetParent(nullptr);
   1.647 +      return NS_ERROR_FAILURE;
   1.648 +    }
   1.649 +  }
   1.650 +
   1.651 +  return NS_OK;
   1.652 +}
   1.653 +
   1.654 +NS_IMETHODIMP
   1.655 +nsSHEntry::RemoveChild(nsISHEntry * aChild)
   1.656 +{
   1.657 +  NS_ENSURE_TRUE(aChild, NS_ERROR_FAILURE);
   1.658 +  bool childRemoved = false;
   1.659 +  bool dynamic = false;
   1.660 +  aChild->IsDynamicallyAdded(&dynamic);
   1.661 +  if (dynamic) {
   1.662 +    childRemoved = mChildren.RemoveObject(aChild);
   1.663 +  } else {
   1.664 +    int32_t index = mChildren.IndexOfObject(aChild);
   1.665 +    if (index >= 0) {
   1.666 +      childRemoved = mChildren.ReplaceObjectAt(nullptr, index);
   1.667 +    }
   1.668 +  }
   1.669 +  if (childRemoved) {
   1.670 +    aChild->SetParent(nullptr);
   1.671 +
   1.672 +    // reduce the child count, i.e. remove empty children at the end
   1.673 +    for (int32_t i = mChildren.Count() - 1; i >= 0 && !mChildren[i]; --i) {
   1.674 +      if (!mChildren.RemoveObjectAt(i)) {
   1.675 +        break;
   1.676 +      }
   1.677 +    }
   1.678 +  }
   1.679 +  return NS_OK;
   1.680 +}
   1.681 +
   1.682 +NS_IMETHODIMP
   1.683 +nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry ** aResult)
   1.684 +{
   1.685 +  if (aIndex >= 0 && aIndex < mChildren.Count()) {
   1.686 +    *aResult = mChildren[aIndex];
   1.687 +    // yes, mChildren can have holes in it.  AddChild's offset parameter makes
   1.688 +    // that possible.
   1.689 +    NS_IF_ADDREF(*aResult);
   1.690 +  } else {
   1.691 +    *aResult = nullptr;
   1.692 +  }
   1.693 +  return NS_OK;
   1.694 +}
   1.695 +
   1.696 +NS_IMETHODIMP
   1.697 +nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell)
   1.698 +{
   1.699 +  NS_ASSERTION(aShell, "Null child shell added to history entry");
   1.700 +  mShared->mChildShells.AppendObject(aShell);
   1.701 +  return NS_OK;
   1.702 +}
   1.703 +
   1.704 +NS_IMETHODIMP
   1.705 +nsSHEntry::ChildShellAt(int32_t aIndex, nsIDocShellTreeItem **aShell)
   1.706 +{
   1.707 +  NS_IF_ADDREF(*aShell = mShared->mChildShells.SafeObjectAt(aIndex));
   1.708 +  return NS_OK;
   1.709 +}
   1.710 +
   1.711 +NS_IMETHODIMP
   1.712 +nsSHEntry::ClearChildShells()
   1.713 +{
   1.714 +  mShared->mChildShells.Clear();
   1.715 +  return NS_OK;
   1.716 +}
   1.717 +
   1.718 +NS_IMETHODIMP
   1.719 +nsSHEntry::GetRefreshURIList(nsISupportsArray **aList)
   1.720 +{
   1.721 +  NS_IF_ADDREF(*aList = mShared->mRefreshURIList);
   1.722 +  return NS_OK;
   1.723 +}
   1.724 +
   1.725 +NS_IMETHODIMP
   1.726 +nsSHEntry::SetRefreshURIList(nsISupportsArray *aList)
   1.727 +{
   1.728 +  mShared->mRefreshURIList = aList;
   1.729 +  return NS_OK;
   1.730 +}
   1.731 +
   1.732 +NS_IMETHODIMP
   1.733 +nsSHEntry::SyncPresentationState()
   1.734 +{
   1.735 +  return mShared->SyncPresentationState();
   1.736 +}
   1.737 +
   1.738 +void
   1.739 +nsSHEntry::RemoveFromBFCacheSync()
   1.740 +{
   1.741 +  mShared->RemoveFromBFCacheSync();
   1.742 +}
   1.743 +
   1.744 +void
   1.745 +nsSHEntry::RemoveFromBFCacheAsync()
   1.746 +{
   1.747 +  mShared->RemoveFromBFCacheAsync();
   1.748 +}
   1.749 +
   1.750 +nsDocShellEditorData*
   1.751 +nsSHEntry::ForgetEditorData()
   1.752 +{
   1.753 +  // XXX jlebar Check how this is used.
   1.754 +  return mShared->mEditorData.forget();
   1.755 +}
   1.756 +
   1.757 +void
   1.758 +nsSHEntry::SetEditorData(nsDocShellEditorData* aData)
   1.759 +{
   1.760 +  NS_ASSERTION(!(aData && mShared->mEditorData),
   1.761 +               "We're going to overwrite an owning ref!");
   1.762 +  if (mShared->mEditorData != aData) {
   1.763 +    mShared->mEditorData = aData;
   1.764 +  }
   1.765 +}
   1.766 +
   1.767 +bool
   1.768 +nsSHEntry::HasDetachedEditor()
   1.769 +{
   1.770 +  return mShared->mEditorData != nullptr;
   1.771 +}
   1.772 +
   1.773 +NS_IMETHODIMP
   1.774 +nsSHEntry::GetStateData(nsIStructuredCloneContainer **aContainer)
   1.775 +{
   1.776 +  NS_ENSURE_ARG_POINTER(aContainer);
   1.777 +  NS_IF_ADDREF(*aContainer = mStateData);
   1.778 +  return NS_OK;
   1.779 +}
   1.780 +
   1.781 +NS_IMETHODIMP
   1.782 +nsSHEntry::SetStateData(nsIStructuredCloneContainer *aContainer)
   1.783 +{
   1.784 +  mStateData = aContainer;
   1.785 +  return NS_OK;
   1.786 +}
   1.787 +
   1.788 +NS_IMETHODIMP
   1.789 +nsSHEntry::IsDynamicallyAdded(bool* aAdded)
   1.790 +{
   1.791 +  *aAdded = mShared->mDynamicallyCreated;
   1.792 +  return NS_OK;
   1.793 +}
   1.794 +
   1.795 +NS_IMETHODIMP
   1.796 +nsSHEntry::HasDynamicallyAddedChild(bool* aAdded)
   1.797 +{
   1.798 +  *aAdded = false;
   1.799 +  for (int32_t i = 0; i < mChildren.Count(); ++i) {
   1.800 +    nsISHEntry* entry = mChildren[i];
   1.801 +    if (entry) {
   1.802 +      entry->IsDynamicallyAdded(aAdded);
   1.803 +      if (*aAdded) {
   1.804 +        break;
   1.805 +      }
   1.806 +    }
   1.807 +  }
   1.808 +  return NS_OK;
   1.809 +}
   1.810 +
   1.811 +NS_IMETHODIMP
   1.812 +nsSHEntry::GetDocshellID(uint64_t* aID)
   1.813 +{
   1.814 +  *aID = mShared->mDocShellID;
   1.815 +  return NS_OK;
   1.816 +}
   1.817 +
   1.818 +NS_IMETHODIMP
   1.819 +nsSHEntry::SetDocshellID(uint64_t aID)
   1.820 +{
   1.821 +  mShared->mDocShellID = aID;
   1.822 +  return NS_OK;
   1.823 +}
   1.824 +
   1.825 +
   1.826 +NS_IMETHODIMP
   1.827 +nsSHEntry::GetLastTouched(uint32_t *aLastTouched)
   1.828 +{
   1.829 +  *aLastTouched = mShared->mLastTouched;
   1.830 +  return NS_OK;
   1.831 +}
   1.832 +
   1.833 +NS_IMETHODIMP
   1.834 +nsSHEntry::SetLastTouched(uint32_t aLastTouched)
   1.835 +{
   1.836 +  mShared->mLastTouched = aLastTouched;
   1.837 +  return NS_OK;
   1.838 +}

mercurial