Bug 396519. Encapsulate content viewer eviction in session history. r+sr=bzbarsky
☠☠ backed out by 77c1ffd2f890 ☠ ☠
authorAndrew Schultz <ajschult@verizon.net>
Tue, 09 Sep 2008 21:39:38 -0400
changeset 19027 ff043f7356f7d920403ac353db111325564570f6
parent 19026 89f146305b76720cc3e982b762a12d29020cba1f
child 19028 9c0c1804d4b74efb56aec86581520e664c318dde
child 19166 77c1ffd2f89039a1201a8add669399ea3591632e
push idunknown
push userunknown
push dateunknown
bugs396519
milestone1.9.1b1pre
Bug 396519. Encapsulate content viewer eviction in session history. r+sr=bzbarsky
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIDocShell.idl
docshell/base/nsWebShell.cpp
docshell/shistory/public/nsISHEntry.idl
docshell/shistory/public/nsISHistoryInternal.idl
docshell/shistory/src/nsSHEntry.cpp
docshell/shistory/src/nsSHEntry.h
docshell/shistory/src/nsSHistory.cpp
layout/base/nsDocumentViewer.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -302,18 +302,16 @@ nsDocShell::nsDocShell():
     mSavingOldViewer(PR_FALSE),
     mAppType(nsIDocShell::APP_TYPE_UNKNOWN),
     mChildOffset(0),
     mBusyFlags(BUSY_FLAGS_NONE),
     mMarginWidth(0),
     mMarginHeight(0),
     mItemType(typeContent),
     mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
