Add support for caching content viewers in session history to speed up back/forward (bug 274784). This initial landing has the feature disabled by default; set browser.sessionhistory.max_viewers to the maximum number of pages to cache to enable the feature. r=bzbarsky, sr/a=brendan.

This commit is contained in:
bryner%brianryner.com 2005-08-18 11:17:00 +00:00
Родитель 7e7578bb1f
Коммит e3bc99eb80
8 изменённых файлов: 383 добавлений и 100 удалений

Просмотреть файл

@ -53,30 +53,30 @@ interface nsIURI;
interface nsIHistoryEntry : nsISupports interface nsIHistoryEntry : nsISupports
{ {
/** /**
* A readonly property that returns the URI * A readonly property that returns the URI
* of the current entry. The object returned is * of the current entry. The object returned is
* of type nsIURI * of type nsIURI
*/ */
readonly attribute nsIURI URI; readonly attribute nsIURI URI;
/** /**
* A readonly property that returns the title * A readonly property that returns the title
* of the current entry. The object returned * of the current entry. The object returned
* is a encoded string * is a encoded string
*/ */
readonly attribute wstring title; readonly attribute wstring title;
/** /**
* A readonly property that returns a boolean * A readonly property that returns a boolean
* flag which indicates if the entry was created as a * flag which indicates if the entry was created as a
* result of a subframe navigation. This flag will be * result of a subframe navigation. This flag will be
* 'false' when a frameset page is visited for * 'false' when a frameset page is visited for
* the first time. This flag will be 'true' for all * the first time. This flag will be 'true' for all
* history entries created as a result of a subframe * history entries created as a result of a subframe
* navigation. * navigation.
*/ */
readonly attribute boolean isSubFrame; readonly attribute boolean isSubFrame;
}; };

Просмотреть файл

