LCOV - code coverage report
Current view: directory - docshell/shistory/src - nsSHEntryShared.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 145 11 7.6 %
Date: 2012-06-02 Functions: 32 4 12.5 %

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

Generated by: LCOV version 1.7