-    mPreviousTransIndex(-1),
-    mLoadedTransIndex(-1),
     mTreeOwner(nsnull),
     mChromeEventHandler(nsnull)
 #ifdef DEBUG
     , mInEnsureScriptEnv(PR_FALSE)
 #endif
 {
     if (gDocShellCount++ == 0) {
         NS_ASSERTION(sURIFixup == nsnull,
@@ -1628,52 +1626,16 @@ nsDocShell::SetUseErrorPages(PRBool aUse
             mObserveErrorPages = PR_FALSE;
         }
     }
     mUseErrorPages = aUseErrorPages;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDocShell::GetPreviousTransIndex(PRInt32 *aPreviousTransIndex)
-{
-    *aPreviousTransIndex = mPreviousTransIndex;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::GetLoadedTransIndex(PRInt32 *aLoadedTransIndex)
-{
-    *aLoadedTransIndex = mLoadedTransIndex;
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-nsDocShell::HistoryPurged(PRInt32 aNumEntries)
-{
-    // These indices are used for fastback cache eviction, to determine
-    // which session history entries are candidates for content viewer
-    // eviction.  We need to adjust by the number of entries that we
-    // just purged from history, so that we look at the right session history
-    // entries during eviction.
-    mPreviousTransIndex = PR_MAX(-1, mPreviousTransIndex - aNumEntries);
-    mLoadedTransIndex = PR_MAX(0, mLoadedTransIndex - aNumEntries);
-
-    PRInt32 count = mChildList.Count();
-    for (PRInt32 i = 0; i < count; ++i) {
-        nsCOMPtr<nsIDocShell> shell = do_QueryInterface(ChildAt(i));
-        if (shell) {
-            shell->HistoryPurged(aNumEntries);
-        }
-    }
-
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsDocShell::GetSessionStorageForURI(nsIURI* aURI,
                                     nsIDOMStorage** aStorage)
 {
     NS_ENSURE_ARG_POINTER(aStorage);
 
     *aStorage = nsnull;
 
     nsCOMPtr<nsIDocShellTreeItem> topItem;
@@ -2708,40 +2670,23 @@ nsDocShell::DoAddChildSHEntry(nsISHEntry
 {
     /* You will get here when you are in a subframe and
      * a new url has been loaded on you. 
      * The mOSHE in this subframe will be the previous url's
      * mOSHE. This mOSHE will be used as the identification
      * for this subframe in the  CloneAndReplace function.
      */
 
-    // In this case, we will end up calling AddEntry, which increases the
-    // current index by 1
-    nsCOMPtr<nsISHistory> rootSH;
-    GetRootSessionHistory(getter_AddRefs(rootSH));
-    if (rootSH) {
-        rootSH->GetIndex(&mPreviousTransIndex);
-    }
-
     nsresult rv;
     nsCOMPtr<nsIDocShellHistory> parent =
         do_QueryInterface(GetAsSupports(mParent), &rv);
     if (parent) {
         rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset);
     }
 
-
-    if (rootSH) {
-        rootSH->GetIndex(&mLoadedTransIndex);
-#ifdef DEBUG_PAGE_CACHE
-        printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
-               mLoadedTransIndex);
-#endif
-    }
-
     return rv;
 }
 
 NS_IMETHODIMP
 nsDocShell::SetUseGlobalHistory(PRBool aUseGlobalHistory)
 {
     nsresult rv;
 
@@ -5436,22 +5381,27 @@ nsDocShell::DetachEditorFromWindow()
 nsresult
 nsDocShell::CaptureState()
 {
     if (!mOSHE || mOSHE == mLSHE) {
         // No entry to save into, or we're replacing the existing entry.
         return NS_ERROR_FAILURE;
     }
 
+    PRBool shouldSaveContentViewer = PR_FALSE;
+    nsresult rv = mOSHE->GetSaveContentViewerFlag(&shouldSaveContentViewer);
+    if (NS_FAILED(rv) || !shouldSaveContentViewer)
+        return NS_ERROR_FAILURE;
+
     nsCOMPtr<nsPIDOMWindow> privWin = do_QueryInterface(mScriptGlobal);
     if (!privWin)
         return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsISupports> windowState;
-    nsresult rv = privWin->SaveWindowState(getter_AddRefs(windowState));
+    rv = privWin->SaveWindowState(getter_AddRefs(windowState));
     NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG_PAGE_CACHE
     nsCOMPtr<nsIURI> uri;
     mOSHE->GetURI(getter_AddRefs(uri));
     nsCAutoString spec;
     if (uri)
         uri->GetSpec(spec);
@@ -5752,23 +5702,17 @@ nsDocShell::RestoreFromHistory()
     // *new* document will fire.
     mFiredUnloadEvent = PR_FALSE;
 
     mURIResultedInDocument = PR_TRUE;
     nsCOMPtr<nsISHistory> rootSH;
     GetRootSessionHistory(getter_AddRefs(rootSH));
     if (rootSH) {
         nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
-        rootSH->GetIndex(&mPreviousTransIndex);
         hist->UpdateIndex();
-        rootSH->GetIndex(&mLoadedTransIndex);
-#ifdef DEBUG_PAGE_CACHE
-        printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
-                   mLoadedTransIndex);
-#endif
     }
 
     // Rather than call Embed(), we will retrieve the viewer from the session
     // history entry and swap it in.
     // XXX can we refactor this so that we can just call Embed()?
     PersistLayoutHistoryState();
     nsresult rv;
     if (mContentViewer) {
@@ -8076,23 +8020,17 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIC
         }
     }
 
     // If this was a history load, update the index in 
     // SH. 
     if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) {
         nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
         if (shInternal) {
-            rootSH->GetIndex(&mPreviousTransIndex);
             shInternal->UpdateIndex();
-            rootSH->GetIndex(&mLoadedTransIndex);
-#ifdef DEBUG_PAGE_CACHE
-            printf("Previous index: %d, Loaded index: %d\n\n",
-                   mPreviousTransIndex, mLoadedTransIndex);
-#endif
         }
     }
     PRBool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
                                                   aFireOnLocationChange);
     // Make sure to store the referrer from the channel, if any
     SetupReferrerFromChannel(aChannel);
     return onLocationChangeNeeded;
 }
@@ -8289,23 +8227,17 @@ nsDocShell::AddToSessionHistory(nsIURI *
             if (shPrivate)
                 rv = shPrivate->ReplaceEntry(index, entry);          
         }
         else {
             // Add to session history
             nsCOMPtr<nsISHistoryInternal>
                 shPrivate(do_QueryInterface(mSessionHistory));
             NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
-            mSessionHistory->GetIndex(&mPreviousTransIndex);
             rv = shPrivate->AddEntry(entry, shouldPersist);
-            mSessionHistory->GetIndex(&mLoadedTransIndex);
-#ifdef DEBUG_PAGE_CACHE
-            printf("Previous index: %d, Loaded index: %d\n\n",
-                   mPreviousTransIndex, mLoadedTransIndex);
-#endif
         }
     }
     else {  
         // This is a subframe.
         if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
                                            LOAD_FLAGS_REPLACE_HISTORY))
             rv = DoAddChildSHEntry(entry, mChildOffset);
     }
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -643,21 +643,16 @@ protected:
     // Holds a weak pointer to a RestorePresentationEvent object if any that
     // holds a weak pointer back to us.  We use this pointer to possibly revoke
     // the event whenever necessary.
     nsRevocableEventPtr<RestorePresentationEvent> mRestorePresentationEvent;
 
     // hash of session storages, keyed by domain
     nsInterfaceHashtable<nsCStringHashKey, nsIDOMStorage> mStorages;
 