@ -42,88 +42,145 @@
* hold all information required to recreate the document from history * hold all information required to recreate the document from history
* *
*/ */
#include "nsISupports.idl" #include "nsIHistoryEntry.idl"
#include "nsIURI.idl"
#include "nsIInputStream.idl"
interface nsILayoutHistoryState; interface nsILayoutHistoryState;
interface nsIDOMDocument; interface nsIContentViewer;
interface nsIURI;
interface nsIInputStream;
interface nsIDocShellTreeItem;
interface nsISecureBrowserUIState;
interface nsISupportsArray;
%{C++
struct nsRect;
%}
[ref] native nsRect(nsRect);
[scriptable, uuid(6b596e1f-a3bd-40f9-a7ee-ab3edc7f9960)] [scriptable, uuid(e47bf412-3bc2-4306-a82f-ea2bdf950432)]
interface nsISHEntry : nsISupports interface nsISHEntry : nsIHistoryEntry
{ {
/** URI for the document */
void setURI(in nsIURI aURI);
/** URI for the document */ /** Referrer URI */
void SetURI(in nsIURI aURI); attribute nsIURI referrerURI;
/** Referrer URI */ /** Content viewer, for fast restoration of presentation */
attribute nsIURI referrerURI; attribute nsIContentViewer contentViewer;
/** DOM Document */ /** Whether the content viewer is marked "sticky" */
attribute nsIDOMDocument document; attribute boolean sticky;
/** Title for the document */ /** Saved state of the global window object */
void SetTitle(in wstring aTitle); attribute nsISupports windowState;
/** Post Data for the document */ /**
attribute nsIInputStream postData; * Saved position and dimensions of the content viewer; we must adjust the
* root view's widget accordingly if this has changed when the presentation
* is restored.
*/
[noscript] void getViewerBounds(in nsRect bounds);
[noscript] void setViewerBounds([const] in nsRect bounds);
/** LayoutHistoryState for scroll position and form values */ /**
attribute nsILayoutHistoryState layoutHistoryState; * Saved child docshells corresponding to contentViewer. There are weak
* references since it's assumed that the content viewer's document has
* an owning reference to the subdocument for each shell. The child shells
* are restored as children of the parent docshell, in this order, when the
* parent docshell restores a saved presentation.
*/
/** parent of this entry */ /** Append a child shell to the end of our list. */
attribute nsISHEntry parent; void addChildShell(in nsIDocShellTreeItem shell);
/** /**
* The loadType for this entry. This is typically loadHistory except * Get the child shell at |index|; returns null if |index| is out of bounds.
* when reload is pressed, it has the appropriate reload flag */
*/ nsIDocShellTreeItem childShellAt(in long index);
attribute unsigned long loadType;
/** /**
* An ID to help identify this entry from others during * Clear the child shell list.
* subframe navigation */
*/ void clearChildShells();
attribute unsigned long ID;
/** /** Saved security state for the content viewer */
* pageIdentifier is an integer that should be the same for two entries attribute nsISupports securityState;
* attached to the same docshell only if the two entries are entries for the
* same page in the sense that one could go from the state represented by one
* to the state represented by the other simply by scrolling (so the 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 */ /** Saved refresh URI list for the content viewer */
attribute nsISupports cacheKey; attribute nsISupportsArray refreshURIList;
/** attribute to indicate whether layoutHistoryState should be saved */ /**
attribute boolean saveLayoutStateFlag; * Ensure that the cached presentation members are self-consistent.
* If either |contentViewer| or |windowState| are null, then all of the
* following members are cleared/reset:
* contentViewer, sticky, windowState, viewerBounds, childShells,
* refreshURIList.
*/
void syncPresentationState();
/** attribute to indicate whether the page is already expired in cache */ /** Title for the document */
attribute boolean expirationStatus; void setTitle(in AString aTitle);
/** attribute to indicate the content-type of the document that this /** Post Data for the document */
is a session history entry for */ attribute nsIInputStream postData;
attribute ACString contentType;
/** LayoutHistoryState for scroll position and form values */
attribute nsILayoutHistoryState layoutHistoryState;
/** parent of this entry */
attribute nsISHEntry parent;
/**
* The loadType for this entry. This is typically loadHistory except
* when reload is pressed, it has the appropriate reload flag
*/
attribute unsigned long loadType;
/**
* An ID to help identify this entry from others during
* subframe navigation
*/
attribute unsigned long ID;
/**
* pageIdentifier is an integer that should be the same for two entries
* attached to the same docshell only if the two entries are entries for
* the same page in the sense that one could go from the state represented
* by one to the state represented by the other simply by scrolling (so the
* 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 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
* is a session history entry for
*/
attribute ACString contentType;
/** Set/Get scrollers' positon in anchored pages */ /** Set/Get scrollers' positon in anchored pages */
void setScrollPosition(in PRInt32 x, in PRInt32 y); void setScrollPosition(in long x, in long y);
void getScrollPosition(out PRInt32 x, out PRInt32 y); void getScrollPosition(out long x, out long y);
/** Additional ways to create an entry */ /** Additional ways to create an entry */
void create(in nsIURI aURI, in wstring aTitle, in nsIDOMDocument aDocument, void create(in nsIURI URI, in AString title,
in nsIInputStream aInputStream, in nsILayoutHistoryState aHistoryLayoutState, in nsIInputStream inputStream,
in nsISupports aCacheKey, in ACString aContentType); in nsILayoutHistoryState layoutHistoryState,
in nsISupports cacheKey, in ACString contentType);
nsISHEntry clone();
/** Attribute that indicates if this entry is for a subframe navigation */
void SetIsSubFrame(in boolean aFlag);
nsISHEntry clone();
/** Attribute that indicates if this entry is for a subframe navigation */
void setIsSubFrame(in boolean aFlag);
}; };

Просмотреть файл

@ -46,7 +46,7 @@ interface nsIDocShell;
%{C++ %{C++
#define NS_SHISTORY_INTERNAL_CID \ #define NS_SHISTORY_INTERNAL_CID \
{0xdd335422, 0xb8b8, 0x11d3, {0xbd, 0xc8, 0x00, 0x50, 0x04, 0x0a, 0x9b, 0x44}} {0x5b4cba4c, 0xbf67, 0x499a, {0xae, 0x2c, 0x3f, 0x76, 0x65, 0x6f, 0x4a, 0x4e}}
#define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1" #define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
%} %}
@ -90,4 +90,11 @@ interface nsISHistoryInternal: nsISupports
*/ */
readonly attribute nsISHistoryListener listener; readonly attribute nsISHistoryListener listener;
/**
* Evict content viewers until the number of content viewers is no more than
* browser.sessionhistory.max_viewers. This is done automatically by
* updateIndex(), but should be called explicitly if a new history entry
* is added and later has a content viewer set.
*/
void evictContentViewers();
}; };

