docshell/shistory/src/nsSHEntryShared.cpp

Wed, 31 Dec 2014 07:53:36 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:53:36 +0100
branch
TOR_BUG_3246
changeset 5
4ab42b5ab56c
permissions
-rw-r--r--

Correct small whitespace inconsistency, lost while renaming variables.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "nsSHEntryShared.h"
michael@0 6
michael@0 7 #include "nsIDOMDocument.h"
michael@0 8 #include "nsISHistory.h"
michael@0 9 #include "nsISHistoryInternal.h"
michael@0 10 #include "nsIDocument.h"
michael@0 11 #include "nsIWebNavigation.h"
michael@0 12 #include "nsIContentViewer.h"
michael@0 13 #include "nsIDocShell.h"
michael@0 14 #include "nsIDocShellTreeItem.h"
michael@0 15 #include "nsDocShellEditorData.h"
michael@0 16 #include "nsThreadUtils.h"
michael@0 17 #include "nsILayoutHistoryState.h"
michael@0 18 #include "mozilla/Attributes.h"
michael@0 19 #include "nsISupportsArray.h"
michael@0 20
michael@0 21 namespace dom = mozilla::dom;
michael@0 22
michael@0 23 namespace {
michael@0 24
michael@0 25 uint64_t gSHEntrySharedID = 0;
michael@0 26
michael@0 27 } // anonymous namespace
michael@0 28
michael@0 29 // Hardcode this to time out unused content viewers after 30 minutes
michael@0 30 // XXX jlebar shouldn't this be a pref?
michael@0 31 #define CONTENT_VIEWER_TIMEOUT_SECONDS (30*60)
michael@0 32
michael@0 33 typedef nsExpirationTracker<nsSHEntryShared, 3> HistoryTrackerBase;
michael@0 34 class HistoryTracker MOZ_FINAL : public HistoryTrackerBase {
michael@0 35 public:
michael@0 36 // Expire cached contentviewers after 20-30 minutes in the cache.
michael@0 37 HistoryTracker()
michael@0 38 : HistoryTrackerBase(1000 * CONTENT_VIEWER_TIMEOUT_SECONDS / 2)
michael@0 39 {
michael@0 40 }
michael@0 41
michael@0 42 protected:
michael@0 43 virtual void NotifyExpired(nsSHEntryShared *aObj) {
michael@0 44 RemoveObject(aObj);
michael@0 45 aObj->Expire();
michael@0 46 }
michael@0 47 };
michael@0 48
michael@0 49 static HistoryTracker *gHistoryTracker = nullptr;
michael@0 50
michael@0 51 void
michael@0 52 nsSHEntryShared::Startup()
michael@0 53 {
michael@0 54 gHistoryTracker = new HistoryTracker();
michael@0 55 }
michael@0 56
michael@0 57 void
michael@0 58 nsSHEntryShared::Shutdown()
michael@0 59 {
michael@0 60 delete gHistoryTracker;
michael@0 61 gHistoryTracker = nullptr;
michael@0 62 }
michael@0 63
michael@0 64 nsSHEntryShared::nsSHEntryShared()
michael@0 65 : mDocShellID(0)
michael@0 66 , mIsFrameNavigation(false)
michael@0 67 , mSaveLayoutState(true)
michael@0 68 , mSticky(true)
michael@0 69 , mDynamicallyCreated(false)
michael@0 70 , mLastTouched(0)
michael@0 71 , mID(gSHEntrySharedID++)
michael@0 72 , mExpired(false)
michael@0 73 , mViewerBounds(0, 0, 0, 0)
michael@0 74 {
michael@0 75 }
michael@0 76
michael@0 77 nsSHEntryShared::~nsSHEntryShared()
michael@0 78 {
michael@0 79 RemoveFromExpirationTracker();
michael@0 80
michael@0 81 #ifdef DEBUG
michael@0 82 // Check that we're not still on track to expire. We shouldn't be, because
michael@0 83 // we just removed ourselves!
michael@0 84 nsExpirationTracker<nsSHEntryShared, 3>::Iterator
michael@0 85 iterator(gHistoryTracker);
michael@0 86
michael@0 87 nsSHEntryShared *elem;
michael@0 88 while ((elem = iterator.Next()) != nullptr) {
michael@0 89 NS_ASSERTION(elem != this, "Found dead entry still in the tracker!");
michael@0 90 }
michael@0 91 #endif
michael@0 92
michael@0 93 if (mContentViewer) {
michael@0 94 RemoveFromBFCacheSync();
michael@0 95 }
michael@0 96 }
michael@0 97
michael@0 98 NS_IMPL_ISUPPORTS(nsSHEntryShared, nsIBFCacheEntry, nsIMutationObserver)
michael@0 99
michael@0 100 already_AddRefed<nsSHEntryShared>
michael@0 101 nsSHEntryShared::Duplicate(nsSHEntryShared *aEntry)
michael@0 102 {
michael@0 103 nsRefPtr<nsSHEntryShared> newEntry = new nsSHEntryShared();
michael@0 104
michael@0 105 newEntry->mDocShellID = aEntry->mDocShellID;
michael@0 106 newEntry->mChildShells.AppendObjects(aEntry->mChildShells);
michael@0 107 newEntry->mOwner = aEntry->mOwner;
michael@0 108 newEntry->mContentType.Assign(aEntry->mContentType);
michael@0 109 newEntry->mIsFrameNavigation = aEntry->mIsFrameNavigation;
michael@0 110 newEntry->mSaveLayoutState = aEntry->mSaveLayoutState;
michael@0 111 newEntry->mSticky = aEntry->mSticky;
michael@0 112 newEntry->mDynamicallyCreated = aEntry->mDynamicallyCreated;
michael@0 113 newEntry->mCacheKey = aEntry->mCacheKey;
michael@0 114 newEntry->mLastTouched = aEntry->mLastTouched;
michael@0 115
michael@0 116 return newEntry.forget();
michael@0 117 }
michael@0 118
michael@0 119 void nsSHEntryShared::RemoveFromExpirationTracker()
michael@0 120 {
michael@0 121 if (GetExpirationState()->IsTracked()) {
michael@0 122 gHistoryTracker->RemoveObject(this);
michael@0 123 }
michael@0 124 }
michael@0 125
michael@0 126 nsresult
michael@0 127 nsSHEntryShared::SyncPresentationState()
michael@0 128 {
michael@0 129 if (mContentViewer && mWindowState) {
michael@0 130 // If we have a content viewer and a window state, we should be ok.
michael@0 131 return NS_OK;
michael@0 132 }
michael@0 133
michael@0 134 DropPresentationState();
michael@0 135
michael@0 136 return NS_OK;
michael@0 137 }
michael@0 138
michael@0 139 void
michael@0 140 nsSHEntryShared::DropPresentationState()
michael@0 141 {
michael@0 142 nsRefPtr<nsSHEntryShared> kungFuDeathGrip = this;
michael@0 143
michael@0 144 if (mDocument) {
michael@0 145 mDocument->SetBFCacheEntry(nullptr);
michael@0 146 mDocument->RemoveMutationObserver(this);
michael@0 147 mDocument = nullptr;
michael@0 148 }
michael@0 149 if (mContentViewer) {
michael@0 150 mContentViewer->ClearHistoryEntry();
michael@0 151 }
michael@0 152
michael@0 153 RemoveFromExpirationTracker();
michael@0 154 mContentViewer = nullptr;
michael@0 155 mSticky = true;
michael@0 156 mWindowState = nullptr;
michael@0 157 mViewerBounds.SetRect(0, 0, 0, 0);
michael@0 158 mChildShells.Clear();
michael@0 159 mRefreshURIList = nullptr;
michael@0 160 mEditorData = nullptr;
michael@0 161 }
michael@0 162
michael@0 163 void
michael@0 164 nsSHEntryShared::Expire()
michael@0 165 {
michael@0 166 // This entry has timed out. If we still have a content viewer, we need to
michael@0 167 // evict it.
michael@0 168 if (!mContentViewer) {
michael@0 169 return;
michael@0 170 }
michael@0 171 nsCOMPtr<nsIDocShell> container;
michael@0 172 mContentViewer->GetContainer(getter_AddRefs(container));
michael@0 173 nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
michael@0 174 if (!treeItem) {
michael@0 175 return;
michael@0 176 }
michael@0 177 // We need to find the root DocShell since only that object has an
michael@0 178 // SHistory and we need the SHistory to evict content viewers
michael@0 179 nsCOMPtr<nsIDocShellTreeItem> root;
michael@0 180 treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
michael@0 181 nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
michael@0 182 nsCOMPtr<nsISHistory> history;
michael@0 183 webNav->GetSessionHistory(getter_AddRefs(history));
michael@0 184 nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
michael@0 185 if (!historyInt) {
michael@0 186 return;
michael@0 187 }
michael@0 188 historyInt->EvictExpiredContentViewerForEntry(this);
michael@0 189 }
michael@0 190
michael@0 191 nsresult
michael@0 192 nsSHEntryShared::SetContentViewer(nsIContentViewer *aViewer)
michael@0 193 {
michael@0 194 NS_PRECONDITION(!aViewer || !mContentViewer,
michael@0 195 "SHEntryShared already contains viewer");
michael@0 196
michael@0 197 if (mContentViewer || !aViewer) {
michael@0 198 DropPresentationState();
michael@0 199 }
michael@0 200
michael@0 201 mContentViewer = aViewer;
michael@0 202
michael@0 203 if (mContentViewer) {
michael@0 204 gHistoryTracker->AddObject(this);
michael@0 205
michael@0 206 nsCOMPtr<nsIDOMDocument> domDoc;
michael@0 207 mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
michael@0 208 // Store observed document in strong pointer in case it is removed from
michael@0 209 // the contentviewer
michael@0 210 mDocument = do_QueryInterface(domDoc);
michael@0 211 if (mDocument) {
michael@0 212 mDocument->SetBFCacheEntry(this);
michael@0 213 mDocument->AddMutationObserver(this);
michael@0 214 }
michael@0 215 }
michael@0 216
michael@0 217 return NS_OK;
michael@0 218 }
michael@0 219
michael@0 220 nsresult
michael@0 221 nsSHEntryShared::RemoveFromBFCacheSync()
michael@0 222 {
michael@0 223 NS_ASSERTION(mContentViewer && mDocument,
michael@0 224 "we're not in the bfcache!");
michael@0 225
michael@0 226 nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
michael@0 227 DropPresentationState();
michael@0 228
michael@0 229 // Warning! The call to DropPresentationState could have dropped the last
michael@0 230 // reference to this object, so don't access members beyond here.
michael@0 231
michael@0 232 if (viewer) {
michael@0 233 viewer->Destroy();
michael@0 234 }
michael@0 235
michael@0 236 return NS_OK;
michael@0 237 }
michael@0 238
michael@0 239 class DestroyViewerEvent : public nsRunnable
michael@0 240 {
michael@0 241 public:
michael@0 242 DestroyViewerEvent(nsIContentViewer* aViewer, nsIDocument* aDocument)
michael@0 243 : mViewer(aViewer),
michael@0 244 mDocument(aDocument)
michael@0 245 {}
michael@0 246
michael@0 247 NS_IMETHOD Run()
michael@0 248 {
michael@0 249 if (mViewer) {
michael@0 250 mViewer->Destroy();
michael@0 251 }
michael@0 252 return NS_OK;
michael@0 253 }
michael@0 254
michael@0 255 nsCOMPtr<nsIContentViewer> mViewer;
michael@0 256 nsCOMPtr<nsIDocument> mDocument;
michael@0 257 };
michael@0 258
michael@0 259 nsresult
michael@0 260 nsSHEntryShared::RemoveFromBFCacheAsync()
michael@0 261 {
michael@0 262 NS_ASSERTION(mContentViewer && mDocument,
michael@0 263 "we're not in the bfcache!");
michael@0 264
michael@0 265 // Release the reference to the contentviewer asynchronously so that the
michael@0 266 // document doesn't get nuked mid-mutation.
michael@0 267
michael@0 268 nsCOMPtr<nsIRunnable> evt =
michael@0 269 new DestroyViewerEvent(mContentViewer, mDocument);
michael@0 270 nsresult rv = NS_DispatchToCurrentThread(evt);
michael@0 271 if (NS_FAILED(rv)) {
michael@0 272 NS_WARNING("failed to dispatch DestroyViewerEvent");
michael@0 273 } else {
michael@0 274 // Drop presentation. Only do this if we succeeded in posting the event
michael@0 275 // since otherwise the document could be torn down mid-mutation, causing
michael@0 276 // crashes.
michael@0 277 DropPresentationState();
michael@0 278 }
michael@0 279
michael@0 280 // Careful! The call to DropPresentationState could have dropped the last
michael@0 281 // reference to this nsSHEntryShared, so don't access members beyond here.
michael@0 282
michael@0 283 return NS_OK;
michael@0 284 }
michael@0 285
michael@0 286 nsresult
michael@0 287 nsSHEntryShared::GetID(uint64_t *aID)
michael@0 288 {
michael@0 289 *aID = mID;
michael@0 290 return NS_OK;
michael@0 291 }
michael@0 292
michael@0 293 //*****************************************************************************
michael@0 294 // nsSHEntryShared: nsIMutationObserver
michael@0 295 //*****************************************************************************
michael@0 296
michael@0 297 void
michael@0 298 nsSHEntryShared::NodeWillBeDestroyed(const nsINode* aNode)
michael@0 299 {
michael@0 300 NS_NOTREACHED("Document destroyed while we're holding a strong ref to it");
michael@0 301 }
michael@0 302
michael@0 303 void
michael@0 304 nsSHEntryShared::CharacterDataWillChange(nsIDocument* aDocument,
michael@0 305 nsIContent* aContent,
michael@0 306 CharacterDataChangeInfo* aInfo)
michael@0 307 {
michael@0 308 }
michael@0 309
michael@0 310 void
michael@0 311 nsSHEntryShared::CharacterDataChanged(nsIDocument* aDocument,
michael@0 312 nsIContent* aContent,
michael@0 313 CharacterDataChangeInfo* aInfo)
michael@0 314 {
michael@0 315 RemoveFromBFCacheAsync();
michael@0 316 }
michael@0 317
michael@0 318 void
michael@0 319 nsSHEntryShared::AttributeWillChange(nsIDocument* aDocument,
michael@0 320 dom::Element* aContent,
michael@0 321 int32_t aNameSpaceID,
michael@0 322 nsIAtom* aAttribute,
michael@0 323 int32_t aModType)
michael@0 324 {
michael@0 325 }
michael@0 326
michael@0 327 void
michael@0 328 nsSHEntryShared::AttributeChanged(nsIDocument* aDocument,
michael@0 329 dom::Element* aElement,
michael@0 330 int32_t aNameSpaceID,
michael@0 331 nsIAtom* aAttribute,
michael@0 332 int32_t aModType)
michael@0 333 {
michael@0 334 RemoveFromBFCacheAsync();
michael@0 335 }
michael@0 336
michael@0 337 void
michael@0 338 nsSHEntryShared::ContentAppended(nsIDocument* aDocument,
michael@0 339 nsIContent* aContainer,
michael@0 340 nsIContent* aFirstNewContent,
michael@0 341 int32_t /* unused */)
michael@0 342 {
michael@0 343 RemoveFromBFCacheAsync();
michael@0 344 }
michael@0 345
michael@0 346 void
michael@0 347 nsSHEntryShared::ContentInserted(nsIDocument* aDocument,
michael@0 348 nsIContent* aContainer,
michael@0 349 nsIContent* aChild,
michael@0 350 int32_t /* unused */)
michael@0 351 {
michael@0 352 RemoveFromBFCacheAsync();
michael@0 353 }
michael@0 354
michael@0 355 void
michael@0 356 nsSHEntryShared::ContentRemoved(nsIDocument* aDocument,
michael@0 357 nsIContent* aContainer,
michael@0 358 nsIContent* aChild,
michael@0 359 int32_t aIndexInContainer,
michael@0 360 nsIContent* aPreviousSibling)
michael@0 361 {
michael@0 362 RemoveFromBFCacheAsync();
michael@0 363 }
michael@0 364
michael@0 365 void
michael@0 366 nsSHEntryShared::ParentChainChanged(nsIContent *aContent)
michael@0 367 {
michael@0 368 }

mercurial