-    // Index into the SHTransaction list, indicating the previous and current
-    // transaction at the time that this DocShell begins to load
-    PRInt32                    mPreviousTransIndex;
-    PRInt32                    mLoadedTransIndex;
-
     // Editor data, if this document is designMode or contentEditable.
     nsAutoPtr<nsDocShellEditorData> mEditorData;
 
     // Transferable hooks/callbacks
     nsCOMPtr<nsIClipboardDragDropHookList>  mTransferableHookData;
 
     // Secure browser UI object
     nsCOMPtr<nsISecureBrowserUI> mSecurityUI;
--- a/docshell/base/nsIDocShell.idl
+++ b/docshell/base/nsIDocShell.idl
@@ -63,17 +63,17 @@ interface nsIWebNavigation;
 interface nsISimpleEnumerator;
 interface nsIInputStream;
 interface nsIRequest;
 interface nsISHEntry;
 interface nsILayoutHistoryState;
 interface nsISecureBrowserUI;
 interface nsIDOMStorage;
 
-[scriptable, uuid(7d1cf6b9-daa3-476d-8f9f-9eb2a971a95c)]
+[scriptable, uuid(cf974f45-d2f1-4bd5-aecd-568a1c4da454)]
 interface nsIDocShell : nsISupports
 {
   /**
    * Loads a given URI.  This will give priority to loading the requested URI
    * in the object implementing	this interface.  If it can't be loaded here
    * however, the URL dispatcher will go through its normal process of content
    * loading.
    *
@@ -395,32 +395,16 @@ interface nsIDocShell : nsISupports
   void finishRestore();
 
   /* Track whether we're currently restoring a document presentation. */
   readonly attribute boolean restoringDocument;
 
   /* attribute to access whether error pages are enabled */
   attribute boolean useErrorPages;
 
-  /**
-   * Keeps track of the previous SHTransaction index and the current
-   * SHTransaction index at the time that the doc shell begins to load.
-   * Used for ContentViewer eviction.
-   */
-  readonly attribute long previousTransIndex;
-  readonly attribute long loadedTransIndex;
-
-  /**
-   * Notification that entries have been removed from the beginning of a
-   * nsSHistory which has this as its rootDocShell.
-   *
-   * @param numEntries - The number of entries removed
-   */
-  void historyPurged(in long numEntries);
-
   /*
    * Retrieves the WebApps session storage object for the supplied domain.
    * If it doesn't already exist, a new one will be created.
    *
    * @param domain the domain of the storage object to retrieve
    */
   nsIDOMStorage getSessionStorageForURI(in nsIURI uri);
 
--- a/docshell/base/nsWebShell.cpp
+++ b/docshell/base/nsWebShell.cpp
@@ -1234,23 +1234,17 @@ nsresult nsWebShell::EndPageLoad(nsIWebP
             rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH));
             }
           }
         }  // mSessionHistory
 
         if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) {
           nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
           if (shInternal) {
-            rootSH->GetIndex(&mPreviousTransIndex);
             shInternal->UpdateIndex();
-            rootSH->GetIndex(&mLoadedTransIndex);
-#ifdef DEBUG_PAGE_CACHE
-            printf("Previous index: %d, Loaded index: %d\n\n",
-                  mPreviousTransIndex, mLoadedTransIndex);
-#endif
           }
         }
 
         // Make it look like we really did honestly finish loading the
         // history page we were loading, since the "reload" load we're
         // about to kick off will reload our current history entry.  This
         // is a bit of a hack, and if the force-load fails I think we'll
         // end up being confused about what page we're on... but we would