Просмотреть файл

@ -55,6 +55,7 @@ REQUIRES = xpcom \
layout \ layout \
docshell \ docshell \
pref \ pref \
gfx \
$(NULL) $(NULL)
CPPSRCS = nsSHEntry.cpp \ CPPSRCS = nsSHEntry.cpp \

Просмотреть файл

@ -37,11 +37,16 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#ifdef DEBUG_bryner
#define DEBUG_PAGE_CACHE
#endif
// Local Includes // Local Includes
#include "nsSHEntry.h" #include "nsSHEntry.h"
#include "nsXPIDLString.h" #include "nsXPIDLString.h"
#include "nsReadableUtils.h" #include "nsReadableUtils.h"
#include "nsIDocShellLoadInfo.h" #include "nsIDocShellLoadInfo.h"
#include "nsIDocShellTreeItem.h"
static PRUint32 gEntryID = 0; static PRUint32 gEntryID = 0;
@ -58,7 +63,9 @@ nsSHEntry::nsSHEntry()
, mIsFrameNavigation(PR_FALSE) , mIsFrameNavigation(PR_FALSE)
, mSaveLayoutState(PR_TRUE) , mSaveLayoutState(PR_TRUE)
, mExpired(PR_FALSE) , mExpired(PR_FALSE)
, mSticky(PR_TRUE)
, mParent(nsnull) , mParent(nsnull)
, mViewerBounds(0, 0, 0, 0)
{ {
} }
@ -77,12 +84,21 @@ nsSHEntry::nsSHEntry(const nsSHEntry &other)
, mIsFrameNavigation(other.mIsFrameNavigation) , mIsFrameNavigation(other.mIsFrameNavigation)
, mSaveLayoutState(other.mSaveLayoutState) , mSaveLayoutState(other.mSaveLayoutState)
, mExpired(other.mExpired) , mExpired(other.mExpired)
, mSticky(PR_TRUE)
// XXX why not copy mContentType? // XXX why not copy mContentType?
, mCacheKey(other.mCacheKey) , mCacheKey(other.mCacheKey)
, mParent(other.mParent) , mParent(other.mParent)
, mViewerBounds(0, 0, 0, 0)
{ {
} }
nsSHEntry::~nsSHEntry()
{
mChildren.Clear();
if (mContentViewer)
mContentViewer->Destroy();
}
//***************************************************************************** //*****************************************************************************
// nsSHEntry: nsISupports // nsSHEntry: nsISupports
//***************************************************************************** //*****************************************************************************
@ -133,19 +149,35 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetDocument(nsIDOMDocument* aDocument) NS_IMETHODIMP
nsSHEntry::SetContentViewer(nsIContentViewer *aViewer)
{ {
mDocument = aDocument; mContentViewer = aViewer;
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::GetDocument(nsIDOMDocument** aResult) NS_IMETHODIMP
nsSHEntry::GetContentViewer(nsIContentViewer **aResult)
{ {
*aResult = mDocument; *aResult = mContentViewer;
NS_IF_ADDREF(*aResult); NS_IF_ADDREF(*aResult);
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsSHEntry::SetSticky(PRBool aSticky)
{
mSticky = aSticky;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetSticky(PRBool *aSticky)
{
*aSticky = mSticky;
return NS_OK;
}
NS_IMETHODIMP nsSHEntry::GetTitle(PRUnichar** aTitle) NS_IMETHODIMP nsSHEntry::GetTitle(PRUnichar** aTitle)
{ {
// Check for empty title... // Check for empty title...
@ -160,7 +192,7 @@ NS_IMETHODIMP nsSHEntry::GetTitle(PRUnichar** aTitle)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP nsSHEntry::SetTitle(const PRUnichar* aTitle) NS_IMETHODIMP nsSHEntry::SetTitle(const nsAString &aTitle)
{ {
mTitle = aTitle; mTitle = aTitle;
return NS_OK; return NS_OK;
@ -297,14 +329,13 @@ NS_IMETHODIMP nsSHEntry::SetContentType(const nsACString& aContentType)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsSHEntry::Create(nsIURI * aURI, const PRUnichar * aTitle, nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle,
nsIDOMDocument * aDOMDocument, nsIInputStream * aInputStream, nsIInputStream * aInputStream,
nsILayoutHistoryState * aHistoryLayoutState, nsILayoutHistoryState * aLayoutHistoryState,
nsISupports * aCacheKey, const nsACString& aContentType) nsISupports * aCacheKey, const nsACString& aContentType)
{ {
mURI = aURI; mURI = aURI;
mTitle = aTitle; mTitle = aTitle;
mDocument = aDOMDocument;
mPostData = aInputStream; mPostData = aInputStream;
mCacheKey = aCacheKey; mCacheKey = aCacheKey;
mContentType = aContentType; mContentType = aContentType;
@ -317,9 +348,9 @@ nsSHEntry::Create(nsIURI * aURI, const PRUnichar * aTitle,
// all subframe navigations, sets the flag to true. // all subframe navigations, sets the flag to true.
mIsFrameNavigation = PR_FALSE; mIsFrameNavigation = PR_FALSE;
// By default we save HistoryLayoutState // By default we save LayoutHistoryState
mSaveLayoutState = PR_TRUE; mSaveLayoutState = PR_TRUE;
mLayoutHistoryState = aHistoryLayoutState; mLayoutHistoryState = aLayoutHistoryState;
//By default the page is not expired //By default the page is not expired
mExpired = PR_FALSE; mExpired = PR_FALSE;
@ -358,6 +389,34 @@ nsSHEntry::SetParent(nsISHEntry * aParent)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsSHEntry::SetWindowState(nsISupports *aState)
{
mWindowState = aState;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetWindowState(nsISupports **aState)
{
NS_IF_ADDREF(*aState = mWindowState);
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetViewerBounds(const nsRect &aBounds)
{
mViewerBounds = aBounds;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetViewerBounds(nsRect &aBounds)
{
aBounds = mViewerBounds;
return NS_OK;
}
//***************************************************************************** //*****************************************************************************
// nsSHEntry: nsISHContainer // nsSHEntry: nsISHContainer
//***************************************************************************** //*****************************************************************************
@ -416,3 +475,77 @@ nsSHEntry::GetChildAt(PRInt32 aIndex, nsISHEntry ** aResult)
} }
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell)
{
NS_ASSERTION(aShell, "Null child shell added to history entry");
mChildShells.AppendElement(aShell);
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell)
{
NS_IF_ADDREF(*aShell =
NS_STATIC_CAST(nsIDocShellTreeItem*,
mChildShells.SafeElementAt(aIndex)));
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::ClearChildShells()
{
mChildShells.Clear();
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetSecurityState(nsISupports **aState)
{
NS_IF_ADDREF(*aState = mSecurityState);
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetSecurityState(nsISupports *aState)
{
mSecurityState = aState;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::GetRefreshURIList(nsISupportsArray **aList)
{
NS_IF_ADDREF(*aList = mRefreshURIList);
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetRefreshURIList(nsISupportsArray *aList)
{
mRefreshURIList = aList;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SyncPresentationState()
{
if (mContentViewer && mWindowState) {
// If we have a content viewer and a window state, we should be ok.
return NS_OK;
}
// If not, then nuke all of the presentation-related members.
if (mContentViewer)
mContentViewer->SetHistoryEntry(nsnull);
mContentViewer = nsnull;
mSticky = PR_TRUE;
mWindowState = nsnull;
mViewerBounds.SetRect(0, 0, 0, 0);
mChildShells.Clear();
mSecurityState = nsnull;
mRefreshURIList = nsnull;
return NS_OK;
}

Просмотреть файл

@ -44,9 +44,10 @@
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsCOMArray.h" #include "nsCOMArray.h"
#include "nsString.h" #include "nsString.h"
#include "nsVoidArray.h"
// Interfaces needed // Interfaces needed
#include "nsIDOMDocument.h" #include "nsIContentViewer.h"
#include "nsIInputStream.h" #include "nsIInputStream.h"
#include "nsILayoutHistoryState.h" #include "nsILayoutHistoryState.h"
#include "nsISHEntry.h" #include "nsISHEntry.h"
@ -54,9 +55,10 @@
#include "nsIURI.h" #include "nsIURI.h"
#include "nsIEnumerator.h" #include "nsIEnumerator.h"
#include "nsIHistoryEntry.h" #include "nsIHistoryEntry.h"
#include "nsRect.h"
#include "nsSupportsArray.h"
class nsSHEntry : public nsIHistoryEntry, class nsSHEntry : public nsISHEntry,
public nsISHEntry,
public nsISHContainer public nsISHContainer
{ {
public: public:
@ -69,11 +71,11 @@ public:
NS_DECL_NSISHCONTAINER NS_DECL_NSISHCONTAINER
private: private:
~nsSHEntry() { mChildren.Clear(); } ~nsSHEntry();
nsCOMPtr<nsIURI> mURI; nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI; nsCOMPtr<nsIURI> mReferrerURI;
nsCOMPtr<nsIDOMDocument> mDocument; nsCOMPtr<nsIContentViewer> mContentViewer;
nsString mTitle; nsString mTitle;
nsCOMPtr<nsIInputStream> mPostData; nsCOMPtr<nsIInputStream> mPostData;
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState; nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
@ -86,9 +88,15 @@ private:
PRPackedBool mIsFrameNavigation; PRPackedBool mIsFrameNavigation;
PRPackedBool mSaveLayoutState; PRPackedBool mSaveLayoutState;
PRPackedBool mExpired; PRPackedBool mExpired;
PRPackedBool mSticky;
nsCString mContentType; nsCString mContentType;
nsCOMPtr<nsISupports> mCacheKey; nsCOMPtr<nsISupports> mCacheKey;
nsISHEntry * mParent; // weak reference nsISHEntry * mParent; // weak reference
nsCOMPtr<nsISupports> mWindowState;
nsRect mViewerBounds;
nsVoidArray mChildShells;
nsCOMPtr<nsISupports> mSecurityState;
nsCOMPtr<nsISupportsArray> mRefreshURIList;
}; };
#endif /* nsSHEntry_h */ #endif /* nsSHEntry_h */

Просмотреть файл

@ -54,9 +54,14 @@
#include "nsIDocShellLoadInfo.h" #include "nsIDocShellLoadInfo.h"
#include "nsIServiceManager.h" #include "nsIServiceManager.h"
#include "nsIPrefService.h" #include "nsIPrefService.h"
#include "nsIURI.h"
#include "nsIContentViewer.h"
#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries" #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
#define PREF_SHISTORY_VIEWERS "browser.sessionhistory.max_viewers"
static PRInt32 gHistoryMaxSize = 50; static PRInt32 gHistoryMaxSize = 50;
static PRInt32 gHistoryMaxViewers = 0;
enum HistCmd{ enum HistCmd{
HIST_CMD_BACK, HIST_CMD_BACK,
@ -104,11 +109,21 @@ nsSHistory::Init()
{ {
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) { if (prefs) {
// Session history size is only taken from the default prefs branch.
// This means that it's only configurable on a per-application basis.
// The goal of this is to unbreak users who have inadvertently set their
// session history size to -1.
nsCOMPtr<nsIPrefBranch> defaultBranch; nsCOMPtr<nsIPrefBranch> defaultBranch;
prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch)); prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch));
if (defaultBranch) { if (defaultBranch) {
defaultBranch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize); defaultBranch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize);
} }
// The size of the content viewer cache does not suffer from this problem,
// so we allow it to be overridden by user prefs.
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
if (branch)
branch->GetIntPref(PREF_SHISTORY_VIEWERS, &gHistoryMaxViewers);
} }
return NS_OK; return NS_OK;
} }
@ -207,6 +222,7 @@ nsSHistory::GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsISHEntry** aR
if (NS_SUCCEEDED(rv) && (*aResult)) { if (NS_SUCCEEDED(rv) && (*aResult)) {
// Set mIndex to the requested index, if asked to do so.. // Set mIndex to the requested index, if asked to do so..
if (aModifyIndex) { if (aModifyIndex) {
EvictContentViewers(mIndex, aIndex);
mIndex = aIndex; mIndex = aIndex;
} }
} //entry } //entry
@ -476,6 +492,14 @@ nsSHistory::GetListener(nsISHistoryListener ** aListener)
return NS_OK; return NS_OK;
} }
NS_IMETHODIMP
nsSHistory::EvictContentViewers()
{
// This is called after a new entry has been appended to the end of the list.
EvictContentViewers(mIndex - 1, mIndex);
return NS_OK;
}
//***************************************************************************** //*****************************************************************************
// nsSHistory: nsIWebNavigation // nsSHistory: nsIWebNavigation
//***************************************************************************** //*****************************************************************************
@ -583,12 +607,63 @@ nsSHistory::Reload(PRUint32 aReloadFlags)
return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD); return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD);
} }
void
nsSHistory::EvictContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex)
{
// To enforce the limit on cached content viewers, we need to release all
// of the content viewers that are no longer in the "window" that now
// ends/begins at aToIndex.
PRInt32 startIndex, endIndex;
if (aToIndex > aFromIndex) { // going forward
startIndex = PR_MAX(0, aFromIndex - gHistoryMaxViewers);
endIndex = PR_MAX(0, aToIndex - gHistoryMaxViewers);
} else { // going backward
startIndex = PR_MIN(mLength - 1, aToIndex + gHistoryMaxViewers);
endIndex = PR_MIN(mLength - 1, aFromIndex + gHistoryMaxViewers);
}
nsCOMPtr<nsISHTransaction> trans;
GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
for (PRInt32 i = startIndex; trans && i < endIndex; ++i) {
nsCOMPtr<nsISHEntry> entry;
trans->GetSHEntry(getter_AddRefs(entry));
nsCOMPtr<nsIContentViewer> viewer;
entry->GetContentViewer(getter_AddRefs(viewer));
if (viewer) {
#ifdef DEBUG_PAGE_CACHE
nsCOMPtr<nsIURI> uri;
entry->GetURI(getter_AddRefs(uri));
nsCAutoString spec;
if (uri)
uri->GetSpec(spec);
printf("Evicting content viewer: %s\n", spec.get());
#endif
viewer->Destroy();
entry->SetContentViewer(nsnull);
entry->SyncPresentationState();
}
nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
}
NS_IMETHODIMP NS_IMETHODIMP
nsSHistory::UpdateIndex() nsSHistory::UpdateIndex()
{ {
// Update the actual index with the right value. // Update the actual index with the right value.
if (mIndex != mRequestedIndex && mRequestedIndex != -1) if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
// We've just finished a history navigation (back or forward), so enforce
// the max number of content viewers.
EvictContentViewers(mIndex, mRequestedIndex);
mIndex = mRequestedIndex; mIndex = mRequestedIndex;
}
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -85,6 +85,8 @@ protected:
nsresult PrintHistory(); nsresult PrintHistory();
#endif #endif
void EvictContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex);
protected: protected:
nsCOMPtr<nsISHTransaction> mListRoot; nsCOMPtr<nsISHTransaction> mListRoot;
PRInt32 mIndex; PRInt32 mIndex;