docshell/shistory/src/nsSHEntryShared.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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

mercurial