--- a/docshell/shistory/public/nsISHEntry.idl
+++ b/docshell/shistory/public/nsISHEntry.idl
@@ -53,17 +53,17 @@ interface nsISupportsArray;
 %{C++
 struct nsRect;
 class nsDocShellEditorData;
 %}
 [ref] native nsRect(nsRect);
 [ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
 
 
-[scriptable, uuid(c16fde76-3108-450e-8c8c-ae8286f286ed)]
+[scriptable, uuid(622412da-be41-407e-b57e-9aba2a282b00)]
 interface nsISHEntry : nsIHistoryEntry
 {
     /** URI for the document */
     void setURI(in nsIURI aURI);
 
     /** Referrer URI */
     attribute nsIURI referrerURI;
 
@@ -147,16 +147,19 @@ interface nsISHEntry : nsIHistoryEntry
      * entries are separated by an anchor traversal or a subframe navigation in
      * some other frame).
      */
     attribute unsigned long pageIdentifier;
 
     /** attribute to set and get the cache key for the entry */
     attribute nsISupports cacheKey;
 
+    /** attribute to indicate whether the contentViewer should be saved */
+    attribute boolean saveContentViewerFlag;
+
     /** attribute to indicate whether layoutHistoryState should be saved */
     attribute boolean saveLayoutStateFlag;
 
     /** attribute to indicate whether the page is already expired in cache */
     attribute boolean expirationStatus;
 
     /**
      * attribute to indicate the content-type of the document that this
--- a/docshell/shistory/public/nsISHistoryInternal.idl
+++ b/docshell/shistory/public/nsISHistoryInternal.idl
@@ -47,17 +47,17 @@ interface nsIDocShell;
 %{C++
 #define NS_SHISTORY_INTERNAL_CID \
 { 0x9c47c121, 0x1c6e, 0x4d8f, \
   { 0xb9, 0x04, 0x3a, 0xc9, 0x68, 0x11, 0x6e, 0x88 } }
 
 #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
 %}
 
-[scriptable, uuid(9c47c121-1c6e-4d8f-b904-3ac968116e88)]
+[scriptable, uuid(0e91697a-4ba0-4ede-b08a-0bae9ee1a701)]
 interface nsISHistoryInternal: nsISupports
 {
   /**
    * Add a new Entry to the History List
    * @param aEntry - The entry to add
    * @param aPersist - If true this specifies that the entry should persist
    * in the list.  If false, this means that when new entries are added
    * this element will not appear in the session history list.
@@ -87,22 +87,20 @@ interface nsISHistoryInternal: nsISuppor
    void replaceEntry(in long aIndex, in nsISHEntry aReplaceEntry);
 
   /** 
    * Get handle to the history listener
    */
    readonly attribute nsISHistoryListener listener;
 
   /**
-   * Evict content viewers until the number of content viewers per tab
-   * is no more than gHistoryMaxViewers.  Also, count
-   * total number of content viewers globally and evict one if we are over
-   * our total max.  This is always called in Show(), after we destroy
-   * the previous viewer.
+   * Count total number of content viewers globally and evict one if we are over
+   * our total max.  This is always called in Show(), after we destroy the
+   * previous viewer.
    */
-   void evictContentViewers(in long previousIndex, in long index);
+   void evictContentViewers();
    
    /**
     * Evict the content viewer associated with a session history entry
     * that has timed out.
     */
    void evictExpiredContentViewerForEntry(in nsISHEntry aEntry);
 };
