2006-04-17 07:50:02 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
2005-08-18 11:15:08 +00:00
|
|
|
*
|
2005-08-18 11:16:53 +00:00
|
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
2005-08-18 11:15:08 +00:00
|
|
|
* The Original Code is the Mozilla browser.
|
2005-08-18 11:16:53 +00:00
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications, Inc.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1999
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
2005-08-18 11:15:08 +00:00
|
|
|
* Contributor(s):
|
|
|
|
* Radha Kulkarni <radha@netscape.com>
|
2005-08-18 11:16:53 +00:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2005-08-18 11:15:33 +00:00
|
|
|
// Local Includes
|
2005-08-18 11:15:08 +00:00
|
|
|
#include "nsSHistory.h"
|
|
|
|
|
2005-08-18 11:15:33 +00:00
|
|
|
// Helper Classes
|
|
|
|
#include "nsXPIDLString.h"
|
2005-08-18 11:16:18 +00:00
|
|
|
#include "nsReadableUtils.h"
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2005-08-18 11:15:33 +00:00
|
|
|
// Interfaces Needed
|
|
|
|
#include "nsILayoutHistoryState.h"
|
2005-08-18 11:16:44 +00:00
|
|
|
#include "nsIDocShell.h"
|
2005-08-18 11:15:34 +00:00
|
|
|
#include "nsIDocShellLoadInfo.h"
|
|
|
|
#include "nsISHContainer.h"
|
|
|
|
#include "nsIDocShellTreeItem.h"
|
|
|
|
#include "nsIDocShellTreeNode.h"
|
2005-08-18 11:15:37 +00:00
|
|
|
#include "nsIDocShellLoadInfo.h"
|
2005-08-18 11:15:47 +00:00
|
|
|
#include "nsIServiceManager.h"
|
2005-08-18 11:16:41 +00:00
|
|
|
#include "nsIPrefService.h"
|
2005-08-18 11:17:00 +00:00
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsIContentViewer.h"
|
2005-09-29 20:24:27 +00:00
|
|
|
#include "nsICacheService.h"
|
|
|
|
#include "nsIObserverService.h"
|
2005-09-23 18:16:40 +00:00
|
|
|
#include "prclist.h"
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 16:59:13 +00:00
|
|
|
#include "mozilla/Services.h"
|
2010-08-17 14:13:55 +00:00
|
|
|
#include "nsTArray.h"
|
|
|
|
#include "nsCOMArray.h"
|
2010-09-05 18:10:35 +00:00
|
|
|
#include "nsDocShell.h"
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
// For calculating max history entries and max cachable contentviewers
|
|
|
|
#include "nspr.h"
|
|
|
|
#include <math.h> // for log()
|
2005-08-18 11:15:59 +00:00
|
|
|
|
|
|
|
#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
|
2005-09-23 18:16:40 +00:00
|
|
|
#define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers"
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2005-08-18 11:16:31 +00:00
|
|
|
static PRInt32 gHistoryMaxSize = 50;
|
2005-09-23 18:16:40 +00:00
|
|
|
// Max viewers allowed per SHistory objects
|
|
|
|
static const PRInt32 gHistoryMaxViewers = 3;
|
|
|
|
// List of all SHistory objects, used for content viewer cache eviction
|
|
|
|
static PRCList gSHistoryList;
|
|
|
|
// Max viewers allowed total, across all SHistory objects - negative default
|
|
|
|
// means we will calculate how many viewers to cache based on total memory
|
|
|
|
PRInt32 nsSHistory::sHistoryMaxTotalViewers = -1;
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2005-08-18 11:16:17 +00:00
|
|
|
enum HistCmd{
|
|
|
|
HIST_CMD_BACK,
|
|
|
|
HIST_CMD_FORWARD,
|
|
|
|
HIST_CMD_GOTOINDEX,
|
|
|
|
HIST_CMD_RELOAD
|
|
|
|
} ;
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
//*****************************************************************************
|
2005-09-29 20:24:27 +00:00
|
|
|
//*** nsSHistoryObserver
|
2005-09-23 18:16:40 +00:00
|
|
|
//*****************************************************************************
|
|
|
|
|
2005-09-29 20:24:27 +00:00
|
|
|
class nsSHistoryObserver : public nsIObserver
|
2005-09-23 18:16:40 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
NS_DECL_NSIOBSERVER
|
|
|
|
|
2005-09-29 20:24:27 +00:00
|
|
|
nsSHistoryObserver() {}
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
protected:
|
2005-09-29 20:24:27 +00:00
|
|
|
~nsSHistoryObserver() {}
|
2005-09-23 18:16:40 +00:00
|
|
|
};
|
|
|
|
|
2005-09-29 20:24:27 +00:00
|
|
|
NS_IMPL_ISUPPORTS1(nsSHistoryObserver, nsIObserver)
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-09-29 20:24:27 +00:00
|
|
|
nsSHistoryObserver::Observe(nsISupports *aSubject, const char *aTopic,
|
|
|
|
const PRUnichar *aData)
|
2005-09-23 18:16:40 +00:00
|
|
|
{
|
|
|
|
if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
|
|
|
|
nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
|
2010-05-02 04:59:08 +00:00
|
|
|
if (prefs) {
|
|
|
|
nsSHistory::UpdatePrefs(prefs);
|
|
|
|
nsSHistory::EvictGlobalContentViewer();
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
2006-06-23 18:09:24 +00:00
|
|
|
} else if (!strcmp(aTopic, NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID) ||
|
|
|
|
!strcmp(aTopic, "memory-pressure")) {
|
2009-01-13 19:32:30 +00:00
|
|
|
nsSHistory::EvictAllContentViewersGlobally();
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:33 +00:00
|
|
|
//*****************************************************************************
|
|
|
|
//*** nsSHistory: Object Management
|
|
|
|
//*****************************************************************************
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2005-08-18 11:16:15 +00:00
|
|
|
nsSHistory::nsSHistory() : mListRoot(nsnull), mIndex(-1), mLength(0), mRequestedIndex(-1)
|
2005-08-18 11:15:08 +00:00
|
|
|
{
|
2005-09-23 18:16:40 +00:00
|
|
|
// Add this new SHistory object to the list
|
|
|
|
PR_APPEND_LINK(this, &gSHistoryList);
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nsSHistory::~nsSHistory()
|
|
|
|
{
|
2005-09-23 18:16:40 +00:00
|
|
|
// Remove this SHistory object from the list
|
|
|
|
PR_REMOVE_LINK(this);
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:33 +00:00
|
|
|
//*****************************************************************************
|
|
|
|
// nsSHistory: nsISupports
|
|
|
|
//*****************************************************************************
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsSHistory)
|
|
|
|
NS_IMPL_RELEASE(nsSHistory)
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsSHistory)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISHistory)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISHistory)
|
2005-08-18 11:15:39 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
|
2005-08-18 11:16:01 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISHistoryInternal)
|
2005-08-18 11:15:33 +00:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
|
|
// nsSHistory: nsISHistory
|
|
|
|
//*****************************************************************************
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
// static
|
|
|
|
PRUint32
|
2005-10-01 20:38:47 +00:00
|
|
|
nsSHistory::CalcMaxTotalViewers()
|
2005-09-23 18:16:40 +00:00
|
|
|
{
|
|
|
|
// Calculate an estimate of how many ContentViewers we should cache based
|
|
|
|
// on RAM. This assumes that the average ContentViewer is 4MB (conservative)
|
|
|
|
// and caps the max at 8 ContentViewers
|
|
|
|
//
|
|
|
|
// TODO: Should we split the cache memory betw. ContentViewer caching and
|
|
|
|
// nsCacheService?
|
|
|
|
//
|
|
|
|
// RAM ContentViewers
|
|
|
|
// -----------------------
|
|
|
|
// 32 Mb 0
|
|
|
|
// 64 Mb 1
|
|
|
|
// 128 Mb 2
|
|
|
|
// 256 Mb 3
|
|
|
|
// 512 Mb 5
|
|
|
|
// 1024 Mb 8
|
|
|
|
// 2048 Mb 8
|
|
|
|
// 4096 Mb 8
|
|
|
|
PRUint64 bytes = PR_GetPhysicalMemorySize();
|
|
|
|
|
|
|
|
if (LL_IS_ZERO(bytes))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Conversion from unsigned int64 to double doesn't work on all platforms.
|
|
|
|
// We need to truncate the value at LL_MAXINT to make sure we don't
|
|
|
|
// overflow.
|
|
|
|
if (LL_CMP(bytes, >, LL_MAXINT))
|
|
|
|
bytes = LL_MAXINT;
|
|
|
|
|
|
|
|
PRUint64 kbytes;
|
|
|
|
LL_SHR(kbytes, bytes, 10);
|
|
|
|
|
|
|
|
double kBytesD;
|
|
|
|
LL_L2D(kBytesD, (PRInt64) kbytes);
|
|
|
|
|
|
|
|
// This is essentially the same calculation as for nsCacheService,
|
|
|
|
// except that we divide the final memory calculation by 4, since
|
|
|
|
// we assume each ContentViewer takes on average 4MB
|
|
|
|
PRUint32 viewers = 0;
|
|
|
|
double x = log(kBytesD)/log(2.0) - 14;
|
|
|
|
if (x > 0) {
|
|
|
|
viewers = (PRUint32)(x * x - x + 2.001); // add .001 for rounding
|
|
|
|
viewers /= 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cap it off at 8 max
|
|
|
|
if (viewers > 8) {
|
|
|
|
viewers = 8;
|
|
|
|
}
|
|
|
|
return viewers;
|
|
|
|
}
|
|
|
|
|
2010-05-02 04:59:08 +00:00
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsSHistory::UpdatePrefs(nsIPrefBranch *aPrefBranch)
|
|
|
|
{
|
|
|
|
aPrefBranch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize);
|
|
|
|
aPrefBranch->GetIntPref(PREF_SHISTORY_MAX_TOTAL_VIEWERS,
|
|
|
|
&sHistoryMaxTotalViewers);
|
|
|
|
// If the pref is negative, that means we calculate how many viewers
|
|
|
|
// we think we should cache, based on total memory
|
|
|
|
if (sHistoryMaxTotalViewers < 0) {
|
|
|
|
sHistoryMaxTotalViewers = CalcMaxTotalViewers();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
nsSHistory::Startup()
|
2005-08-18 11:15:59 +00:00
|
|
|
{
|
2005-08-18 11:16:41 +00:00
|
|
|
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
|
|
|
if (prefs) {
|
2008-02-23 09:36:27 +00:00
|
|
|
nsCOMPtr<nsIPrefBranch> sesHBranch;
|
|
|
|
prefs->GetBranch(nsnull, getter_AddRefs(sesHBranch));
|
|
|
|
if (sesHBranch) {
|
2010-05-02 04:59:08 +00:00
|
|
|
UpdatePrefs(sesHBranch);
|
2008-02-23 09:36:27 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:17:00 +00:00
|
|
|
// The goal of this is to unbreak users who have inadvertently set their
|
2008-02-23 09:36:27 +00:00
|
|
|
// session history size to less than the default value.
|
|
|
|
PRInt32 defaultHistoryMaxSize = 50;
|
2005-08-18 11:16:41 +00:00
|
|
|
nsCOMPtr<nsIPrefBranch> defaultBranch;
|
|
|
|
prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch));
|
|
|
|
if (defaultBranch) {
|
2008-02-23 09:36:27 +00:00
|
|
|
defaultBranch->GetIntPref(PREF_SHISTORY_SIZE, &defaultHistoryMaxSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gHistoryMaxSize < defaultHistoryMaxSize) {
|
|
|
|
gHistoryMaxSize = defaultHistoryMaxSize;
|
2005-08-18 11:16:41 +00:00
|
|
|
}
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
// Allow the user to override the max total number of cached viewers,
|
|
|
|
// but keep the per SHistory cached viewer limit constant
|
2010-05-02 04:59:08 +00:00
|
|
|
nsCOMPtr<nsIPrefBranch2> branch = do_QueryInterface(sesHBranch);
|
2005-09-23 18:16:40 +00:00
|
|
|
if (branch) {
|
2005-09-29 20:24:27 +00:00
|
|
|
nsSHistoryObserver* obs = new nsSHistoryObserver();
|
2005-09-23 18:16:40 +00:00
|
|
|
if (!obs) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2010-05-02 04:59:08 +00:00
|
|
|
branch->AddObserver(PREF_SHISTORY_SIZE, obs, PR_FALSE);
|
2005-09-23 18:16:40 +00:00
|
|
|
branch->AddObserver(PREF_SHISTORY_MAX_TOTAL_VIEWERS,
|
|
|
|
obs, PR_FALSE);
|
2005-09-29 20:24:27 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obsSvc =
|
Bug 560095 - Use mozilla::services::GetObserverService(). r=biesi,dveditz,gavin,josh,jst,mrbkap,roc,sdwilsh,shaver,sicking,smontagu,surkov
2010-04-29 16:59:13 +00:00
|
|
|
mozilla::services::GetObserverService();
|
2005-09-29 20:24:27 +00:00
|
|
|
if (obsSvc) {
|
2006-06-23 18:09:24 +00:00
|
|
|
// Observe empty-cache notifications so tahat clearing the disk/memory
|
|
|
|
// cache will also evict all content viewers.
|
2005-09-29 20:24:27 +00:00
|
|
|
obsSvc->AddObserver(obs,
|
|
|
|
NS_CACHESERVICE_EMPTYCACHE_TOPIC_ID, PR_FALSE);
|
2006-06-23 18:09:24 +00:00
|
|
|
|
|
|
|
// Same for memory-pressure notifications
|
|
|
|
obsSvc->AddObserver(obs, "memory-pressure", PR_FALSE);
|
2005-09-29 20:24:27 +00:00
|
|
|
}
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the global list of all SHistory objects
|
|
|
|
PR_INIT_CLIST(&gSHistoryList);
|
2005-09-14 07:28:05 +00:00
|
|
|
return NS_OK;
|
2005-09-14 03:38:40 +00:00
|
|
|
}
|
2005-08-18 11:15:59 +00:00
|
|
|
|
2005-08-18 11:15:08 +00:00
|
|
|
/* Add an entry to the History list at mIndex and
|
|
|
|
* increment the index to point to the new entry
|
|
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:15:28 +00:00
|
|
|
nsSHistory::AddEntry(nsISHEntry * aSHEntry, PRBool aPersist)
|
2005-08-18 11:15:08 +00:00
|
|
|
{
|
2005-08-18 11:15:59 +00:00
|
|
|
NS_ENSURE_ARG(aSHEntry);
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
nsCOMPtr<nsISHTransaction> currentTxn;
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
if(mListRoot)
|
|
|
|
GetTransactionAtIndex(mIndex, getter_AddRefs(currentTxn));
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
PRBool currentPersist = PR_TRUE;
|
|
|
|
if(currentTxn)
|
|
|
|
currentTxn->GetPersist(¤tPersist);
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
if(!currentPersist)
|
|
|
|
{
|
|
|
|
NS_ENSURE_SUCCESS(currentTxn->SetSHEntry(aSHEntry),NS_ERROR_FAILURE);
|
|
|
|
currentTxn->SetPersist(aPersist);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
nsCOMPtr<nsISHTransaction> txn(do_CreateInstance(NS_SHTRANSACTION_CONTRACTID));
|
|
|
|
NS_ENSURE_TRUE(txn, NS_ERROR_FAILURE);
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:16:00 +00:00
|
|
|
// Notify any listener about the new addition
|
|
|
|
if (mListener) {
|
2005-08-18 11:16:04 +00:00
|
|
|
nsCOMPtr<nsISHistoryListener> listener(do_QueryReferent(mListener));
|
2005-08-18 11:16:00 +00:00
|
|
|
if (listener) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsIHistoryEntry> hEntry(do_QueryInterface(aSHEntry));
|
|
|
|
if (hEntry) {
|
2006-01-27 20:34:43 +00:00
|
|
|
PRInt32 currentIndex = mIndex;
|
2005-08-18 11:16:01 +00:00
|
|
|
hEntry->GetURI(getter_AddRefs(uri));
|
|
|
|
listener->OnHistoryNewEntry(uri);
|
2006-01-27 20:34:43 +00:00
|
|
|
|
|
|
|
// If a listener has changed mIndex, we need to get currentTxn again,
|
|
|
|
// otherwise we'll be left at an inconsistent state (see bug 320742)
|
|
|
|
if (currentIndex != mIndex)
|
|
|
|
GetTransactionAtIndex(mIndex, getter_AddRefs(currentTxn));
|
2005-08-18 11:16:01 +00:00
|
|
|
}
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
// 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);
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
// 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.
|
|
|
|
mLength = (++mIndex + 1);
|
|
|
|
|
|
|
|
// If this is the very first transaction, initialize the list
|
|
|
|
if(!mListRoot)
|
|
|
|
mListRoot = txn;
|
|
|
|
|
2006-01-27 20:34:43 +00:00
|
|
|
// Purge History list if it is too long
|
2005-08-18 11:15:59 +00:00
|
|
|
if ((gHistoryMaxSize >= 0) && (mLength > gHistoryMaxSize))
|
|
|
|
PurgeHistory(mLength-gHistoryMaxSize);
|
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
RemoveDynEntries(mIndex - 1, mIndex);
|
2005-08-18 11:15:59 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:18 +00:00
|
|
|
/* Get size of the history list */
|
2005-08-18 11:15:08 +00:00
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:15:18 +00:00
|
|
|
nsSHistory::GetCount(PRInt32 * aResult)
|
2005-08-18 11:15:08 +00:00
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
*aResult = mLength;
|
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get index of the history list */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetIndex(PRInt32 * aResult)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_PRECONDITION(aResult, "null out param?");
|
|
|
|
*aResult = mIndex;
|
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
2006-02-19 17:33:31 +00:00
|
|
|
/* Get the requestedIndex */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetRequestedIndex(PRInt32 * aResult)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_PRECONDITION(aResult, "null out param?");
|
|
|
|
*aResult = mRequestedIndex;
|
|
|
|
return NS_OK;
|
2006-02-19 17:33:31 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:14 +00:00
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:01 +00:00
|
|
|
nsSHistory::GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsISHEntry** aResult)
|
2005-08-18 11:15:14 +00:00
|
|
|
{
|
2005-08-18 11:16:01 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISHTransaction> txn;
|
|
|
|
|
|
|
|
/* GetTransactionAtIndex ensures aResult is valid and validates aIndex */
|
|
|
|
rv = GetTransactionAtIndex(aIndex, getter_AddRefs(txn));
|
|
|
|
if (NS_SUCCEEDED(rv) && txn) {
|
|
|
|
//Get the Entry from the transaction
|
2005-08-18 11:16:03 +00:00
|
|
|
rv = txn->GetSHEntry(aResult);
|
2005-08-18 11:16:01 +00:00
|
|
|
if (NS_SUCCEEDED(rv) && (*aResult)) {
|
|
|
|
// Set mIndex to the requested index, if asked to do so..
|
|
|
|
if (aModifyIndex) {
|
|
|
|
mIndex = aIndex;
|
|
|
|
}
|
|
|
|
} //entry
|
|
|
|
} //Transaction
|
|
|
|
return rv;
|
2005-08-18 11:15:14 +00:00
|
|
|
}
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2005-08-18 11:15:14 +00:00
|
|
|
|
|
|
|
/* Get the entry at a given index */
|
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:01 +00:00
|
|
|
nsSHistory::GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsIHistoryEntry** aResult)
|
2005-08-18 11:15:14 +00:00
|
|
|
{
|
2005-08-18 11:16:01 +00:00
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISHEntry> shEntry;
|
|
|
|
rv = GetEntryAtIndex(aIndex, aModifyIndex, getter_AddRefs(shEntry));
|
|
|
|
if (NS_SUCCEEDED(rv) && shEntry)
|
|
|
|
rv = CallQueryInterface(shEntry, aResult);
|
|
|
|
|
|
|
|
return rv;
|
2005-08-18 11:15:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the transaction at a given index */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetTransactionAtIndex(PRInt32 aIndex, nsISHTransaction ** aResult)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
nsresult rv;
|
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
|
|
|
|
if ((mLength <= 0) || (aIndex < 0) || (aIndex >= mLength))
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (!mListRoot)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
if (aIndex == 0)
|
|
|
|
{
|
|
|
|
*aResult = mListRoot;
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
PRInt32 cnt=0;
|
|
|
|
nsCOMPtr<nsISHTransaction> tempPtr;
|
|
|
|
|
|
|
|
rv = GetRootTransaction(getter_AddRefs(tempPtr));
|
|
|
|
if (NS_FAILED(rv) || !tempPtr)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
while(1) {
|
|
|
|
nsCOMPtr<nsISHTransaction> ptr;
|
|
|
|
rv = tempPtr->GetNext(getter_AddRefs(ptr));
|
|
|
|
if (NS_SUCCEEDED(rv) && ptr) {
|
|
|
|
cnt++;
|
|
|
|
if (cnt == aIndex) {
|
|
|
|
*aResult = ptr;
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tempPtr = ptr;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} //NS_SUCCEEDED
|
|
|
|
else
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
} // while
|
2005-08-18 11:15:14 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:52 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsresult
|
2005-08-18 11:15:14 +00:00
|
|
|
nsSHistory::PrintHistory()
|
|
|
|
{
|
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
nsCOMPtr<nsISHTransaction> txn;
|
|
|
|
PRInt32 index = 0;
|
|
|
|
nsresult rv;
|
2005-08-18 11:15:14 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
if (!mListRoot)
|
|
|
|
return NS_ERROR_FAILURE;
|
2005-08-18 11:15:14 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
txn = mListRoot;
|
2005-08-18 11:15:14 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
while (1) {
|
|
|
|
if (!txn)
|
|
|
|
break;
|
|
|
|
nsCOMPtr<nsISHEntry> entry;
|
|
|
|
rv = txn->GetSHEntry(getter_AddRefs(entry));
|
|
|
|
if (NS_FAILED(rv) && !entry)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsILayoutHistoryState> layoutHistoryState;
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
2006-04-17 08:37:23 +00:00
|
|
|
nsXPIDLString title;
|
2009-09-01 16:45:05 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
entry->GetLayoutHistoryState(getter_AddRefs(layoutHistoryState));
|
|
|
|
nsCOMPtr<nsIHistoryEntry> hEntry(do_QueryInterface(entry));
|
|
|
|
if (hEntry) {
|
|
|
|
hEntry->GetURI(getter_AddRefs(uri));
|
|
|
|
hEntry->GetTitle(getter_Copies(title));
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:35 +00:00
|
|
|
#if 0
|
2006-04-17 07:50:02 +00:00
|
|
|
nsCAutoString url;
|
|
|
|
if (uri)
|
|
|
|
uri->GetSpec(url);
|
|
|
|
|
|
|
|
printf("**** SH Transaction #%d, Entry = %x\n", index, entry.get());
|
2009-09-01 16:45:05 +00:00
|
|
|
printf("\t\t URL = %s\n", url.get());
|
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
printf("\t\t Title = %s\n", NS_LossyConvertUTF16toASCII(title).get());
|
2009-09-01 16:45:05 +00:00
|
|
|
printf("\t\t layout History Data = %x\n", layoutHistoryState.get());
|
2005-08-18 11:16:28 +00:00
|
|
|
#endif
|
2009-09-01 16:45:05 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
nsCOMPtr<nsISHTransaction> next;
|
|
|
|
rv = txn->GetNext(getter_AddRefs(next));
|
|
|
|
if (NS_SUCCEEDED(rv) && next) {
|
|
|
|
txn = next;
|
|
|
|
index++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
2005-08-18 11:15:14 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2005-08-18 11:16:52 +00:00
|
|
|
#endif
|
2005-08-18 11:15:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetRootTransaction(nsISHTransaction ** aResult)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
*aResult=mListRoot;
|
|
|
|
NS_IF_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
2005-08-18 11:15:14 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
/* Get the max size of the history list */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetMaxLength(PRInt32 * aResult)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
*aResult = gHistoryMaxSize;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the max size of the history list */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::SetMaxLength(PRInt32 aMaxSize)
|
|
|
|
{
|
|
|
|
if (aMaxSize < 0)
|
|
|
|
return NS_ERROR_ILLEGAL_VALUE;
|
|
|
|
|
|
|
|
gHistoryMaxSize = aMaxSize;
|
2005-08-18 11:16:17 +00:00
|
|
|
if (mLength > aMaxSize)
|
|
|
|
PurgeHistory(mLength-aMaxSize);
|
2005-08-18 11:15:59 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::PurgeHistory(PRInt32 aEntries)
|
|
|
|
{
|
|
|
|
if (mLength <= 0 || aEntries <= 0)
|
|
|
|
return NS_ERROR_FAILURE;
|
2005-08-18 11:16:51 +00:00
|
|
|
|
2010-02-09 17:09:06 +00:00
|
|
|
aEntries = NS_MIN(aEntries, mLength);
|
2005-08-18 11:16:51 +00:00
|
|
|
|
2005-08-18 11:16:00 +00:00
|
|
|
PRBool purgeHistory = PR_TRUE;
|
|
|
|
// Notify the listener about the history purge
|
|
|
|
if (mListener) {
|
2005-08-18 11:16:04 +00:00
|
|
|
nsCOMPtr<nsISHistoryListener> listener(do_QueryReferent(mListener));
|
2005-08-18 11:16:00 +00:00
|
|
|
if (listener) {
|
|
|
|
listener->OnHistoryPurge(aEntries, &purgeHistory);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!purgeHistory) {
|
|
|
|
// Listener asked us not to purge
|
2005-08-18 11:16:59 +00:00
|
|
|
return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA;
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 cnt = 0;
|
2005-08-18 11:15:59 +00:00
|
|
|
while (cnt < aEntries) {
|
|
|
|
nsCOMPtr<nsISHTransaction> nextTxn;
|
2010-11-26 10:29:22 +00:00
|
|
|
if (mListRoot) {
|
2005-08-18 11:15:59 +00:00
|
|
|
mListRoot->GetNext(getter_AddRefs(nextTxn));
|
2010-11-26 10:29:22 +00:00
|
|
|
mListRoot->SetNext(nsnull);
|
|
|
|
}
|
2005-08-18 11:15:59 +00:00
|
|
|
mListRoot = nextTxn;
|
2010-11-26 10:29:22 +00:00
|
|
|
if (mListRoot) {
|
|
|
|
mListRoot->SetPrev(nsnull);
|
|
|
|
}
|
2005-08-18 11:15:59 +00:00
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
mLength -= cnt;
|
|
|
|
mIndex -= cnt;
|
2005-08-18 11:16:51 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2008-09-11 21:54:40 +00:00
|
|
|
if (mRootDocShell)
|
|
|
|
mRootDocShell->HistoryPurged(cnt);
|
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:00 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::AddSHistoryListener(nsISHistoryListener * aListener)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aListener);
|
|
|
|
|
|
|
|
// Check if the listener supports Weak Reference. This is a must.
|
|
|
|
// This listener functionality is used by embedders and we want to
|
|
|
|
// have the right ownership with who ever listens to SHistory
|
2005-08-18 11:16:50 +00:00
|
|
|
nsWeakPtr listener = do_GetWeakReference(aListener);
|
2005-08-18 11:16:00 +00:00
|
|
|
if (!listener) return NS_ERROR_FAILURE;
|
|
|
|
mListener = listener;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::RemoveSHistoryListener(nsISHistoryListener * aListener)
|
|
|
|
{
|
2005-08-18 11:16:22 +00:00
|
|
|
// Make sure the listener that wants to be removed is the
|
|
|
|
// one we have in store.
|
2005-08-18 11:16:50 +00:00
|
|
|
nsWeakPtr listener = do_GetWeakReference(aListener);
|
2005-08-18 11:16:22 +00:00
|
|
|
if (listener == mListener) {
|
|
|
|
mListener = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:24 +00:00
|
|
|
|
|
|
|
/* Replace an entry in the History list at a particular index.
|
|
|
|
* Do not update index or count.
|
|
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::ReplaceEntry(PRInt32 aIndex, nsISHEntry * aReplaceEntry)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aReplaceEntry);
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsISHTransaction> currentTxn;
|
|
|
|
|
|
|
|
if (!mListRoot) // Session History is not initialised.
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
rv = GetTransactionAtIndex(aIndex, getter_AddRefs(currentTxn));
|
|
|
|
|
|
|
|
if(currentTxn)
|
|
|
|
{
|
|
|
|
// Set the replacement entry in the transaction
|
|
|
|
rv = currentTxn->SetSHEntry(aReplaceEntry);
|
|
|
|
rv = currentTxn->SetPersist(PR_TRUE);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:30 +00:00
|
|
|
/* Get a handle to the Session history listener */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetListener(nsISHistoryListener ** aListener)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aListener);
|
|
|
|
if (mListener)
|
|
|
|
CallQueryReferent(mListener.get(), aListener);
|
|
|
|
// Don't addref aListener. It is a weak pointer.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:17:00 +00:00
|
|
|
NS_IMETHODIMP
|
2008-09-11 21:54:40 +00:00
|
|
|
nsSHistory::EvictContentViewers(PRInt32 aPreviousIndex, PRInt32 aIndex)
|
2005-08-18 11:17:00 +00:00
|
|
|
{
|
2008-09-11 21:54:40 +00:00
|
|
|
// Check our per SHistory object limit in the currently navigated SHistory
|
|
|
|
EvictWindowContentViewers(aPreviousIndex, aIndex);
|
2005-09-23 18:16:40 +00:00
|
|
|
// Check our total limit across all SHistory objects
|
|
|
|
EvictGlobalContentViewer();
|
2005-08-18 11:17:00 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2009-01-13 19:32:30 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::EvictAllContentViewers()
|
|
|
|
{
|
|
|
|
// XXXbz we don't actually do a good job of evicting things as we should, so
|
|
|
|
// we might have viewers quite far from mIndex. So just evict everything.
|
|
|
|
EvictContentViewersInRange(0, mLength);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-08-18 11:15:34 +00:00
|
|
|
//*****************************************************************************
|
|
|
|
// nsSHistory: nsIWebNavigation
|
|
|
|
//*****************************************************************************
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetCanGoBack(PRBool * aCanGoBack)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aCanGoBack);
|
|
|
|
*aCanGoBack = PR_FALSE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
PRInt32 index = -1;
|
|
|
|
NS_ENSURE_SUCCESS(GetIndex(&index), NS_ERROR_FAILURE);
|
|
|
|
if(index > 0)
|
|
|
|
*aCanGoBack = PR_TRUE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetCanGoForward(PRBool * aCanGoForward)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aCanGoForward);
|
|
|
|
*aCanGoForward = PR_FALSE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
PRInt32 index = -1;
|
|
|
|
PRInt32 count = -1;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_SUCCESS(GetIndex(&index), NS_ERROR_FAILURE);
|
|
|
|
NS_ENSURE_SUCCESS(GetCount(&count), NS_ERROR_FAILURE);
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
if((index >= 0) && (index < (count - 1)))
|
|
|
|
*aCanGoForward = PR_TRUE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
2005-08-18 11:15:37 +00:00
|
|
|
|
2005-08-18 11:15:34 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GoBack()
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
PRBool canGoBack = PR_FALSE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
GetCanGoBack(&canGoBack);
|
|
|
|
if (!canGoBack) // Can't go back
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2005-08-18 11:16:17 +00:00
|
|
|
return LoadEntry(mIndex-1, nsIDocShellLoadInfo::loadHistory, HIST_CMD_BACK);
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GoForward()
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
PRBool canGoForward = PR_FALSE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
GetCanGoForward(&canGoForward);
|
|
|
|
if (!canGoForward) // Can't go forward
|
|
|
|
return NS_ERROR_UNEXPECTED;
|
2005-08-18 11:16:17 +00:00
|
|
|
return LoadEntry(mIndex+1, nsIDocShellLoadInfo::loadHistory, HIST_CMD_FORWARD);
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:15:51 +00:00
|
|
|
nsSHistory::Reload(PRUint32 aReloadFlags)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2005-08-18 11:16:00 +00:00
|
|
|
nsresult rv;
|
2006-04-17 07:50:02 +00:00
|
|
|
nsDocShellInfoLoadType loadType;
|
|
|
|
if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY &&
|
|
|
|
aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)
|
|
|
|
{
|
|
|
|
loadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
|
|
|
|
}
|
|
|
|
else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY)
|
|
|
|
{
|
|
|
|
loadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
|
|
|
|
}
|
|
|
|
else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE)
|
|
|
|
{
|
|
|
|
loadType = nsIDocShellLoadInfo::loadReloadBypassCache;
|
|
|
|
}
|
2005-08-18 11:16:06 +00:00
|
|
|
else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
loadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
|
2005-08-18 11:16:06 +00:00
|
|
|
}
|
|
|
|
else
|
2006-04-17 07:50:02 +00:00
|
|
|
{
|
|
|
|
loadType = nsIDocShellLoadInfo::loadReloadNormal;
|
|
|
|
}
|
2005-08-18 11:16:00 +00:00
|
|
|
|
|
|
|
// Notify listeners
|
|
|
|
PRBool canNavigate = PR_TRUE;
|
|
|
|
if (mListener) {
|
2005-08-18 11:16:04 +00:00
|
|
|
nsCOMPtr<nsISHistoryListener> listener(do_QueryReferent(mListener));
|
2005-08-18 11:16:00 +00:00
|
|
|
// We are reloading. Send Reload notifications.
|
|
|
|
// nsDocShellLoadFlagType is not public, where as nsIWebNavigation
|
|
|
|
// is public. So send the reload notifications with the
|
|
|
|
// nsIWebNavigation flags.
|
|
|
|
if (listener) {
|
|
|
|
nsCOMPtr<nsIURI> currentURI;
|
|
|
|
rv = GetCurrentURI(getter_AddRefs(currentURI));
|
|
|
|
listener->OnHistoryReload(currentURI, aReloadFlags, &canNavigate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!canNavigate)
|
|
|
|
return NS_OK;
|
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD);
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:17:00 +00:00
|
|
|
void
|
2005-09-23 18:16:40 +00:00
|
|
|
nsSHistory::EvictWindowContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex)
|
2005-08-18 11:17:00 +00:00
|
|
|
{
|
2005-09-23 18:16:40 +00:00
|
|
|
// To enforce the per SHistory object limit on cached content viewers, we
|
|
|
|
// need to release all of the content viewers that are no longer in the
|
2007-09-28 02:56:08 +00:00
|
|
|
// "window" that now ends/begins at aToIndex. Existing content viewers
|
|
|
|
// should be in the window from
|
|
|
|
// aFromIndex - gHistoryMaxViewers to aFromIndex + gHistoryMaxViewers
|
|
|
|
//
|
|
|
|
// We make the assumption that entries outside this range have no viewers so
|
|
|
|
// that we don't have to walk the whole entire session history checking for
|
|
|
|
// content viewers.
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
// This can happen on the first load of a page in a particular window
|
|
|
|
if (aFromIndex < 0 || aToIndex < 0) {
|
|
|
|
return;
|
|
|
|
}
|
2008-03-07 07:47:30 +00:00
|
|
|
NS_ASSERTION(aFromIndex < mLength, "aFromIndex is out of range");
|
|
|
|
NS_ASSERTION(aToIndex < mLength, "aToIndex is out of range");
|
|
|
|
if (aFromIndex >= mLength || aToIndex >= mLength) {
|
|
|
|
return;
|
|
|
|
}
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
// These indices give the range of SHEntries whose content viewers will be
|
|
|
|
// evicted
|
2005-08-18 11:17:00 +00:00
|
|
|
PRInt32 startIndex, endIndex;
|
|
|
|
if (aToIndex > aFromIndex) { // going forward
|
2005-09-23 18:16:40 +00:00
|
|
|
endIndex = aToIndex - gHistoryMaxViewers;
|
|
|
|
if (endIndex <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
2010-02-09 17:09:06 +00:00
|
|
|
startIndex = NS_MAX(0, aFromIndex - gHistoryMaxViewers);
|
2005-08-18 11:17:00 +00:00
|
|
|
} else { // going backward
|
2005-09-23 18:16:40 +00:00
|
|
|
startIndex = aToIndex + gHistoryMaxViewers + 1;
|
|
|
|
if (startIndex >= mLength) {
|
|
|
|
return;
|
|
|
|
}
|
2010-02-09 17:09:06 +00:00
|
|
|
endIndex = NS_MIN(mLength, aFromIndex + gHistoryMaxViewers + 1);
|
2005-08-18 11:17:00 +00:00
|
|
|
}
|
2007-11-17 06:28:56 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsCOMPtr<nsISHTransaction> trans;
|
|
|
|
GetTransactionAtIndex(0, getter_AddRefs(trans));
|
|
|
|
|
|
|
|
// Walk the full session history and check that entries outside the window
|
|
|
|
// around aFromIndex have no content viewers
|
|
|
|
for (PRInt32 i = 0; i < mLength; ++i) {
|
|
|
|
if (i < aFromIndex - gHistoryMaxViewers ||
|
|
|
|
i > aFromIndex + gHistoryMaxViewers) {
|
|
|
|
nsCOMPtr<nsISHEntry> entry;
|
|
|
|
trans->GetSHEntry(getter_AddRefs(entry));
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
|
|
nsCOMPtr<nsISHEntry> ownerEntry;
|
|
|
|
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
|
|
|
|
getter_AddRefs(viewer));
|
2009-12-12 21:47:37 +00:00
|
|
|
NS_WARN_IF_FALSE(!viewer,
|
|
|
|
"ContentViewer exists outside gHistoryMaxViewer range");
|
2007-11-17 06:28:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsISHTransaction *temp = trans;
|
|
|
|
temp->GetNext(getter_AddRefs(trans));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-09-21 09:19:59 +00:00
|
|
|
EvictContentViewersInRange(startIndex, endIndex);
|
|
|
|
}
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2007-09-21 09:19:59 +00:00
|
|
|
void
|
|
|
|
nsSHistory::EvictContentViewersInRange(PRInt32 aStart, PRInt32 aEnd)
|
|
|
|
{
|
2005-08-18 11:17:00 +00:00
|
|
|
nsCOMPtr<nsISHTransaction> trans;
|
2007-09-21 09:19:59 +00:00
|
|
|
GetTransactionAtIndex(aStart, getter_AddRefs(trans));
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2007-09-21 09:19:59 +00:00
|
|
|
for (PRInt32 i = aStart; i < aEnd; ++i) {
|
2005-08-18 11:17:00 +00:00
|
|
|
nsCOMPtr<nsISHEntry> entry;
|
|
|
|
trans->GetSHEntry(getter_AddRefs(entry));
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
2005-09-23 18:16:40 +00:00
|
|
|
nsCOMPtr<nsISHEntry> ownerEntry;
|
|
|
|
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
|
|
|
|
getter_AddRefs(viewer));
|
2005-08-18 11:17:00 +00:00
|
|
|
if (viewer) {
|
2005-09-23 18:16:40 +00:00
|
|
|
NS_ASSERTION(ownerEntry,
|
|
|
|
"ContentViewer exists but its SHEntry is null");
|
2009-09-01 16:45:05 +00:00
|
|
|
#ifdef DEBUG_PAGE_CACHE
|
2005-08-18 11:17:00 +00:00
|
|
|
nsCOMPtr<nsIURI> uri;
|
2005-09-23 18:16:40 +00:00
|
|
|
ownerEntry->GetURI(getter_AddRefs(uri));
|
2005-08-18 11:17:00 +00:00
|
|
|
nsCAutoString spec;
|
|
|
|
if (uri)
|
|
|
|
uri->GetSpec(spec);
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
printf("per SHistory limit: evicting content viewer: %s\n", spec.get());
|
2005-08-18 11:17:00 +00:00
|
|
|
#endif
|
|
|
|
|
2006-01-05 21:01:24 +00:00
|
|
|
// Drop the presentation state before destroying the viewer, so that
|
|
|
|
// document teardown is able to correctly persist the state.
|
2005-09-23 18:16:40 +00:00
|
|
|
ownerEntry->SetContentViewer(nsnull);
|
|
|
|
ownerEntry->SyncPresentationState();
|
2006-01-05 21:01:24 +00:00
|
|
|
viewer->Destroy();
|
2005-08-18 11:17:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsISHTransaction *temp = trans;
|
|
|
|
temp->GetNext(getter_AddRefs(trans));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsSHistory::EvictGlobalContentViewer()
|
|
|
|
{
|
|
|
|
// true until the total number of content viewers is <= total max
|
|
|
|
// The usual case is that we only need to evict one content viewer.
|
|
|
|
// However, if somebody resets the pref value, we might occasionally
|
|
|
|
// need to evict more than one.
|
|
|
|
PRBool shouldTryEviction = PR_TRUE;
|
|
|
|
while (shouldTryEviction) {
|
|
|
|
// Walk through our list of SHistory objects, looking for content
|
|
|
|
// viewers in the possible active window of all of the SHEntry objects.
|
|
|
|
// Keep track of the SHEntry object that has a ContentViewer and is
|
|
|
|
// farthest from the current focus in any SHistory object. The
|
|
|
|
// ContentViewer associated with that SHEntry will be evicted
|
|
|
|
PRInt32 distanceFromFocus = 0;
|
|
|
|
nsCOMPtr<nsISHEntry> evictFromSHE;
|
|
|
|
nsCOMPtr<nsIContentViewer> evictViewer;
|
|
|
|
PRInt32 totalContentViewers = 0;
|
2007-07-08 07:08:04 +00:00
|
|
|
nsSHistory* shist = static_cast<nsSHistory*>
|
|
|
|
(PR_LIST_HEAD(&gSHistoryList));
|
2005-09-23 18:16:40 +00:00
|
|
|
while (shist != &gSHistoryList) {
|
|
|
|
// Calculate the window of SHEntries that could possibly have a content
|
|
|
|
// viewer. There could be up to gHistoryMaxViewers content viewers,
|
|
|
|
// but we don't know whether they are before or after the mIndex position
|
|
|
|
// in the SHEntry list. Just check both sides, to be safe.
|
2010-02-09 17:09:06 +00:00
|
|
|
PRInt32 startIndex = NS_MAX(0, shist->mIndex - gHistoryMaxViewers);
|
|
|
|
PRInt32 endIndex = NS_MIN(shist->mLength - 1,
|
2005-09-23 18:16:40 +00:00
|
|
|
shist->mIndex + gHistoryMaxViewers);
|
|
|
|
nsCOMPtr<nsISHTransaction> trans;
|
|
|
|
shist->GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
|
|
|
|
|
|
|
|
for (PRInt32 i = startIndex; i <= endIndex; ++i) {
|
|
|
|
nsCOMPtr<nsISHEntry> entry;
|
|
|
|
trans->GetSHEntry(getter_AddRefs(entry));
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
|
|
nsCOMPtr<nsISHEntry> ownerEntry;
|
|
|
|
entry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
|
|
|
|
getter_AddRefs(viewer));
|
|
|
|
|
|
|
|
#ifdef DEBUG_PAGE_CACHE
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
if (ownerEntry) {
|
|
|
|
ownerEntry->GetURI(getter_AddRefs(uri));
|
|
|
|
} else {
|
|
|
|
entry->GetURI(getter_AddRefs(uri));
|
|
|
|
}
|
|
|
|
nsCAutoString spec;
|
|
|
|
if (uri) {
|
|
|
|
uri->GetSpec(spec);
|
|
|
|
printf("Considering for eviction: %s\n", spec.get());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// This SHEntry has a ContentViewer, so check how far away it is from
|
|
|
|
// the currently used SHEntry within this SHistory object
|
|
|
|
if (viewer) {
|
|
|
|
PRInt32 distance = PR_ABS(shist->mIndex - i);
|
|
|
|
|
|
|
|
#ifdef DEBUG_PAGE_CACHE
|
|
|
|
printf("Has a cached content viewer: %s\n", spec.get());
|
|
|
|
printf("mIndex: %d i: %d\n", shist->mIndex, i);
|
|
|
|
#endif
|
|
|
|
totalContentViewers++;
|
|
|
|
if (distance > distanceFromFocus) {
|
|
|
|
|
|
|
|
#ifdef DEBUG_PAGE_CACHE
|
|
|
|
printf("Choosing as new eviction candidate: %s\n", spec.get());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
distanceFromFocus = distance;
|
|
|
|
evictFromSHE = ownerEntry;
|
|
|
|
evictViewer = viewer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsISHTransaction* temp = trans;
|
|
|
|
temp->GetNext(getter_AddRefs(trans));
|
|
|
|
}
|
2007-07-08 07:08:04 +00:00
|
|
|
shist = static_cast<nsSHistory*>(PR_NEXT_LINK(shist));
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_PAGE_CACHE
|
|
|
|
printf("Distance from focus: %d\n", distanceFromFocus);
|
|
|
|
printf("Total max viewers: %d\n", sHistoryMaxTotalViewers);
|
|
|
|
printf("Total number of viewers: %d\n", totalContentViewers);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (totalContentViewers > sHistoryMaxTotalViewers && evictViewer) {
|
|
|
|
#ifdef DEBUG_PAGE_CACHE
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
evictFromSHE->GetURI(getter_AddRefs(uri));
|
|
|
|
nsCAutoString spec;
|
|
|
|
if (uri) {
|
|
|
|
uri->GetSpec(spec);
|
|
|
|
printf("Evicting content viewer: %s\n", spec.get());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-01-05 21:01:24 +00:00
|
|
|
// Drop the presentation state before destroying the viewer, so that
|
|
|
|
// document teardown is able to correctly persist the state.
|
2005-09-23 18:16:40 +00:00
|
|
|
evictFromSHE->SetContentViewer(nsnull);
|
|
|
|
evictFromSHE->SyncPresentationState();
|
2006-01-05 21:01:24 +00:00
|
|
|
evictViewer->Destroy();
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
// If we only needed to evict one content viewer, then we are done.
|
|
|
|
// Otherwise, continue evicting until we reach the max total limit.
|
|
|
|
if (totalContentViewers - sHistoryMaxTotalViewers == 1) {
|
|
|
|
shouldTryEviction = PR_FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// couldn't find a content viewer to evict, so we are done
|
|
|
|
shouldTryEviction = PR_FALSE;
|
|
|
|
}
|
|
|
|
} // while shouldTryEviction
|
|
|
|
}
|
|
|
|
|
2007-09-21 09:19:59 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::EvictExpiredContentViewerForEntry(nsISHEntry *aEntry)
|
|
|
|
{
|
2010-02-09 17:09:06 +00:00
|
|
|
PRInt32 startIndex = NS_MAX(0, mIndex - gHistoryMaxViewers);
|
|
|
|
PRInt32 endIndex = NS_MIN(mLength - 1,
|
2007-09-21 09:19:59 +00:00
|
|
|
mIndex + gHistoryMaxViewers);
|
|
|
|
nsCOMPtr<nsISHTransaction> trans;
|
|
|
|
GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
|
|
|
|
|
|
|
|
PRInt32 i;
|
|
|
|
for (i = startIndex; i <= endIndex; ++i) {
|
|
|
|
nsCOMPtr<nsISHEntry> entry;
|
|
|
|
trans->GetSHEntry(getter_AddRefs(entry));
|
|
|
|
if (entry == aEntry)
|
|
|
|
break;
|
|
|
|
|
|
|
|
nsISHTransaction *temp = trans;
|
|
|
|
temp->GetNext(getter_AddRefs(trans));
|
|
|
|
}
|
|
|
|
if (i > endIndex)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
NS_ASSERTION(i != mIndex, "How did the current session entry expire?");
|
|
|
|
if (i == mIndex)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
// We evict content viewers for the expired entry and any other entries that
|
|
|
|
// we would have to go through the expired entry to get to (i.e. the entries
|
|
|
|
// that have the expired entry between them and the current entry). Those
|
|
|
|
// other entries should have timed out already, actually, but this is just
|
|
|
|
// to be on the safe side.
|
|
|
|
if (i < mIndex) {
|
|
|
|
EvictContentViewersInRange(startIndex, i + 1);
|
|
|
|
} else {
|
|
|
|
EvictContentViewersInRange(i, endIndex + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-09-29 20:24:27 +00:00
|
|
|
// Evicts all content viewers in all history objects. This is very
|
|
|
|
// inefficient, because it requires a linear search through all SHistory
|
|
|
|
// objects for each viewer to be evicted. However, this method is called
|
|
|
|
// infrequently -- only when the disk or memory cache is cleared.
|
|
|
|
|
|
|
|
//static
|
|
|
|
void
|
2009-01-13 19:32:30 +00:00
|
|
|
nsSHistory::EvictAllContentViewersGlobally()
|
2005-09-29 20:24:27 +00:00
|
|
|
{
|
|
|
|
PRInt32 maxViewers = sHistoryMaxTotalViewers;
|
|
|
|
sHistoryMaxTotalViewers = 0;
|
|
|
|
EvictGlobalContentViewer();
|
|
|
|
sHistoryMaxTotalViewers = maxViewers;
|
|
|
|
}
|
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
void GetDynamicChildren(nsISHContainer* aContainer,
|
|
|
|
nsTArray<PRUint64>& aDocshellIDs,
|
|
|
|
PRBool aOnlyTopLevelDynamic)
|
|
|
|
{
|
|
|
|
PRInt32 count = 0;
|
|
|
|
aContainer->GetChildCount(&count);
|
|
|
|
for (PRInt32 i = 0; i < count; ++i) {
|
|
|
|
nsCOMPtr<nsISHEntry> child;
|
|
|
|
aContainer->GetChildAt(i, getter_AddRefs(child));
|
|
|
|
if (child) {
|
|
|
|
PRBool dynAdded = PR_FALSE;
|
|
|
|
child->IsDynamicallyAdded(&dynAdded);
|
|
|
|
if (dynAdded) {
|
|
|
|
PRUint64 docshellID = 0;
|
|
|
|
child->GetDocshellID(&docshellID);
|
|
|
|
aDocshellIDs.AppendElement(docshellID);
|
|
|
|
}
|
|
|
|
if (!dynAdded || !aOnlyTopLevelDynamic) {
|
|
|
|
nsCOMPtr<nsISHContainer> childAsContainer = do_QueryInterface(child);
|
|
|
|
if (childAsContainer) {
|
|
|
|
GetDynamicChildren(childAsContainer, aDocshellIDs,
|
|
|
|
aOnlyTopLevelDynamic);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
RemoveFromSessionHistoryContainer(nsISHContainer* aContainer,
|
|
|
|
nsTArray<PRUint64>& aDocshellIDs)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISHEntry> root = do_QueryInterface(aContainer);
|
|
|
|
NS_ENSURE_TRUE(root, PR_FALSE);
|
|
|
|
|
|
|
|
PRBool didRemove = PR_FALSE;
|
|
|
|
PRInt32 childCount = 0;
|
|
|
|
aContainer->GetChildCount(&childCount);
|
|
|
|
for (PRInt32 i = childCount - 1; i >= 0; --i) {
|
|
|
|
nsCOMPtr<nsISHEntry> child;
|
|
|
|
aContainer->GetChildAt(i, getter_AddRefs(child));
|
|
|
|
if (child) {
|
|
|
|
PRUint64 docshelldID = 0;
|
|
|
|
child->GetDocshellID(&docshelldID);
|
|
|
|
if (aDocshellIDs.Contains(docshelldID)) {
|
|
|
|
didRemove = PR_TRUE;
|
|
|
|
aContainer->RemoveChild(child);
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsISHContainer> container = do_QueryInterface(child);
|
|
|
|
if (container) {
|
|
|
|
PRBool childRemoved =
|
|
|
|
RemoveFromSessionHistoryContainer(container, aDocshellIDs);
|
|
|
|
if (childRemoved) {
|
|
|
|
didRemove = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return didRemove;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool RemoveChildEntries(nsISHistory* aHistory, PRInt32 aIndex,
|
|
|
|
nsTArray<PRUint64>& aEntryIDs)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIHistoryEntry> rootHE;
|
|
|
|
aHistory->GetEntryAtIndex(aIndex, PR_FALSE, getter_AddRefs(rootHE));
|
|
|
|
nsCOMPtr<nsISHContainer> root = do_QueryInterface(rootHE);
|
|
|
|
return root ? RemoveFromSessionHistoryContainer(root, aEntryIDs) : PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-09-05 18:10:35 +00:00
|
|
|
PRBool IsSameTree(nsISHEntry* aEntry1, nsISHEntry* aEntry2)
|
|
|
|
{
|
|
|
|
if (!aEntry1 && !aEntry2) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
if ((!aEntry1 && aEntry2) || (aEntry1 && !aEntry2)) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
PRUint32 id1, id2;
|
|
|
|
aEntry1->GetID(&id1);
|
|
|
|
aEntry2->GetID(&id2);
|
|
|
|
if (id1 != id2) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsISHContainer> container1 = do_QueryInterface(aEntry1);
|
|
|
|
nsCOMPtr<nsISHContainer> container2 = do_QueryInterface(aEntry2);
|
|
|
|
PRInt32 count1, count2;
|
|
|
|
container1->GetChildCount(&count1);
|
|
|
|
container2->GetChildCount(&count2);
|
|
|
|
// We allow null entries in the end of the child list.
|
|
|
|
PRInt32 count = PR_MAX(count1, count2);
|
|
|
|
for (PRInt32 i = 0; i < count; ++i) {
|
|
|
|
nsCOMPtr<nsISHEntry> child1, child2;
|
|
|
|
container1->GetChildAt(i, getter_AddRefs(child1));
|
|
|
|
container2->GetChildAt(i, getter_AddRefs(child2));
|
|
|
|
if (!IsSameTree(child1, child2)) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2010-11-15 10:11:51 +00:00
|
|
|
nsSHistory::RemoveDuplicate(PRInt32 aIndex, PRBool aKeepNext)
|
2010-09-05 18:10:35 +00:00
|
|
|
{
|
2010-11-15 10:11:51 +00:00
|
|
|
NS_ASSERTION(aIndex >= 0, "aIndex must be >= 0!");
|
|
|
|
NS_ASSERTION(aIndex != mIndex, "Shouldn't remove mIndex!");
|
|
|
|
PRInt32 compareIndex = aKeepNext ? aIndex + 1 : aIndex - 1;
|
2010-09-05 18:10:35 +00:00
|
|
|
nsCOMPtr<nsIHistoryEntry> rootHE1, rootHE2;
|
|
|
|
GetEntryAtIndex(aIndex, PR_FALSE, getter_AddRefs(rootHE1));
|
2010-11-15 10:11:51 +00:00
|
|
|
GetEntryAtIndex(compareIndex, PR_FALSE, getter_AddRefs(rootHE2));
|
2010-09-05 18:10:35 +00:00
|
|
|
nsCOMPtr<nsISHEntry> root1 = do_QueryInterface(rootHE1);
|
|
|
|
nsCOMPtr<nsISHEntry> root2 = do_QueryInterface(rootHE2);
|
|
|
|
if (IsSameTree(root1, root2)) {
|
2010-11-15 10:11:51 +00:00
|
|
|
nsCOMPtr<nsISHTransaction> txToRemove, txToKeep, txNext, txPrev;
|
2010-09-05 18:10:35 +00:00
|
|
|
GetTransactionAtIndex(aIndex, getter_AddRefs(txToRemove));
|
2010-11-15 10:11:51 +00:00
|
|
|
GetTransactionAtIndex(compareIndex, getter_AddRefs(txToKeep));
|
2010-09-05 18:10:35 +00:00
|
|
|
NS_ENSURE_TRUE(txToRemove, PR_FALSE);
|
|
|
|
NS_ENSURE_TRUE(txToKeep, PR_FALSE);
|
|
|
|
txToRemove->GetNext(getter_AddRefs(txNext));
|
2010-11-15 10:11:51 +00:00
|
|
|
txToRemove->GetPrev(getter_AddRefs(txPrev));
|
2010-09-05 18:10:35 +00:00
|
|
|
txToRemove->SetNext(nsnull);
|
|
|
|
txToRemove->SetPrev(nsnull);
|
2010-11-15 10:11:51 +00:00
|
|
|
if (aKeepNext) {
|
|
|
|
if (txPrev) {
|
|
|
|
txPrev->SetNext(txToKeep);
|
|
|
|
} else {
|
|
|
|
txToKeep->SetPrev(nsnull);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
txToKeep->SetNext(txNext);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aIndex == 0 && aKeepNext) {
|
|
|
|
NS_ASSERTION(txToRemove == mListRoot,
|
|
|
|
"Transaction at index 0 should be mListRoot!");
|
|
|
|
// We're removing the very first session history transaction!
|
|
|
|
mListRoot = txToKeep;
|
|
|
|
}
|
2010-11-19 12:01:10 +00:00
|
|
|
if (mRootDocShell) {
|
|
|
|
static_cast<nsDocShell*>(mRootDocShell)->HistoryTransactionRemoved(aIndex);
|
|
|
|
}
|
2010-11-15 10:11:51 +00:00
|
|
|
if (mIndex > aIndex) {
|
2010-09-05 18:10:35 +00:00
|
|
|
mIndex = mIndex - 1;
|
|
|
|
}
|
|
|
|
--mLength;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
NS_IMETHODIMP_(void)
|
|
|
|
nsSHistory::RemoveEntries(nsTArray<PRUint64>& aIDs, PRInt32 aStartIndex)
|
|
|
|
{
|
|
|
|
PRInt32 index = aStartIndex;
|
|
|
|
while(index >= 0 && RemoveChildEntries(this, --index, aIDs));
|
2010-11-15 10:11:51 +00:00
|
|
|
PRInt32 minIndex = index;
|
2010-08-17 14:13:55 +00:00
|
|
|
index = aStartIndex;
|
|
|
|
while(index >= 0 && RemoveChildEntries(this, index++, aIDs));
|
2010-09-05 18:10:35 +00:00
|
|
|
|
|
|
|
// We need to remove duplicate nsSHEntry trees.
|
|
|
|
PRBool didRemove = PR_FALSE;
|
2010-11-15 10:11:51 +00:00
|
|
|
while (index > minIndex) {
|
|
|
|
if (index != mIndex) {
|
|
|
|
didRemove = RemoveDuplicate(index, index < mIndex) || didRemove;
|
|
|
|
}
|
|
|
|
--index;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
|
|
|
if (didRemove && mRootDocShell) {
|
|
|
|
nsRefPtr<nsIRunnable> ev =
|
|
|
|
NS_NewRunnableMethod(static_cast<nsDocShell*>(mRootDocShell),
|
|
|
|
&nsDocShell::FireDummyOnLocationChange);
|
|
|
|
NS_DispatchToCurrentThread(ev);
|
|
|
|
}
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSHistory::RemoveDynEntries(PRInt32 aOldIndex, PRInt32 aNewIndex)
|
|
|
|
{
|
|
|
|
// Search for the entries which are in the current index,
|
|
|
|
// but not in the new one.
|
|
|
|
nsCOMPtr<nsISHEntry> originalSH;
|
|
|
|
GetEntryAtIndex(aOldIndex, PR_FALSE, getter_AddRefs(originalSH));
|
|
|
|
nsCOMPtr<nsISHContainer> originalContainer = do_QueryInterface(originalSH);
|
|
|
|
nsAutoTArray<PRUint64, 16> toBeRemovedEntries;
|
|
|
|
if (originalContainer) {
|
|
|
|
nsTArray<PRUint64> originalDynDocShellIDs;
|
|
|
|
GetDynamicChildren(originalContainer, originalDynDocShellIDs, PR_TRUE);
|
|
|
|
if (originalDynDocShellIDs.Length()) {
|
|
|
|
nsCOMPtr<nsISHEntry> currentSH;
|
|
|
|
GetEntryAtIndex(aNewIndex, PR_FALSE, getter_AddRefs(currentSH));
|
|
|
|
nsCOMPtr<nsISHContainer> newContainer = do_QueryInterface(currentSH);
|
|
|
|
if (newContainer) {
|
|
|
|
nsTArray<PRUint64> newDynDocShellIDs;
|
|
|
|
GetDynamicChildren(newContainer, newDynDocShellIDs, PR_FALSE);
|
|
|
|
for (PRUint32 i = 0; i < originalDynDocShellIDs.Length(); ++i) {
|
|
|
|
if (!newDynDocShellIDs.Contains(originalDynDocShellIDs[i])) {
|
|
|
|
toBeRemovedEntries.AppendElement(originalDynDocShellIDs[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (toBeRemovedEntries.Length()) {
|
|
|
|
RemoveEntries(toBeRemovedEntries, aOldIndex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:15 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::UpdateIndex()
|
|
|
|
{
|
|
|
|
// Update the actual index with the right value.
|
2005-08-18 11:17:00 +00:00
|
|
|
if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
|
2010-08-17 14:13:55 +00:00
|
|
|
RemoveDynEntries(mIndex, mRequestedIndex);
|
2005-08-18 11:16:23 +00:00
|
|
|
mIndex = mRequestedIndex;
|
2005-08-18 11:17:00 +00:00
|
|
|
}
|
|
|
|
|
2008-04-14 01:36:04 +00:00
|
|
|
mRequestedIndex = -1;
|
2005-08-18 11:16:15 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:34 +00:00
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:05 +00:00
|
|
|
nsSHistory::Stop(PRUint32 aStopFlags)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
//Not implemented
|
|
|
|
return NS_OK;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetDocument(nsIDOMDocument** aDocument)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
// Not implemented
|
2005-08-18 11:15:34 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:00 +00:00
|
|
|
nsSHistory::GetCurrentURI(nsIURI** aResultURI)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2005-08-18 11:16:00 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aResultURI);
|
2005-08-18 11:16:01 +00:00
|
|
|
nsresult rv;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsIHistoryEntry> currentEntry;
|
|
|
|
rv = GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(currentEntry));
|
2005-08-18 11:16:00 +00:00
|
|
|
if (NS_FAILED(rv) && !currentEntry) return rv;
|
2005-08-18 11:16:01 +00:00
|
|
|
rv = currentEntry->GetURI(aResultURI);
|
|
|
|
return rv;
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
|
|
|
|
2005-08-18 11:16:29 +00:00
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:40 +00:00
|
|
|
nsSHistory::GetReferringURI(nsIURI** aURI)
|
2005-08-18 11:16:29 +00:00
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
*aURI = nsnull;
|
|
|
|
// Not implemented
|
|
|
|
return NS_OK;
|
2005-08-18 11:16:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-18 11:15:34 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::SetSessionHistory(nsISHistory* aSessionHistory)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
// Not implemented
|
|
|
|
return NS_OK;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetSessionHistory(nsISHistory** aSessionHistory)
|
|
|
|
{
|
|
|
|
// Not implemented
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:29 +00:00
|
|
|
nsSHistory::LoadURI(const PRUnichar* aURI,
|
|
|
|
PRUint32 aLoadFlags,
|
2005-08-18 11:16:40 +00:00
|
|
|
nsIURI* aReferringURI,
|
2005-08-18 11:16:29 +00:00
|
|
|
nsIInputStream* aPostStream,
|
|
|
|
nsIInputStream* aExtraHeaderStream)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GotoIndex(PRInt32 aIndex)
|
2005-08-18 11:15:37 +00:00
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
return LoadEntry(aIndex, nsIDocShellLoadInfo::loadHistory, HIST_CMD_GOTOINDEX);
|
2005-08-18 11:15:37 +00:00
|
|
|
}
|
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
nsresult
|
|
|
|
nsSHistory::LoadNextPossibleEntry(PRInt32 aNewIndex, long aLoadType, PRUint32 aHistCmd)
|
|
|
|
{
|
|
|
|
mRequestedIndex = -1;
|
|
|
|
if (aNewIndex < mIndex) {
|
|
|
|
return LoadEntry(aNewIndex - 1, aLoadType, aHistCmd);
|
|
|
|
}
|
|
|
|
if (aNewIndex > mIndex) {
|
|
|
|
return LoadEntry(aNewIndex + 1, aLoadType, aHistCmd);
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:37 +00:00
|
|
|
NS_IMETHODIMP
|
2005-08-18 11:16:17 +00:00
|
|
|
nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsIDocShell> docShell;
|
|
|
|
nsCOMPtr<nsISHEntry> shEntry;
|
2005-08-18 11:16:15 +00:00
|
|
|
// Keep note of requested history index in mRequestedIndex.
|
|
|
|
mRequestedIndex = aIndex;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsISHEntry> prevEntry;
|
2009-09-01 16:45:05 +00:00
|
|
|
GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry));
|
|
|
|
|
|
|
|
nsCOMPtr<nsISHEntry> nextEntry;
|
2005-08-18 11:16:15 +00:00
|
|
|
GetEntryAtIndex(mRequestedIndex, PR_FALSE, getter_AddRefs(nextEntry));
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsIHistoryEntry> nHEntry(do_QueryInterface(nextEntry));
|
2009-09-01 16:45:05 +00:00
|
|
|
if (!nextEntry || !prevEntry || !nHEntry) {
|
2005-08-18 11:16:15 +00:00
|
|
|
mRequestedIndex = -1;
|
2005-08-18 11:16:01 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2005-08-18 11:16:07 +00:00
|
|
|
}
|
2009-09-01 16:45:05 +00:00
|
|
|
|
2005-08-18 11:16:00 +00:00
|
|
|
// Send appropriate listener notifications
|
|
|
|
PRBool canNavigate = PR_TRUE;
|
2005-08-18 11:16:01 +00:00
|
|
|
// Get the uri for the entry we are about to visit
|
|
|
|
nsCOMPtr<nsIURI> nextURI;
|
|
|
|
nHEntry->GetURI(getter_AddRefs(nextURI));
|
2009-09-01 16:45:05 +00:00
|
|
|
|
|
|
|
if(mListener) {
|
2005-08-18 11:16:04 +00:00
|
|
|
nsCOMPtr<nsISHistoryListener> listener(do_QueryReferent(mListener));
|
2005-08-18 11:16:00 +00:00
|
|
|
if (listener) {
|
2005-08-18 11:16:17 +00:00
|
|
|
if (aHistCmd == HIST_CMD_BACK) {
|
2005-08-18 11:16:00 +00:00
|
|
|
// We are going back one entry. Send GoBack notifications
|
2005-08-18 11:16:01 +00:00
|
|
|
listener->OnHistoryGoBack(nextURI, &canNavigate);
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
2005-08-18 11:16:17 +00:00
|
|
|
else if (aHistCmd == HIST_CMD_FORWARD) {
|
2005-08-18 11:16:00 +00:00
|
|
|
// We are going forward. Send GoForward notification
|
2005-08-18 11:16:01 +00:00
|
|
|
listener->OnHistoryGoForward(nextURI, &canNavigate);
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
2005-08-18 11:16:17 +00:00
|
|
|
else if (aHistCmd == HIST_CMD_GOTOINDEX) {
|
2005-08-18 11:16:00 +00:00
|
|
|
// We are going somewhere else. This is not reload either
|
2005-08-18 11:16:26 +00:00
|
|
|
listener->OnHistoryGotoIndex(aIndex, nextURI, &canNavigate);
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!canNavigate) {
|
2005-08-18 11:16:15 +00:00
|
|
|
// If the listener asked us not to proceed with
|
|
|
|
// the operation, simply return.
|
2005-08-18 11:16:00 +00:00
|
|
|
return NS_OK; // XXX Maybe I can return some other error code?
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsIURI> nexturi;
|
|
|
|
PRInt32 pCount=0, nCount=0;
|
|
|
|
nsCOMPtr<nsISHContainer> prevAsContainer(do_QueryInterface(prevEntry));
|
|
|
|
nsCOMPtr<nsISHContainer> nextAsContainer(do_QueryInterface(nextEntry));
|
|
|
|
if (prevAsContainer && nextAsContainer) {
|
|
|
|
prevAsContainer->GetChildCount(&pCount);
|
|
|
|
nextAsContainer->GetChildCount(&nCount);
|
|
|
|
}
|
2005-08-18 11:15:43 +00:00
|
|
|
|
2005-08-18 11:16:01 +00:00
|
|
|
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
|
2005-08-18 11:16:15 +00:00
|
|
|
if (mRequestedIndex == mIndex) {
|
2005-08-18 11:16:01 +00:00
|
|
|
// Possibly a reload case
|
|
|
|
docShell = mRootDocShell;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Going back or forward.
|
|
|
|
if ((pCount > 0) && (nCount > 0)) {
|
|
|
|
/* THis is a subframe navigation. Go find
|
|
|
|
* the docshell in which load should happen
|
|
|
|
*/
|
2005-08-18 11:16:33 +00:00
|
|
|
PRBool frameFound = PR_FALSE;
|
|
|
|
nsresult rv = CompareFrames(prevEntry, nextEntry, mRootDocShell, aLoadType, &frameFound);
|
|
|
|
if (!frameFound) {
|
2010-08-17 14:13:55 +00:00
|
|
|
// We did not successfully find the subframe in which
|
|
|
|
// the new url was to be loaded. Go further in the history.
|
|
|
|
return LoadNextPossibleEntry(aIndex, aLoadType, aHistCmd);
|
2005-08-18 11:16:01 +00:00
|
|
|
}
|
2005-08-18 11:16:33 +00:00
|
|
|
return rv;
|
2005-08-18 11:16:01 +00:00
|
|
|
} // (pCount >0)
|
2010-08-17 14:13:55 +00:00
|
|
|
else {
|
|
|
|
// Loading top level page.
|
|
|
|
PRUint32 prevID = 0;
|
|
|
|
PRUint32 nextID = 0;
|
|
|
|
prevEntry->GetID(&prevID);
|
|
|
|
nextEntry->GetID(&nextID);
|
|
|
|
if (prevID == nextID) {
|
|
|
|
// Try harder to find something new to load.
|
|
|
|
// This may happen for example if some page removed iframes dynamically.
|
|
|
|
return LoadNextPossibleEntry(aIndex, aLoadType, aHistCmd);
|
|
|
|
}
|
2005-08-18 11:16:01 +00:00
|
|
|
docShell = mRootDocShell;
|
|
|
|
}
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
if (!docShell) {
|
2006-04-17 07:50:02 +00:00
|
|
|
// we did not successfully go to the proper index.
|
|
|
|
// return error.
|
|
|
|
mRequestedIndex = -1;
|
|
|
|
return NS_ERROR_FAILURE;
|
2005-08-18 11:16:07 +00:00
|
|
|
}
|
2005-08-18 11:16:01 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
// Start the load on the appropriate docshell
|
2008-09-11 21:54:40 +00:00
|
|
|
return InitiateLoad(nextEntry, docShell, aLoadType);
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
nsresult
|
|
|
|
nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2005-08-18 11:16:33 +00:00
|
|
|
if (!aPrevEntry || !aNextEntry || !aParent)
|
2010-08-17 14:13:55 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// We should be comparing only entries which were created for the
|
|
|
|
// same docshell. This is here to just prevent anything strange happening.
|
|
|
|
// This check could be possibly an assertion.
|
|
|
|
PRUint64 prevdID, nextdID;
|
|
|
|
aPrevEntry->GetDocshellID(&prevdID);
|
|
|
|
aNextEntry->GetDocshellID(&nextdID);
|
|
|
|
NS_ENSURE_STATE(prevdID == nextdID);
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
nsresult result = NS_OK;
|
|
|
|
PRUint32 prevID, nextID;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
aPrevEntry->GetID(&prevID);
|
|
|
|
aNextEntry->GetID(&nextID);
|
2005-08-18 11:15:56 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
// Check the IDs to verify if the pages are different.
|
|
|
|
if (prevID != nextID) {
|
|
|
|
if (aIsFrameFound)
|
|
|
|
*aIsFrameFound = PR_TRUE;
|
|
|
|
// Set the Subframe flag of the entry to indicate that
|
|
|
|
// it is subframe navigation
|
|
|
|
aNextEntry->SetIsSubFrame(PR_TRUE);
|
|
|
|
InitiateLoad(aNextEntry, aParent, aLoadType);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
/* The root entries are the same, so compare any child frames */
|
2005-08-18 11:16:46 +00:00
|
|
|
PRInt32 pcnt=0, ncnt=0, dsCount=0;
|
2005-08-18 11:16:33 +00:00
|
|
|
nsCOMPtr<nsISHContainer> prevContainer(do_QueryInterface(aPrevEntry));
|
|
|
|
nsCOMPtr<nsISHContainer> nextContainer(do_QueryInterface(aNextEntry));
|
|
|
|
nsCOMPtr<nsIDocShellTreeNode> dsTreeNode(do_QueryInterface(aParent));
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
if (!dsTreeNode)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
if (!prevContainer || !nextContainer)
|
|
|
|
return NS_ERROR_FAILURE;
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2005-08-18 11:16:02 +00:00
|
|
|
prevContainer->GetChildCount(&pcnt);
|
|
|
|
nextContainer->GetChildCount(&ncnt);
|
|
|
|
dsTreeNode->GetChildCount(&dsCount);
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
// Create an array for child docshells.
|
|
|
|
nsCOMArray<nsIDocShell> docshells;
|
|
|
|
for (PRInt32 i = 0; i < dsCount; ++i) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
|
|
|
dsTreeNode->GetChildAt(i, getter_AddRefs(treeItem));
|
|
|
|
nsCOMPtr<nsIDocShell> shell = do_QueryInterface(treeItem);
|
|
|
|
if (shell) {
|
|
|
|
docshells.AppendObject(shell);
|
|
|
|
}
|
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
// Search for something to load next.
|
|
|
|
for (PRInt32 i = 0; i < ncnt; ++i) {
|
|
|
|
// First get an entry which may cause a new page to be loaded.
|
|
|
|
nsCOMPtr<nsISHEntry> nChild;
|
|
|
|
nextContainer->GetChildAt(i, getter_AddRefs(nChild));
|
|
|
|
if (!nChild) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
PRUint64 docshellID = 0;
|
|
|
|
nChild->GetDocshellID(&docshellID);
|
|
|
|
|
|
|
|
// Then find the associated docshell.
|
|
|
|
nsIDocShell* dsChild = nsnull;
|
|
|
|
PRInt32 count = docshells.Count();
|
|
|
|
for (PRInt32 j = 0; j < count; ++j) {
|
|
|
|
PRUint64 shellID = 0;
|
|
|
|
nsIDocShell* shell = docshells[j];
|
|
|
|
shell->GetHistoryID(&shellID);
|
|
|
|
if (shellID == docshellID) {
|
|
|
|
dsChild = shell;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!dsChild) {
|
|
|
|
continue;
|
|
|
|
}
|
2005-08-18 11:15:39 +00:00
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
// Then look at the previous entries to see if there was
|
|
|
|
// an entry for the docshell.
|
|
|
|
nsCOMPtr<nsISHEntry> pChild;
|
|
|
|
for (PRInt32 k = 0; k < pcnt; ++k) {
|
|
|
|
nsCOMPtr<nsISHEntry> child;
|
|
|
|
prevContainer->GetChildAt(k, getter_AddRefs(child));
|
|
|
|
if (child) {
|
|
|
|
PRUint64 dID = 0;
|
|
|
|
child->GetDocshellID(&dID);
|
|
|
|
if (dID == docshellID) {
|
|
|
|
pChild = child;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
// Finally recursively call this method.
|
|
|
|
// This will either load a new page to shell or some subshell or
|
|
|
|
// do nothing.
|
2006-04-17 07:50:02 +00:00
|
|
|
CompareFrames(pChild, nChild, dsChild, aLoadType, aIsFrameFound);
|
|
|
|
}
|
2005-08-18 11:16:33 +00:00
|
|
|
return result;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
nsresult
|
|
|
|
nsSHistory::InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType)
|
|
|
|
{
|
2010-11-19 12:01:10 +00:00
|
|
|
NS_ENSURE_STATE(aFrameDS && aFrameEntry);
|
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
|
|
|
|
|
|
|
|
/* Set the loadType in the SHEntry too to what was passed on.
|
|
|
|
* This will be passed on to child subframes later in nsDocShell,
|
|
|
|
* so that proper loadType is maintained through out a frameset
|
|
|
|
*/
|
|
|
|
aFrameEntry->SetLoadType(aLoadType);
|
|
|
|
aFrameDS->CreateLoadInfo (getter_AddRefs(loadInfo));
|
|
|
|
|
|
|
|
loadInfo->SetLoadType(aLoadType);
|
|
|
|
loadInfo->SetSHEntry(aFrameEntry);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> nextURI;
|
|
|
|
nsCOMPtr<nsIHistoryEntry> hEntry(do_QueryInterface(aFrameEntry));
|
|
|
|
hEntry->GetURI(getter_AddRefs(nextURI));
|
|
|
|
// Time to initiate a document load
|
2005-08-18 11:16:34 +00:00
|
|
|
return aFrameDS->LoadURI(nextURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE);
|
2005-08-18 11:16:33 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::SetRootDocShell(nsIDocShell * aDocShell)
|
|
|
|
{
|
|
|
|
mRootDocShell = aDocShell;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetRootDocShell(nsIDocShell ** aDocShell)
|
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aDocShell);
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
*aDocShell = mRootDocShell;
|
|
|
|
//Not refcounted. May this method should not be available for public
|
2005-08-18 11:15:34 +00:00
|
|
|
// NS_IF_ADDREF(*aDocShell);
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:35 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:01 +00:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::GetSHistoryEnumerator(nsISimpleEnumerator** aEnumerator)
|
|
|
|
{
|
|
|
|
nsresult status = NS_OK;
|
|
|
|
|
|
|
|
NS_ENSURE_ARG_POINTER(aEnumerator);
|
|
|
|
nsSHEnumerator * iterator = new nsSHEnumerator(this);
|
2005-08-18 11:16:25 +00:00
|
|
|
if (iterator && NS_FAILED(status = CallQueryInterface(iterator, aEnumerator)))
|
2005-08-18 11:16:01 +00:00
|
|
|
delete iterator;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//*****************************************************************************
|
|
|
|
//*** nsSHEnumerator: Object Management
|
|
|
|
//*****************************************************************************
|
|
|
|
|
|
|
|
nsSHEnumerator::nsSHEnumerator(nsSHistory * aSHistory):mIndex(-1)
|
|
|
|
{
|
|
|
|
mSHistory = aSHistory;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSHEnumerator::~nsSHEnumerator()
|
|
|
|
{
|
|
|
|
mSHistory = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(nsSHEnumerator, nsISimpleEnumerator)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHEnumerator::HasMoreElements(PRBool * aReturn)
|
|
|
|
{
|
|
|
|
PRInt32 cnt;
|
|
|
|
*aReturn = PR_FALSE;
|
|
|
|
mSHistory->GetCount(&cnt);
|
2005-08-18 11:16:04 +00:00
|
|
|
if (mIndex >= -1 && mIndex < (cnt-1) ) {
|
2005-08-18 11:16:01 +00:00
|
|
|
*aReturn = PR_TRUE;
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHEnumerator::GetNext(nsISupports **aItem)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aItem);
|
|
|
|
PRInt32 cnt= 0;
|
|
|
|
|
|
|
|
nsresult result = NS_ERROR_FAILURE;
|
|
|
|
mSHistory->GetCount(&cnt);
|
|
|
|
if (mIndex < (cnt-1)) {
|
|
|
|
mIndex++;
|
|
|
|
nsCOMPtr<nsIHistoryEntry> hEntry;
|
|
|
|
result = mSHistory->GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(hEntry));
|
2006-04-17 07:50:02 +00:00
|
|
|
if (hEntry)
|
2005-08-18 11:16:01 +00:00
|
|
|
result = CallQueryInterface(hEntry, aItem);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|