docshell/shistory/src/nsSHEntryShared.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/docshell/shistory/src/nsSHEntryShared.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,368 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "nsSHEntryShared.h"
     1.9 +
    1.10 +#include "nsIDOMDocument.h"
    1.11 +#include "nsISHistory.h"
    1.12 +#include "nsISHistoryInternal.h"
    1.13 +#include "nsIDocument.h"
    1.14 +#include "nsIWebNavigation.h"
    1.15 +#include "nsIContentViewer.h"
    1.16 +#include "nsIDocShell.h"
    1.17 +#include "nsIDocShellTreeItem.h"
    1.18 +#include "nsDocShellEditorData.h"
    1.19 +#include "nsThreadUtils.h"
    1.20 +#include "nsILayoutHistoryState.h"
    1.21 +#include "mozilla/Attributes.h"
    1.22 +#include "nsISupportsArray.h"
    1.23 +
    1.24 +namespace dom = mozilla::dom;
    1.25 +
    1.26 +namespace {
    1.27 +
    1.28 +uint64_t gSHEntrySharedID = 0;
    1.29 +
    1.30 +} // anonymous namespace
    1.31 +
    1.32 +// Hardcode this to time out unused content viewers after 30 minutes
    1.33 +// XXX jlebar shouldn't this be a pref?
    1.34 +#define CONTENT_VIEWER_TIMEOUT_SECONDS (30*60)
    1.35 +
    1.36 +typedef nsExpirationTracker<nsSHEntryShared, 3> HistoryTrackerBase;
    1.37 +class HistoryTracker MOZ_FINAL : public HistoryTrackerBase {
    1.38 +public:
    1.39 +  // Expire cached contentviewers after 20-30 minutes in the cache.
    1.40 +  HistoryTracker() 
    1.41 +    : HistoryTrackerBase(1000 * CONTENT_VIEWER_TIMEOUT_SECONDS / 2)
    1.42 +  {
    1.43 +  }
    1.44 +  
    1.45 +protected:
    1.46 +  virtual void NotifyExpired(nsSHEntryShared *aObj) {
    1.47 +    RemoveObject(aObj);
    1.48 +    aObj->Expire();
    1.49 +  }
    1.50 +};
    1.51 +
    1.52 +static HistoryTracker *gHistoryTracker = nullptr;
    1.53 +
    1.54 +void
    1.55 +nsSHEntryShared::Startup()
    1.56 +{
    1.57 +  gHistoryTracker = new HistoryTracker();
    1.58 +}
    1.59 +
    1.60 +void
    1.61 +nsSHEntryShared::Shutdown()
    1.62 +{
    1.63 +  delete gHistoryTracker;
    1.64 +  gHistoryTracker = nullptr;
    1.65 +}
    1.66 +
    1.67 +nsSHEntryShared::nsSHEntryShared()
    1.68 +  : mDocShellID(0)
    1.69 +  , mIsFrameNavigation(false)
    1.70 +  , mSaveLayoutState(true)
    1.71 +  , mSticky(true)
    1.72 +  , mDynamicallyCreated(false)
    1.73 +  , mLastTouched(0)
    1.74 +  , mID(gSHEntrySharedID++)
    1.75 +  , mExpired(false)
    1.76 +  , mViewerBounds(0, 0, 0, 0)
    1.77 +{
    1.78 +}
    1.79 +
    1.80 +nsSHEntryShared::~nsSHEntryShared()
    1.81 +{
    1.82 +  RemoveFromExpirationTracker();
    1.83 +
    1.84 +#ifdef DEBUG
    1.85 +  // Check that we're not still on track to expire.  We shouldn't be, because
    1.86 +  // we just removed ourselves!
    1.87 +  nsExpirationTracker<nsSHEntryShared, 3>::Iterator
    1.88 +    iterator(gHistoryTracker);
    1.89 +
    1.90 +  nsSHEntryShared *elem;
    1.91 +  while ((elem = iterator.Next()) != nullptr) {
    1.92 +    NS_ASSERTION(elem != this, "Found dead entry still in the tracker!");
    1.93 +  }
    1.94 +#endif
    1.95 +
    1.96 +  if (mContentViewer) {
    1.97 +    RemoveFromBFCacheSync();
    1.98 +  }
    1.99 +}
   1.100 +
   1.101 +NS_IMPL_ISUPPORTS(nsSHEntryShared, nsIBFCacheEntry, nsIMutationObserver)
   1.102 +
   1.103 +already_AddRefed<nsSHEntryShared>
   1.104 +nsSHEntryShared::Duplicate(nsSHEntryShared *aEntry)
   1.105 +{
   1.106 +  nsRefPtr<nsSHEntryShared> newEntry = new nsSHEntryShared();
   1.107 +
   1.108 +  newEntry->mDocShellID = aEntry->mDocShellID;
   1.109 +  newEntry->mChildShells.AppendObjects(aEntry->mChildShells);
   1.110 +  newEntry->mOwner = aEntry->mOwner;
   1.111 +  newEntry->mContentType.Assign(aEntry->mContentType);
   1.112 +  newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation;
   1.113 +  newEntry->mSaveLayoutState = aEntry->mSaveLayoutState;
   1.114 +  newEntry->mSticky = aEntry->mSticky;
   1.115 +  newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated;
   1.116 +  newEntry->mCacheKey = aEntry->mCacheKey;
   1.117 +  newEntry->mLastTouched = aEntry->mLastTouched;
   1.118 +
   1.119 +  return newEntry.forget();
   1.120 +}
   1.121 +
   1.122 +void nsSHEntryShared::RemoveFromExpirationTracker()
   1.123 +{
   1.124 +  if (GetExpirationState()->IsTracked()) {
   1.125 +    gHistoryTracker->RemoveObject(this);
   1.126 +  }
   1.127 +}
   1.128 +
   1.129 +nsresult
   1.130 +nsSHEntryShared::SyncPresentationState()
   1.131 +{
   1.132 +  if (mContentViewer && mWindowState) {
   1.133 +    // If we have a content viewer and a window state, we should be ok.
   1.134 +    return NS_OK;
   1.135 +  }
   1.136 +
   1.137 +  DropPresentationState();
   1.138 +
   1.139 +  return NS_OK;
   1.140 +}
   1.141 +
   1.142 +void
   1.143 +nsSHEntryShared::DropPresentationState()
   1.144 +{
   1.145 +  nsRefPtr<nsSHEntryShared> kungFuDeathGrip = this;
   1.146 +
   1.147 +  if (mDocument) {
   1.148 +    mDocument->SetBFCacheEntry(nullptr);
   1.149 +    mDocument->RemoveMutationObserver(this);
   1.150 +    mDocument = nullptr;
   1.151 +  }
   1.152 +  if (mContentViewer) {
   1.153 +    mContentViewer->ClearHistoryEntry();
   1.154 +  }
   1.155 +
   1.156 +  RemoveFromExpirationTracker();
   1.157 +  mContentViewer = nullptr;
   1.158 +  mSticky = true;
   1.159 +  mWindowState = nullptr;
   1.160 +  mViewerBounds.SetRect(0, 0, 0, 0);
   1.161 +  mChildShells.Clear();
   1.162 +  mRefreshURIList = nullptr;
   1.163 +  mEditorData = nullptr;
   1.164 +}
   1.165 +
   1.166 +void
   1.167 +nsSHEntryShared::Expire()
   1.168 +{
   1.169 +  // This entry has timed out. If we still have a content viewer, we need to
   1.170 +  // evict it.
   1.171 +  if (!mContentViewer) {
   1.172 +    return;
   1.173 +  }
   1.174 +  nsCOMPtr<nsIDocShell> container;
   1.175 +  mContentViewer->GetContainer(getter_AddRefs(container));
   1.176 +  nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
   1.177 +  if (!treeItem) {
   1.178 +    return;
   1.179 +  }
   1.180 +  // We need to find the root DocShell since only that object has an
   1.181 +  // SHistory and we need the SHistory to evict content viewers
   1.182 +  nsCOMPtr<nsIDocShellTreeItem> root;
   1.183 +  treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
   1.184 +  nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
   1.185 +  nsCOMPtr<nsISHistory> history;
   1.186 +  webNav->GetSessionHistory(getter_AddRefs(history));
   1.187 +  nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
   1.188 +  if (!historyInt) {
   1.189 +    return;
   1.190 +  }
   1.191 +  historyInt->EvictExpiredContentViewerForEntry(this);
   1.192 +}
   1.193 +
   1.194 +nsresult
   1.195 +nsSHEntryShared::SetContentViewer(nsIContentViewer *aViewer)
   1.196 +{
   1.197 +  NS_PRECONDITION(!aViewer || !mContentViewer,
   1.198 +                  "SHEntryShared already contains viewer");
   1.199 +
   1.200 +  if (mContentViewer || !aViewer) {
   1.201 +    DropPresentationState();
   1.202 +  }
   1.203 +
   1.204 +  mContentViewer = aViewer;
   1.205 +
   1.206 +  if (mContentViewer) {
   1.207 +    gHistoryTracker->AddObject(this);
   1.208 +
   1.209 +    nsCOMPtr<nsIDOMDocument> domDoc;
   1.210 +    mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
   1.211 +    // Store observed document in strong pointer in case it is removed from
   1.212 +    // the contentviewer
   1.213 +    mDocument = do_QueryInterface(domDoc);
   1.214 +    if (mDocument) {
   1.215 +      mDocument->SetBFCacheEntry(this);
   1.216 +      mDocument->AddMutationObserver(this);
   1.217 +    }
   1.218 +  }
   1.219 +
   1.220 +  return NS_OK;
   1.221 +}
   1.222 +
   1.223 +nsresult
   1.224 +nsSHEntryShared::RemoveFromBFCacheSync()
   1.225 +{
   1.226 +  NS_ASSERTION(mContentViewer && mDocument,
   1.227 +               "we're not in the bfcache!");
   1.228 +
   1.229 +  nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
   1.230 +  DropPresentationState();
   1.231 +
   1.232 +  // Warning! The call to DropPresentationState could have dropped the last
   1.233 +  // reference to this object, so don't access members beyond here.
   1.234 +
   1.235 +  if (viewer) {
   1.236 +    viewer->Destroy();
   1.237 +  }
   1.238 +
   1.239 +  return NS_OK;
   1.240 +}
   1.241 +
   1.242 +class DestroyViewerEvent : public nsRunnable
   1.243 +{
   1.244 +public:
   1.245 +  DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument)
   1.246 +    : mViewer(aViewer),
   1.247 +      mDocument(aDocument)
   1.248 +  {}
   1.249 +
   1.250 +  NS_IMETHOD Run()
   1.251 +  {
   1.252 +    if (mViewer) {
   1.253 +      mViewer->Destroy();
   1.254 +    }
   1.255 +    return NS_OK;
   1.256 +  }
   1.257 +
   1.258 +  nsCOMPtr<nsIContentViewer> mViewer;
   1.259 +  nsCOMPtr<nsIDocument> mDocument;
   1.260 +};
   1.261 +
   1.262 +nsresult
   1.263 +nsSHEntryShared::RemoveFromBFCacheAsync()
   1.264 +{
   1.265 +  NS_ASSERTION(mContentViewer && mDocument,
   1.266 +               "we're not in the bfcache!");
   1.267 +
   1.268 +  // Release the reference to the contentviewer asynchronously so that the
   1.269 +  // document doesn't get nuked mid-mutation.
   1.270 +
   1.271 +  nsCOMPtr<nsIRunnable> evt =
   1.272 +    new DestroyViewerEvent(mContentViewer, mDocument);
   1.273 +  nsresult rv = NS_DispatchToCurrentThread(evt);
   1.274 +  if (NS_FAILED(rv)) {
   1.275 +    NS_WARNING("failed to dispatch DestroyViewerEvent");
   1.276 +  } else {
   1.277 +    // Drop presentation. Only do this if we succeeded in posting the event
   1.278 +    // since otherwise the document could be torn down mid-mutation, causing
   1.279 +    // crashes.
   1.280 +    DropPresentationState();
   1.281 +  }
   1.282 +
   1.283 +  // Careful! The call to DropPresentationState could have dropped the last
   1.284 +  // reference to this nsSHEntryShared, so don't access members beyond here.
   1.285 +
   1.286 +  return NS_OK;
   1.287 +}
   1.288 +
   1.289 +nsresult
   1.290 +nsSHEntryShared::GetID(uint64_t *aID)
   1.291 +{
   1.292 +  *aID = mID;
   1.293 +  return NS_OK;
   1.294 +}
   1.295 +
   1.296 +//*****************************************************************************
   1.297 +//    nsSHEntryShared: nsIMutationObserver
   1.298 +//*****************************************************************************
   1.299 +
   1.300 +void
   1.301 +nsSHEntryShared::NodeWillBeDestroyed(const nsINode* aNode)
   1.302 +{
   1.303 +  NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
   1.304 +}
   1.305 +
   1.306 +void
   1.307 +nsSHEntryShared::CharacterDataWillChange(nsIDocument* aDocument,
   1.308 +                                         nsIContent* aContent,
   1.309 +                                         CharacterDataChangeInfo* aInfo)
   1.310 +{
   1.311 +}
   1.312 +
   1.313 +void
   1.314 +nsSHEntryShared::CharacterDataChanged(nsIDocument* aDocument,
   1.315 +                                      nsIContent* aContent,
   1.316 +                                      CharacterDataChangeInfo* aInfo)
   1.317 +{
   1.318 +  RemoveFromBFCacheAsync();
   1.319 +}
   1.320 +
   1.321 +void
   1.322 +nsSHEntryShared::AttributeWillChange(nsIDocument* aDocument,
   1.323 +                                     dom::Element* aContent,
   1.324 +                                     int32_t aNameSpaceID,
   1.325 +                                     nsIAtom* aAttribute,
   1.326 +                                     int32_t aModType)
   1.327 +{
   1.328 +}
   1.329 +
   1.330 +void
   1.331 +nsSHEntryShared::AttributeChanged(nsIDocument* aDocument,
   1.332 +                                  dom::Element* aElement,
   1.333 +                                  int32_t aNameSpaceID,
   1.334 +                                  nsIAtom* aAttribute,
   1.335 +                                  int32_t aModType)
   1.336 +{
   1.337 +  RemoveFromBFCacheAsync();
   1.338 +}
   1.339 +
   1.340 +void
   1.341 +nsSHEntryShared::ContentAppended(nsIDocument* aDocument,
   1.342 +                                 nsIContent* aContainer,
   1.343 +                                 nsIContent* aFirstNewContent,
   1.344 +                                 int32_t /* unused */)
   1.345 +{
   1.346 +  RemoveFromBFCacheAsync();
   1.347 +}
   1.348 +
   1.349 +void
   1.350 +nsSHEntryShared::ContentInserted(nsIDocument* aDocument,
   1.351 +                                 nsIContent* aContainer,
   1.352 +                                 nsIContent* aChild,
   1.353 +                                 int32_t /* unused */)
   1.354 +{
   1.355 +  RemoveFromBFCacheAsync();
   1.356 +}
   1.357 +
   1.358 +void
   1.359 +nsSHEntryShared::ContentRemoved(nsIDocument* aDocument,
   1.360 +                                nsIContent* aContainer,
   1.361 +                                nsIContent* aChild,
   1.362 +                                int32_t aIndexInContainer,
   1.363 +                                nsIContent* aPreviousSibling)
   1.364 +{
   1.365 +  RemoveFromBFCacheAsync();
   1.366 +}
   1.367 +
   1.368 +void
   1.369 +nsSHEntryShared::ParentChainChanged(nsIContent *aContent)
   1.370 +{
   1.371 +}

mercurial