--- a/docshell/shistory/src/nsSHEntry.cpp
+++ b/docshell/shistory/src/nsSHEntry.cpp
@@ -101,16 +101,17 @@ static void StopTrackingEntry(nsSHEntry 
 
 
 nsSHEntry::nsSHEntry() 
   : mLoadType(0)
   , mID(gEntryID++)
   , mPageIdentifier(mID)
   , mScrollPositionX(0)
   , mScrollPositionY(0)
+  , mSaveContentViewer(PR_TRUE)
   , mIsFrameNavigation(PR_FALSE)
   , mSaveLayoutState(PR_TRUE)
   , mExpired(PR_FALSE)
   , mSticky(PR_TRUE)
   , mParent(nsnull)
   , mViewerBounds(0, 0, 0, 0)
 {
 }
@@ -122,16 +123,17 @@ nsSHEntry::nsSHEntry(const nsSHEntry &ot
   , mTitle(other.mTitle)
   , mPostData(other.mPostData)
   , mLayoutHistoryState(other.mLayoutHistoryState)
   , mLoadType(0)         // XXX why not copy?
   , mID(other.mID)
   , mPageIdentifier(other.mPageIdentifier)
   , mScrollPositionX(0)  // XXX why not copy?
   , mScrollPositionY(0)  // XXX why not copy?
+  , mSaveContentViewer(other.mSaveContentViewer)
   , mIsFrameNavigation(other.mIsFrameNavigation)
   , mSaveLayoutState(other.mSaveLayoutState)
   , mExpired(other.mExpired)
   , mSticky(PR_TRUE)
   // XXX why not copy mContentType?
   , mCacheKey(other.mCacheKey)
   , mParent(other.mParent)
   , mViewerBounds(0, 0, 0, 0)
@@ -411,16 +413,28 @@ NS_IMETHODIMP nsSHEntry::GetCacheKey(nsI
 }
 
 NS_IMETHODIMP nsSHEntry::SetCacheKey(nsISupports* aCacheKey)
 {
   mCacheKey = aCacheKey;
   return NS_OK;
 }
 
+NS_IMETHODIMP nsSHEntry::GetSaveContentViewerFlag(PRBool * aFlag)
+{
+  *aFlag = mSaveContentViewer;
+  return NS_OK;
+}
+
+NS_IMETHODIMP nsSHEntry::SetSaveContentViewerFlag(PRBool  aFlag)
+{
+  mSaveContentViewer = aFlag;
+  return NS_OK;
+}
+
 NS_IMETHODIMP nsSHEntry::GetSaveLayoutStateFlag(PRBool * aFlag)
 {
   *aFlag = mSaveLayoutState;
   return NS_OK;
 }
 
 NS_IMETHODIMP nsSHEntry::SetSaveLayoutStateFlag(PRBool  aFlag)
 {
--- a/docshell/shistory/src/nsSHEntry.h
+++ b/docshell/shistory/src/nsSHEntry.h
@@ -97,16 +97,17 @@ private:
   nsCOMPtr<nsIInputStream>        mPostData;
   nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
   nsCOMArray<nsISHEntry>          mChildren;
   PRUint32                        mLoadType;  
   PRUint32                        mID;
   PRUint32                        mPageIdentifier;
   PRInt32                         mScrollPositionX;
   PRInt32                         mScrollPositionY;
+  PRPackedBool                    mSaveContentViewer;
   PRPackedBool                    mIsFrameNavigation;
   PRPackedBool                    mSaveLayoutState;
   PRPackedBool                    mExpired;
   PRPackedBool                    mSticky;
   nsCString                       mContentType;
   nsCOMPtr<nsISupports>           mCacheKey;
   nsISHEntry *                    mParent;  // weak reference
   nsCOMPtr<nsISupports>           mWindowState;
--- a/docshell/shistory/src/nsSHistory.cpp
+++ b/docshell/shistory/src/nsSHistory.cpp
@@ -325,26 +325,29 @@ nsSHistory::AddEntry(nsISHEntry * aSHEnt
   // Set the ShEntry and parent for the transaction. setting the 
   // parent will properly set the parent child relationship
   txn->SetPersist(aPersist);
   NS_ENSURE_SUCCESS(txn->Create(aSHEntry, currentTxn), NS_ERROR_FAILURE);
    
   // A little tricky math here...  Basically when adding an object regardless of
   // what the length was before, it should always be set back to the current and
   // lop off the forward.
+  PRInt32 oldIndex = mIndex;
   mLength = (++mIndex + 1);
 
   // If this is the very first transaction, initialize the list
   if(!mListRoot)
     mListRoot = txn;
 
   // Purge History list if it is too long
   if ((gHistoryMaxSize >= 0) && (mLength > gHistoryMaxSize))
     PurgeHistory(mLength-gHistoryMaxSize);
   
+  // Evict a content viewer if we might have too many behind us
+  EvictWindowContentViewers(oldIndex, mIndex);
   return NS_OK;
 }
 
 /* Get size of the history list */
 NS_IMETHODIMP
 nsSHistory::GetCount(PRInt32 * aResult)
 {
   NS_ENSURE_ARG_POINTER(aResult);
@@ -578,19 +581,16 @@ nsSHistory::PurgeHistory(PRInt32 aEntrie
   mIndex -= cnt;
 
   // Now if we were not at the end of the history, mIndex could have
   // become far too negative.  If so, just set it to -1.
   if (mIndex < -1) {
     mIndex = -1;
   }
 
-  if (mRootDocShell)
-    mRootDocShell->HistoryPurged(cnt);
-
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsSHistory::AddSHistoryListener(nsISHistoryListener * aListener)
 {
   NS_ENSURE_ARG_POINTER(aListener);
@@ -650,20 +650,18 @@ nsSHistory::GetListener(nsISHistoryListe
   NS_ENSURE_ARG_POINTER(aListener);
   if (mListener) 
     CallQueryReferent(mListener.get(),  aListener);
   // Don't addref aListener. It is a weak pointer.
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsSHistory::EvictContentViewers(PRInt32 aPreviousIndex, PRInt32 aIndex)
+nsSHistory::EvictContentViewers()
 {
-  // Check our per SHistory object limit in the currently navigated SHistory
-  EvictWindowContentViewers(aPreviousIndex, aIndex);
   // Check our total limit across all SHistory objects
   EvictGlobalContentViewer();
   return NS_OK;
 }
 
 //*****************************************************************************
 //    nsSHistory: nsIWebNavigation
 //*****************************************************************************
@@ -1121,16 +1119,25 @@ nsSHistory::LoadURI(const PRUnichar* aUR
                     nsIInputStream* aExtraHeaderStream)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSHistory::GotoIndex(PRInt32 aIndex)
 {
+ 
+  if (mIndex > -1 && PR_ABS(aIndex - mIndex) > gHistoryMaxViewers) {
+    // The current entry is too far from the new index, so mark it so its
+    // content viewer doesn't get saved.
+    nsCOMPtr<nsISHEntry> currentEntry;
+    nsresult rv = GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(currentEntry));
+    if (NS_SUCCEEDED(rv) && currentEntry)
+      currentEntry->SetSaveContentViewerFlag(PR_FALSE);
+  }
   return LoadEntry(aIndex, nsIDocShellLoadInfo::loadHistory, HIST_CMD_GOTOINDEX);
 }
 
 NS_IMETHODIMP
 nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
 {
   nsCOMPtr<nsIDocShell> docShell;
   nsCOMPtr<nsISHEntry> shEntry;
@@ -1216,17 +1223,27 @@ nsSHistory::LoadEntry(PRInt32 aIndex, lo
   if (!docShell) {
     // we did not successfully go to the proper index.
     // return error.
     mRequestedIndex = -1;
     return NS_ERROR_FAILURE;
   }
 
   // Start the load on the appropriate docshell
-  return InitiateLoad(nextEntry, docShell, aLoadType);
+  nsresult rv = InitiateLoad(nextEntry, docShell, aLoadType);
+
+  if (NS_SUCCEEDED(rv)) {
+    // mark the entry as being able to save its content viewer
+    nextEntry->SetSaveContentViewerFlag(PR_TRUE);
+    // evict any content viewers that are now gHistoryMaxViewers
+    // or more away from the new index
+    EvictWindowContentViewers(mIndex, mRequestedIndex);
+  }
+
+  return rv;
 }
 
 
 
 nsresult
 nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
 {
   if (!aPrevEntry || !aNextEntry || !aParent)
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -1856,25 +1856,20 @@ DocumentViewerImpl::Show(void)
       // SHistory and we need the SHistory to evict content viewers
       nsCOMPtr<nsIDocShellTreeItem> root;
       treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
       nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
       nsCOMPtr<nsISHistory> history;
       webNav->GetSessionHistory(getter_AddRefs(history));
       nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
       if (historyInt) {
-        PRInt32 prevIndex,loadedIndex;
-        nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(treeItem);
-        docShell->GetPreviousTransIndex(&prevIndex);
-        docShell->GetLoadedTransIndex(&loadedIndex);
 #ifdef DEBUG_PAGE_CACHE
-        printf("About to evict content viewers: prev=%d, loaded=%d\n",
-               prevIndex, loadedIndex);
+        printf("About to evict content viewers\n");
 #endif
-        historyInt->EvictContentViewers(prevIndex, loadedIndex);
+        historyInt->EvictContentViewers();
       }
     }
   }
 
   if (mWindow) {
     mWindow->Show(PR_TRUE);
   }