2015-05-08 11:37:00 +00:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2012-05-21 11:12:37 +00:00
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2005-08-18 11:15:08 +00:00
|
|
|
|
|
|
|
#include "nsSHistory.h"
|
|
|
|
|
2017-04-27 10:16:46 +00:00
|
|
|
#include <algorithm>
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2017-04-27 10:16:46 +00:00
|
|
|
#include "nsCOMArray.h"
|
|
|
|
#include "nsComponentManagerUtils.h"
|
|
|
|
#include "nsDocShell.h"
|
|
|
|
#include "nsIContentViewer.h"
|
2005-08-18 11:16:44 +00:00
|
|
|
#include "nsIDocShell.h"
|
2018-10-26 03:50:37 +00:00
|
|
|
#include "nsDocShellLoadState.h"
|
2005-08-18 11:15:34 +00:00
|
|
|
#include "nsIDocShellTreeItem.h"
|
2017-04-27 10:16:46 +00:00
|
|
|
#include "nsILayoutHistoryState.h"
|
2005-09-29 20:24:27 +00:00
|
|
|
#include "nsIObserverService.h"
|
2013-09-04 15:26:20 +00:00
|
|
|
#include "nsISHEntry.h"
|
|
|
|
#include "nsISHistoryListener.h"
|
2017-04-27 10:16:46 +00:00
|
|
|
#include "nsIURI.h"
|
2016-11-29 09:31:17 +00:00
|
|
|
#include "nsNetUtil.h"
|
2017-04-27 10:16:46 +00:00
|
|
|
#include "nsTArray.h"
|
2013-09-04 15:26:20 +00:00
|
|
|
#include "prsystem.h"
|
2017-04-27 10:16:46 +00:00
|
|
|
|
|
|
|
#include "mozilla/Attributes.h"
|
|
|
|
#include "mozilla/LinkedList.h"
|
2013-02-16 03:55:36 +00:00
|
|
|
#include "mozilla/MathAlgorithms.h"
|
2017-04-27 10:16:46 +00:00
|
|
|
#include "mozilla/Preferences.h"
|
|
|
|
#include "mozilla/Services.h"
|
|
|
|
#include "mozilla/StaticPtr.h"
|
2017-04-27 10:59:11 +00:00
|
|
|
#include "mozilla/dom/TabGroup.h"
|
2005-08-18 11:15:59 +00:00
|
|
|
|
2011-06-25 01:55:46 +00:00
|
|
|
using namespace mozilla;
|
|
|
|
|
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"
|
2017-04-27 10:59:11 +00:00
|
|
|
#define CONTENT_VIEWER_TIMEOUT_SECONDS "browser.sessionhistory.contentViewerTimeout"
|
|
|
|
|
|
|
|
// Default this to time out unused content viewers after 30 minutes
|
|
|
|
#define CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT (30 * 60)
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2011-06-25 01:55:46 +00:00
|
|
|
static const char* kObservedPrefs[] = {
|
|
|
|
PREF_SHISTORY_SIZE,
|
|
|
|
PREF_SHISTORY_MAX_TOTAL_VIEWERS,
|
2012-07-30 14:20:58 +00:00
|
|
|
nullptr
|
2011-06-25 01:55:46 +00:00
|
|
|
};
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
static int32_t gHistoryMaxSize = 50;
|
2005-09-23 18:16:40 +00:00
|
|
|
// List of all SHistory objects, used for content viewer cache eviction
|
2017-04-19 17:05:00 +00:00
|
|
|
static LinkedList<nsSHistory> gSHistoryList;
|
2005-09-23 18:16:40 +00:00
|
|
|
// Max viewers allowed total, across all SHistory objects - negative default
|
|
|
|
// means we will calculate how many viewers to cache based on total memory
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t nsSHistory::sHistoryMaxTotalViewers = -1;
|
2005-08-18 11:15:08 +00:00
|
|
|
|
2011-01-19 19:57:36 +00:00
|
|
|
// A counter that is used to be able to know the order in which
|
|
|
|
// entries were touched, so that we can evict older entries first.
|
2012-08-22 15:56:38 +00:00
|
|
|
static uint32_t gTouchCounter = 0;
|
2011-01-19 19:57:36 +00:00
|
|
|
|
2016-01-28 18:35:00 +00:00
|
|
|
static LazyLogModule gSHistoryLog("nsSHistory");
|
|
|
|
|
|
|
|
#define LOG(format) MOZ_LOG(gSHistoryLog, mozilla::LogLevel::Debug, format)
|
2011-10-21 15:26:34 +00:00
|
|
|
|
|
|
|
// This macro makes it easier to print a log message which includes a URI's
|
|
|
|
// spec. Example use:
|
|
|
|
//
|
|
|
|
// nsIURI *uri = [...];
|
|
|
|
// LOG_SPEC(("The URI is %s.", _spec), uri);
|
|
|
|
//
|
|
|
|
#define LOG_SPEC(format, uri) \
|
|
|
|
PR_BEGIN_MACRO \
|
2016-01-28 18:35:00 +00:00
|
|
|
if (MOZ_LOG_TEST(gSHistoryLog, LogLevel::Debug)) { \
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString _specStr(NS_LITERAL_CSTRING("(null)"));\
|
2011-10-21 15:26:34 +00:00
|
|
|
if (uri) { \
|
2016-08-26 06:02:31 +00:00
|
|
|
_specStr = uri->GetSpecOrDefault(); \
|
2011-10-21 15:26:34 +00:00
|
|
|
} \
|
|
|
|
const char* _spec = _specStr.get(); \
|
|
|
|
LOG(format); \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
|
|
|
// This macro makes it easy to log a message including an SHEntry's URI.
|
|
|
|
// For example:
|
|
|
|
//
|
|
|
|
// nsCOMPtr<nsISHEntry> shentry = [...];
|
|
|
|
// LOG_SHENTRY_SPEC(("shentry %p has uri %s.", shentry.get(), _spec), shentry);
|
|
|
|
//
|
|
|
|
#define LOG_SHENTRY_SPEC(format, shentry) \
|
|
|
|
PR_BEGIN_MACRO \
|
2016-01-28 18:35:00 +00:00
|
|
|
if (MOZ_LOG_TEST(gSHistoryLog, LogLevel::Debug)) { \
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsIURI> uri = shentry->GetURI(); \
|
2011-10-21 15:26:34 +00:00
|
|
|
LOG_SPEC(format, uri); \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
2012-09-20 14:41:18 +00:00
|
|
|
// Iterates over all registered session history listeners.
|
|
|
|
#define ITERATE_LISTENERS(body) \
|
|
|
|
PR_BEGIN_MACRO \
|
|
|
|
{ \
|
|
|
|
nsAutoTObserverArray<nsWeakPtr, 2>::EndLimitedIterator \
|
|
|
|
iter(mListeners); \
|
|
|
|
while (iter.HasMore()) { \
|
|
|
|
nsCOMPtr<nsISHistoryListener> listener = \
|
|
|
|
do_QueryReferent(iter.GetNext()); \
|
|
|
|
if (listener) { \
|
2012-09-21 11:11:25 +00:00
|
|
|
body \
|
2012-09-20 14:41:18 +00:00
|
|
|
} \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
|
|
|
// Calls a given method on all registered session history listeners.
|
|
|
|
#define NOTIFY_LISTENERS(method, args) \
|
|
|
|
ITERATE_LISTENERS( \
|
|
|
|
listener->method args; \
|
|
|
|
);
|
|
|
|
|
|
|
|
// Calls a given method on all registered session history listeners.
|
|
|
|
// Listeners may return 'false' to cancel an action so make sure that we
|
|
|
|
// set the return value to 'false' if one of the listeners wants to cancel.
|
|
|
|
#define NOTIFY_LISTENERS_CANCELABLE(method, retval, args) \
|
|
|
|
PR_BEGIN_MACRO \
|
|
|
|
{ \
|
|
|
|
bool canceled = false; \
|
|
|
|
retval = true; \
|
|
|
|
ITERATE_LISTENERS( \
|
|
|
|
listener->method args; \
|
|
|
|
if (!retval) { \
|
|
|
|
canceled = true; \
|
|
|
|
} \
|
|
|
|
); \
|
|
|
|
if (canceled) { \
|
|
|
|
retval = false; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
enum HistCmd
|
|
|
|
{
|
2005-08-18 11:16:17 +00:00
|
|
|
HIST_CMD_GOTOINDEX,
|
|
|
|
HIST_CMD_RELOAD
|
2015-05-06 17:57:23 +00:00
|
|
|
};
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2015-03-21 16:28:04 +00:00
|
|
|
class nsSHistoryObserver final : 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
|
|
|
|
2018-07-05 21:58:04 +00:00
|
|
|
void PrefChanged(const char* aPref);
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
2015-04-17 13:19:00 +00:00
|
|
|
StaticRefPtr<nsSHistoryObserver> gObserver;
|
2011-06-25 01:55:46 +00:00
|
|
|
|
2014-04-27 07:06:00 +00:00
|
|
|
NS_IMPL_ISUPPORTS(nsSHistoryObserver, nsIObserver)
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2018-07-05 21:58:04 +00:00
|
|
|
void
|
|
|
|
nsSHistoryObserver::PrefChanged(const char* aPref)
|
|
|
|
{
|
|
|
|
nsSHistory::UpdatePrefs();
|
|
|
|
nsSHistory::GloballyEvictContentViewers();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
NS_IMETHODIMP
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistoryObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
|
|
|
const char16_t* aData)
|
2005-09-23 18:16:40 +00:00
|
|
|
{
|
2018-07-05 21:58:04 +00:00
|
|
|
if (!strcmp(aTopic, "cacheservice:empty-cache") ||
|
|
|
|
!strcmp(aTopic, "memory-pressure")) {
|
2011-10-21 15:26:34 +00:00
|
|
|
nsSHistory::GloballyEvictAllContentViewers();
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
already_AddRefed<nsIContentViewer>
|
2018-09-04 23:03:22 +00:00
|
|
|
GetContentViewerForEntry(nsISHEntry* aEntry)
|
2011-10-21 15:26:34 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsISHEntry> ownerEntry;
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
2018-09-04 23:03:22 +00:00
|
|
|
aEntry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
|
2018-09-04 23:02:37 +00:00
|
|
|
getter_AddRefs(viewer));
|
2011-10-21 15:26:34 +00:00
|
|
|
return viewer.forget();
|
|
|
|
}
|
|
|
|
|
2017-01-24 06:56:37 +00:00
|
|
|
} // namespace
|
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
void
|
2018-09-04 23:03:22 +00:00
|
|
|
nsSHistory::EvictContentViewerForEntry(nsISHEntry* aEntry)
|
2011-10-21 15:26:34 +00:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
|
|
nsCOMPtr<nsISHEntry> ownerEntry;
|
2018-09-04 23:03:22 +00:00
|
|
|
aEntry->GetAnyContentViewer(getter_AddRefs(ownerEntry),
|
2018-09-04 23:02:37 +00:00
|
|
|
getter_AddRefs(viewer));
|
2011-10-21 15:26:34 +00:00
|
|
|
if (viewer) {
|
2015-05-06 17:57:23 +00:00
|
|
|
NS_ASSERTION(ownerEntry, "Content viewer exists but its SHEntry is null");
|
2011-10-21 15:26:34 +00:00
|
|
|
|
|
|
|
LOG_SHENTRY_SPEC(("Evicting content viewer 0x%p for "
|
|
|
|
"owning SHEntry 0x%p at %s.",
|
2015-05-06 17:57:23 +00:00
|
|
|
viewer.get(), ownerEntry.get(), _spec),
|
2017-08-24 06:32:23 +00:00
|
|
|
ownerEntry);
|
2011-10-21 15:26:34 +00:00
|
|
|
|
|
|
|
// Drop the presentation state before destroying the viewer, so that
|
|
|
|
// document teardown is able to correctly persist the state.
|
2012-07-30 14:20:58 +00:00
|
|
|
ownerEntry->SetContentViewer(nullptr);
|
2011-10-21 15:26:34 +00:00
|
|
|
ownerEntry->SyncPresentationState();
|
|
|
|
viewer->Destroy();
|
|
|
|
}
|
|
|
|
|
2017-01-24 06:56:37 +00:00
|
|
|
// When dropping bfcache, we have to remove associated dynamic entries as well.
|
2018-09-11 06:08:39 +00:00
|
|
|
int32_t index = GetIndexOfEntry(aEntry);
|
2017-01-24 06:56:37 +00:00
|
|
|
if (index != -1) {
|
2018-09-04 23:03:22 +00:00
|
|
|
RemoveDynEntries(index, aEntry);
|
2017-01-24 06:56:37 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::nsSHistory()
|
|
|
|
: mIndex(-1)
|
|
|
|
, mRequestedIndex(-1)
|
2016-01-12 18:16:59 +00:00
|
|
|
, mRootDocShell(nullptr)
|
2005-08-18 11:15:08 +00:00
|
|
|
{
|
2005-09-23 18:16:40 +00:00
|
|
|
// Add this new SHistory object to the list
|
2017-04-19 17:05:00 +00:00
|
|
|
gSHistoryList.insertBack(this);
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsSHistory::~nsSHistory()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:33 +00:00
|
|
|
NS_IMPL_ADDREF(nsSHistory)
|
|
|
|
NS_IMPL_RELEASE(nsSHistory)
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsSHistory)
|
2015-05-06 17:57:23 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISHistory)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISHistory)
|
2017-04-27 10:59:11 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
2005-08-18 11:15:33 +00:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
2005-09-23 18:16:40 +00:00
|
|
|
// static
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t
|
2005-10-01 20:38:47 +00:00
|
|
|
nsSHistory::CalcMaxTotalViewers()
|
2005-09-23 18:16:40 +00:00
|
|
|
{
|
Bug 1335148 - Part 1: Dynamically determine content viewer count on Android, too. r=bz,snorp
The current limit of at most one bfcache entry on Android dates back to when
Fennec was built for the Nokia N810, which had a whopping 128 MB of memory.
Since a few years have passed since then and mobile device technology has
evolved considerably, it should be safe now to allow a little more than that.
Since web sites sizes might have grown somewhat as well compared to the figure
of 4MB mentioned in CalcMaxTotalViweres(), though and to be absolutely on the
safe side, we still tweak the formula when building for Android, though.
If in the worst case even those assumptions turn out too generous, we will still
be protected by the fact that
- we temporarily disable the bfcache when the OS signals memory pressure, and
- our contentViewerTimeout is set to a lower value than on Desktop, so bfcache
entries will expire sooner
MozReview-Commit-ID: 1A6d0Q6Mdx0
--HG--
extra : rebase_source : 9cc1f7abb1aef82ffc4d7987773ae7cf35440884
2018-03-29 19:51:13 +00:00
|
|
|
// This value allows tweaking how fast the allowed amount of content viewers
|
|
|
|
// grows with increasing amounts of memory. Larger values mean slower growth.
|
|
|
|
#ifdef ANDROID
|
|
|
|
#define MAX_TOTAL_VIEWERS_BIAS 15.9
|
|
|
|
#else
|
|
|
|
#define MAX_TOTAL_VIEWERS_BIAS 14
|
|
|
|
#endif
|
|
|
|
|
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?
|
|
|
|
//
|
Bug 1335148 - Part 1: Dynamically determine content viewer count on Android, too. r=bz,snorp
The current limit of at most one bfcache entry on Android dates back to when
Fennec was built for the Nokia N810, which had a whopping 128 MB of memory.
Since a few years have passed since then and mobile device technology has
evolved considerably, it should be safe now to allow a little more than that.
Since web sites sizes might have grown somewhat as well compared to the figure
of 4MB mentioned in CalcMaxTotalViweres(), though and to be absolutely on the
safe side, we still tweak the formula when building for Android, though.
If in the worst case even those assumptions turn out too generous, we will still
be protected by the fact that
- we temporarily disable the bfcache when the OS signals memory pressure, and
- our contentViewerTimeout is set to a lower value than on Desktop, so bfcache
entries will expire sooner
MozReview-Commit-ID: 1A6d0Q6Mdx0
--HG--
extra : rebase_source : 9cc1f7abb1aef82ffc4d7987773ae7cf35440884
2018-03-29 19:51:13 +00:00
|
|
|
// RAM | ContentViewers | on Android
|
|
|
|
// -------------------------------------
|
|
|
|
// 32 Mb 0 0
|
|
|
|
// 64 Mb 1 0
|
|
|
|
// 128 Mb 2 0
|
|
|
|
// 256 Mb 3 1
|
|
|
|
// 512 Mb 5 2
|
|
|
|
// 768 Mb 6 2
|
|
|
|
// 1024 Mb 8 3
|
|
|
|
// 2048 Mb 8 5
|
|
|
|
// 3072 Mb 8 7
|
|
|
|
// 4096 Mb 8 8
|
2012-08-22 15:56:38 +00:00
|
|
|
uint64_t bytes = PR_GetPhysicalMemorySize();
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
if (bytes == 0) {
|
2005-09-23 18:16:40 +00:00
|
|
|
return 0;
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2012-10-11 23:38:04 +00:00
|
|
|
// Conversion from unsigned int64_t to double doesn't work on all platforms.
|
2012-09-28 19:55:23 +00:00
|
|
|
// We need to truncate the value at INT64_MAX to make sure we don't
|
2005-09-23 18:16:40 +00:00
|
|
|
// overflow.
|
2015-05-06 17:57:23 +00:00
|
|
|
if (bytes > INT64_MAX) {
|
2012-09-28 19:55:23 +00:00
|
|
|
bytes = INT64_MAX;
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2013-07-18 20:50:05 +00:00
|
|
|
double kBytesD = (double)(bytes >> 10);
|
2005-09-23 18:16:40 +00:00
|
|
|
|
|
|
|
// 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
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t viewers = 0;
|
Bug 1335148 - Part 1: Dynamically determine content viewer count on Android, too. r=bz,snorp
The current limit of at most one bfcache entry on Android dates back to when
Fennec was built for the Nokia N810, which had a whopping 128 MB of memory.
Since a few years have passed since then and mobile device technology has
evolved considerably, it should be safe now to allow a little more than that.
Since web sites sizes might have grown somewhat as well compared to the figure
of 4MB mentioned in CalcMaxTotalViweres(), though and to be absolutely on the
safe side, we still tweak the formula when building for Android, though.
If in the worst case even those assumptions turn out too generous, we will still
be protected by the fact that
- we temporarily disable the bfcache when the OS signals memory pressure, and
- our contentViewerTimeout is set to a lower value than on Desktop, so bfcache
entries will expire sooner
MozReview-Commit-ID: 1A6d0Q6Mdx0
--HG--
extra : rebase_source : 9cc1f7abb1aef82ffc4d7987773ae7cf35440884
2018-03-29 19:51:13 +00:00
|
|
|
double x = std::log(kBytesD) / std::log(2.0) - MAX_TOTAL_VIEWERS_BIAS;
|
2005-09-23 18:16:40 +00:00
|
|
|
if (x > 0) {
|
2015-05-06 17:57:23 +00:00
|
|
|
viewers = (uint32_t)(x * x - x + 2.001); // add .001 for rounding
|
|
|
|
viewers /= 4;
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cap it off at 8 max
|
|
|
|
if (viewers > 8) {
|
|
|
|
viewers = 8;
|
|
|
|
}
|
|
|
|
return viewers;
|
|
|
|
}
|
|
|
|
|
2010-05-02 04:59:08 +00:00
|
|
|
// static
|
|
|
|
void
|
2011-06-25 01:55:46 +00:00
|
|
|
nsSHistory::UpdatePrefs()
|
2010-05-02 04:59:08 +00:00
|
|
|
{
|
2011-06-25 01:55:46 +00:00
|
|
|
Preferences::GetInt(PREF_SHISTORY_SIZE, &gHistoryMaxSize);
|
|
|
|
Preferences::GetInt(PREF_SHISTORY_MAX_TOTAL_VIEWERS,
|
|
|
|
&sHistoryMaxTotalViewers);
|
2010-05-02 04:59:08 +00:00
|
|
|
// 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
|
|
|
{
|
2011-06-25 01:55:46 +00:00
|
|
|
UpdatePrefs();
|
|
|
|
|
|
|
|
// The goal of this is to unbreak users who have inadvertently set their
|
|
|
|
// session history size to less than the default value.
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t defaultHistoryMaxSize =
|
2017-11-14 08:06:01 +00:00
|
|
|
Preferences::GetInt(PREF_SHISTORY_SIZE, 50, PrefValueKind::Default);
|
2011-06-25 01:55:46 +00:00
|
|
|
if (gHistoryMaxSize < defaultHistoryMaxSize) {
|
|
|
|
gHistoryMaxSize = defaultHistoryMaxSize;
|
|
|
|
}
|
2015-05-06 17:57:23 +00:00
|
|
|
|
2011-06-25 01:55:46 +00:00
|
|
|
// Allow the user to override the max total number of cached viewers,
|
|
|
|
// but keep the per SHistory cached viewer limit constant
|
|
|
|
if (!gObserver) {
|
|
|
|
gObserver = new nsSHistoryObserver();
|
2018-07-05 21:58:04 +00:00
|
|
|
Preferences::RegisterCallbacks(
|
|
|
|
PREF_CHANGE_METHOD(nsSHistoryObserver::PrefChanged),
|
|
|
|
kObservedPrefs, gObserver.get());
|
2011-06-25 01:55:46 +00:00
|
|
|
|
|
|
|
nsCOMPtr<nsIObserverService> obsSvc =
|
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (obsSvc) {
|
|
|
|
// Observe empty-cache notifications so tahat clearing the disk/memory
|
|
|
|
// cache will also evict all content viewers.
|
2015-05-06 17:57:23 +00:00
|
|
|
obsSvc->AddObserver(gObserver, "cacheservice:empty-cache", false);
|
2011-06-25 01:55:46 +00:00
|
|
|
|
|
|
|
// Same for memory-pressure notifications
|
2011-10-17 14:59:28 +00:00
|
|
|
obsSvc->AddObserver(gObserver, "memory-pressure", false);
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2011-06-25 01:55:46 +00:00
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsSHistory::Shutdown()
|
|
|
|
{
|
|
|
|
if (gObserver) {
|
2018-07-05 21:58:04 +00:00
|
|
|
Preferences::UnregisterCallbacks(
|
|
|
|
PREF_CHANGE_METHOD(nsSHistoryObserver::PrefChanged),
|
|
|
|
kObservedPrefs, gObserver.get());
|
|
|
|
|
2011-06-25 01:55:46 +00:00
|
|
|
nsCOMPtr<nsIObserverService> obsSvc =
|
|
|
|
mozilla::services::GetObserverService();
|
|
|
|
if (obsSvc) {
|
2014-06-05 18:14:07 +00:00
|
|
|
obsSvc->RemoveObserver(gObserver, "cacheservice:empty-cache");
|
2011-06-25 01:55:46 +00:00
|
|
|
obsSvc->RemoveObserver(gObserver, "memory-pressure");
|
|
|
|
}
|
2015-04-17 13:19:00 +00:00
|
|
|
gObserver = nullptr;
|
2011-06-25 01:55:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-19 10:26:36 +00:00
|
|
|
// static
|
|
|
|
nsISHEntry*
|
|
|
|
nsSHistory::GetRootSHEntry(nsISHEntry* aEntry)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISHEntry> rootEntry = aEntry;
|
|
|
|
nsISHEntry* result = nullptr;
|
|
|
|
while (rootEntry) {
|
|
|
|
result = rootEntry;
|
2018-09-07 01:56:23 +00:00
|
|
|
rootEntry = result->GetParent();
|
2017-12-19 10:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
nsSHistory::WalkHistoryEntries(nsISHEntry* aRootEntry,
|
|
|
|
nsDocShell* aRootShell,
|
|
|
|
WalkHistoryEntriesFunc aCallback,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
|
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
int32_t childCount = aRootEntry->GetChildCount();
|
2017-12-19 10:26:36 +00:00
|
|
|
for (int32_t i = 0; i < childCount; i++) {
|
|
|
|
nsCOMPtr<nsISHEntry> childEntry;
|
2018-08-22 09:20:56 +00:00
|
|
|
aRootEntry->GetChildAt(i, getter_AddRefs(childEntry));
|
2017-12-19 10:26:36 +00:00
|
|
|
if (!childEntry) {
|
|
|
|
// childEntry can be null for valid reasons, for example if the
|
|
|
|
// docshell at index i never loaded anything useful.
|
|
|
|
// Remember to clone also nulls in the child array (bug 464064).
|
|
|
|
aCallback(nullptr, nullptr, i, aData);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDocShell* childShell = nullptr;
|
|
|
|
if (aRootShell) {
|
|
|
|
// Walk the children of aRootShell and see if one of them
|
|
|
|
// has srcChild as a SHEntry.
|
|
|
|
int32_t length;
|
|
|
|
aRootShell->GetChildCount(&length);
|
|
|
|
for (int32_t i = 0; i < length; i++) {
|
|
|
|
nsCOMPtr<nsIDocShellTreeItem> item;
|
|
|
|
nsresult rv = aRootShell->GetChildAt(i, getter_AddRefs(item));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsDocShell* child = static_cast<nsDocShell*>(item.get());
|
|
|
|
if (child->HasHistoryEntry(childEntry)) {
|
|
|
|
childShell = child;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsresult rv = aCallback(childEntry, childShell, i, aData);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// callback data for WalkHistoryEntries
|
|
|
|
struct MOZ_STACK_CLASS CloneAndReplaceData
|
|
|
|
{
|
|
|
|
CloneAndReplaceData(uint32_t aCloneID, nsISHEntry* aReplaceEntry,
|
|
|
|
bool aCloneChildren, nsISHEntry* aDestTreeParent)
|
|
|
|
: cloneID(aCloneID)
|
|
|
|
, cloneChildren(aCloneChildren)
|
|
|
|
, replaceEntry(aReplaceEntry)
|
|
|
|
, destTreeParent(aDestTreeParent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t cloneID;
|
|
|
|
bool cloneChildren;
|
|
|
|
nsISHEntry* replaceEntry;
|
|
|
|
nsISHEntry* destTreeParent;
|
|
|
|
nsCOMPtr<nsISHEntry> resultEntry;
|
|
|
|
};
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
nsSHistory::CloneAndReplaceChild(nsISHEntry* aEntry,
|
|
|
|
nsDocShell* aShell,
|
|
|
|
int32_t aEntryIndex,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsISHEntry> dest;
|
|
|
|
|
|
|
|
CloneAndReplaceData* data = static_cast<CloneAndReplaceData*>(aData);
|
|
|
|
uint32_t cloneID = data->cloneID;
|
|
|
|
nsISHEntry* replaceEntry = data->replaceEntry;
|
|
|
|
|
|
|
|
if (!aEntry) {
|
2018-08-22 09:20:56 +00:00
|
|
|
if (data->destTreeParent) {
|
|
|
|
data->destTreeParent->AddChild(nullptr, aEntryIndex);
|
2017-12-19 10:26:36 +00:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
uint32_t srcID = aEntry->GetID();
|
2017-12-19 10:26:36 +00:00
|
|
|
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (srcID == cloneID) {
|
|
|
|
// Replace the entry
|
|
|
|
dest = replaceEntry;
|
|
|
|
} else {
|
|
|
|
// Clone the SHEntry...
|
|
|
|
rv = aEntry->Clone(getter_AddRefs(dest));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
dest->SetIsSubFrame(true);
|
|
|
|
|
|
|
|
if (srcID != cloneID || data->cloneChildren) {
|
|
|
|
// Walk the children
|
|
|
|
CloneAndReplaceData childData(cloneID, replaceEntry,
|
|
|
|
data->cloneChildren, dest);
|
|
|
|
rv = WalkHistoryEntries(aEntry, aShell,
|
|
|
|
CloneAndReplaceChild, &childData);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srcID != cloneID && aShell) {
|
|
|
|
aShell->SwapHistoryEntries(aEntry, dest);
|
|
|
|
}
|
|
|
|
|
2018-08-22 09:20:56 +00:00
|
|
|
if (data->destTreeParent) {
|
|
|
|
data->destTreeParent->AddChild(dest, aEntryIndex);
|
2017-12-19 10:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
data->resultEntry = dest;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
nsSHistory::CloneAndReplace(nsISHEntry* aSrcEntry,
|
|
|
|
nsDocShell* aSrcShell,
|
|
|
|
uint32_t aCloneID,
|
|
|
|
nsISHEntry* aReplaceEntry,
|
|
|
|
bool aCloneChildren,
|
|
|
|
nsISHEntry** aResultEntry)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aResultEntry);
|
|
|
|
NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr);
|
|
|
|
nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
|
|
|
|
|
|
|
|
data.resultEntry.swap(*aResultEntry);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsresult
|
|
|
|
nsSHistory::SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell,
|
|
|
|
int32_t aEntryIndex, void* aData)
|
|
|
|
{
|
|
|
|
SwapEntriesData* data = static_cast<SwapEntriesData*>(aData);
|
|
|
|
nsDocShell* ignoreShell = data->ignoreShell;
|
|
|
|
|
|
|
|
if (!aShell || aShell == ignoreShell) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsISHEntry* destTreeRoot = data->destTreeRoot;
|
|
|
|
|
|
|
|
nsCOMPtr<nsISHEntry> destEntry;
|
|
|
|
|
2018-08-22 09:20:56 +00:00
|
|
|
if (data->destTreeParent) {
|
2017-12-19 10:26:36 +00:00
|
|
|
// aEntry is a clone of some child of destTreeParent, but since the
|
|
|
|
// trees aren't necessarily in sync, we'll have to locate it.
|
|
|
|
// Note that we could set aShell's entry to null if we don't find a
|
|
|
|
// corresponding entry under destTreeParent.
|
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
uint32_t targetID = aEntry->GetID();
|
2017-12-19 10:26:36 +00:00
|
|
|
|
|
|
|
// First look at the given index, since this is the common case.
|
|
|
|
nsCOMPtr<nsISHEntry> entry;
|
2018-08-22 09:20:56 +00:00
|
|
|
data->destTreeParent->GetChildAt(aEntryIndex, getter_AddRefs(entry));
|
2018-09-07 01:56:23 +00:00
|
|
|
if (entry && entry->GetID() == targetID) {
|
2017-12-19 10:26:36 +00:00
|
|
|
destEntry.swap(entry);
|
|
|
|
} else {
|
|
|
|
int32_t childCount;
|
2018-08-22 09:20:56 +00:00
|
|
|
data->destTreeParent->GetChildCount(&childCount);
|
2017-12-19 10:26:36 +00:00
|
|
|
for (int32_t i = 0; i < childCount; ++i) {
|
2018-08-22 09:20:56 +00:00
|
|
|
data->destTreeParent->GetChildAt(i, getter_AddRefs(entry));
|
2017-12-19 10:26:36 +00:00
|
|
|
if (!entry) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
if (entry->GetID() == targetID) {
|
2017-12-19 10:26:36 +00:00
|
|
|
destEntry.swap(entry);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
destEntry = destTreeRoot;
|
|
|
|
}
|
|
|
|
|
|
|
|
aShell->SwapHistoryEntries(aEntry, destEntry);
|
|
|
|
|
|
|
|
// Now handle the children of aEntry.
|
|
|
|
SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
|
|
|
|
return WalkHistoryEntries(aEntry, aShell, SetChildHistoryEntry, &childData);
|
|
|
|
}
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
/* Add an entry to the History list at mIndex and
|
2005-08-18 11:15:08 +00:00
|
|
|
* increment the index to point to the new entry
|
|
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool 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
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsISHistory> shistoryOfEntry = aSHEntry->GetSHistory();
|
2017-05-22 07:36:06 +00:00
|
|
|
if (shistoryOfEntry && shistoryOfEntry != this) {
|
|
|
|
NS_WARNING("The entry has been associated to another nsISHistory instance. "
|
|
|
|
"Try nsISHEntry.clone() and nsISHEntry.abandonBFCacheEntry() "
|
|
|
|
"first if you're copying an entry from another nsISHistory.");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-09-04 23:02:37 +00:00
|
|
|
nsCOMPtr<nsISHEntry> currentTxn;
|
2018-09-04 22:53:28 +00:00
|
|
|
if (mIndex >= 0) {
|
2018-09-04 23:03:22 +00:00
|
|
|
nsresult rv = GetEntryAtIndex(mIndex, getter_AddRefs(currentTxn));
|
2018-09-04 22:53:28 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
2017-04-27 10:59:11 +00:00
|
|
|
aSHEntry->SetSHistory(this);
|
|
|
|
|
2016-11-16 21:42:35 +00:00
|
|
|
// If we have a root docshell, update the docshell id of the root shentry to
|
|
|
|
// match the id of that docshell
|
|
|
|
if (mRootDocShell) {
|
|
|
|
nsID docshellID = mRootDocShell->HistoryID();
|
|
|
|
aSHEntry->SetDocshellID(&docshellID);
|
|
|
|
}
|
|
|
|
|
2018-09-04 23:02:37 +00:00
|
|
|
if (currentTxn && !currentTxn->GetPersist()) {
|
|
|
|
NOTIFY_LISTENERS(OnHistoryReplaceEntry, (mIndex));
|
|
|
|
aSHEntry->SetPersist(aPersist);
|
2018-09-04 23:03:22 +00:00
|
|
|
mEntries[mIndex] = aSHEntry;
|
2018-09-04 23:02:37 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:59 +00:00
|
|
|
}
|
2005-08-18 11:15:28 +00:00
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsIURI> uri = aSHEntry->GetURI();
|
2018-09-04 04:00:45 +00:00
|
|
|
NOTIFY_LISTENERS(OnHistoryNewEntry, (uri, mIndex));
|
2005-08-18 11:16:00 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// Remove all entries after the current one, add the new one, and set the new
|
|
|
|
// one as the current one.
|
2018-08-27 04:28:46 +00:00
|
|
|
MOZ_ASSERT(mIndex >= -1);
|
2018-09-04 23:02:37 +00:00
|
|
|
aSHEntry->SetPersist(aPersist);
|
2018-09-04 23:03:22 +00:00
|
|
|
mEntries.TruncateLength(mIndex + 1);
|
|
|
|
mEntries.AppendElement(aSHEntry);
|
2018-08-27 04:28:46 +00:00
|
|
|
mIndex++;
|
2016-10-14 07:18:29 +00:00
|
|
|
|
2006-01-27 20:34:43 +00:00
|
|
|
// Purge History list if it is too long
|
2018-08-27 04:28:46 +00:00
|
|
|
if (gHistoryMaxSize >= 0 && Length() > gHistoryMaxSize) {
|
|
|
|
PurgeHistory(Length() - gHistoryMaxSize);
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
|
|
|
|
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
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::GetCount(int32_t* aResult)
|
2005-08-18 11:15:08 +00:00
|
|
|
{
|
2018-09-11 06:08:37 +00:00
|
|
|
MOZ_ASSERT(aResult, "null out param?");
|
2018-08-27 04:28:46 +00:00
|
|
|
*aResult = Length();
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::GetIndex(int32_t* aResult)
|
2005-08-18 11:15:08 +00:00
|
|
|
{
|
2018-04-28 19:50:58 +00:00
|
|
|
MOZ_ASSERT(aResult, "null out param?");
|
2006-04-17 07:50:02 +00:00
|
|
|
*aResult = mIndex;
|
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
2018-09-04 23:02:37 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::SetIndex(int32_t aIndex)
|
|
|
|
{
|
|
|
|
if (aIndex < 0 || aIndex >= Length()) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
mIndex = aIndex;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-02-19 17:33:31 +00:00
|
|
|
/* Get the requestedIndex */
|
|
|
|
NS_IMETHODIMP
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::GetRequestedIndex(int32_t* aResult)
|
2006-02-19 17:33:31 +00:00
|
|
|
{
|
2018-04-28 19:50:58 +00:00
|
|
|
MOZ_ASSERT(aResult, "null out param?");
|
2006-04-17 07:50:02 +00:00
|
|
|
*aResult = mRequestedIndex;
|
|
|
|
return NS_OK;
|
2006-02-19 17:33:31 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:14 +00:00
|
|
|
NS_IMETHODIMP
|
2018-09-04 23:02:37 +00:00
|
|
|
nsSHistory::GetEntryAtIndex(int32_t aIndex, nsISHEntry** aResult)
|
2005-08-18 11:15:14 +00:00
|
|
|
{
|
2006-04-17 07:50:02 +00:00
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
|
2018-08-27 04:28:46 +00:00
|
|
|
if (aIndex < 0 || aIndex >= Length()) {
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2006-04-17 07:50:02 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
*aResult = mEntries[aIndex];
|
2018-08-27 04:28:46 +00:00
|
|
|
NS_ADDREF(*aResult);
|
2006-04-17 07:50:02 +00:00
|
|
|
return NS_OK;
|
2005-08-18 11:15:08 +00:00
|
|
|
}
|
|
|
|
|
2018-09-11 06:08:39 +00:00
|
|
|
NS_IMETHODIMP_(int32_t)
|
|
|
|
nsSHistory::GetIndexOfEntry(nsISHEntry* aSHEntry)
|
2015-05-06 17:57:23 +00:00
|
|
|
{
|
2018-08-27 04:28:46 +00:00
|
|
|
for (int32_t i = 0; i < Length(); i++) {
|
2018-09-04 23:03:22 +00:00
|
|
|
if (aSHEntry == mEntries[i]) {
|
2018-09-11 06:08:39 +00:00
|
|
|
return i;
|
2014-04-24 19:12:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-11 06:08:39 +00:00
|
|
|
return -1;
|
2014-04-24 19:12:15 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:52 +00:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsresult
|
2005-08-18 11:15:14 +00:00
|
|
|
nsSHistory::PrintHistory()
|
|
|
|
{
|
2018-08-27 04:28:46 +00:00
|
|
|
for (int32_t i = 0; i < Length(); i++) {
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> entry = mEntries[i];
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsILayoutHistoryState> layoutHistoryState =
|
|
|
|
entry->GetLayoutHistoryState();
|
|
|
|
nsCOMPtr<nsIURI> uri = entry->GetURI();
|
2017-08-08 06:07:55 +00:00
|
|
|
nsString title;
|
2018-09-05 01:29:36 +00:00
|
|
|
entry->GetTitle(title);
|
2006-04-17 07:50:02 +00:00
|
|
|
|
2005-08-18 11:16:35 +00:00
|
|
|
#if 0
|
2012-09-02 02:35:17 +00:00
|
|
|
nsAutoCString url;
|
2015-05-06 17:57:23 +00:00
|
|
|
if (uri) {
|
|
|
|
uri->GetSpec(url);
|
|
|
|
}
|
2006-04-17 07:50:02 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
printf("**** SH Entry #%d: %x\n", i, 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
|
2006-04-17 07:50:02 +00:00
|
|
|
}
|
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
|
|
|
|
2018-08-28 02:00:41 +00:00
|
|
|
void
|
|
|
|
nsSHistory::WindowIndices(int32_t aIndex, int32_t* aOutStartIndex,
|
|
|
|
int32_t* aOutEndIndex)
|
|
|
|
{
|
2018-09-11 06:08:39 +00:00
|
|
|
*aOutStartIndex = std::max(0, aIndex - nsSHistory::VIEWER_WINDOW);
|
|
|
|
*aOutEndIndex = std::min(Length() - 1, aIndex + nsSHistory::VIEWER_WINDOW);
|
2018-08-28 02:00:41 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
NS_IMETHODIMP
|
2018-08-27 04:28:46 +00:00
|
|
|
nsSHistory::PurgeHistory(int32_t aNumEntries)
|
2005-08-18 11:15:59 +00:00
|
|
|
{
|
2018-08-27 04:28:46 +00:00
|
|
|
if (Length() <= 0 || aNumEntries <= 0) {
|
2005-08-18 11:15:59 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2005-08-18 11:16:51 +00:00
|
|
|
|
2018-08-27 04:28:46 +00:00
|
|
|
aNumEntries = std::min(aNumEntries, Length());
|
2015-05-06 17:57:23 +00:00
|
|
|
|
2018-09-06 06:51:58 +00:00
|
|
|
NOTIFY_LISTENERS(OnHistoryPurge, (aNumEntries));
|
2005-08-18 11:16:00 +00:00
|
|
|
|
2018-08-27 04:28:46 +00:00
|
|
|
// Remove the first `aNumEntries` entries.
|
2018-09-04 23:03:22 +00:00
|
|
|
mEntries.RemoveElementsAt(0, aNumEntries);
|
2018-08-27 04:28:46 +00:00
|
|
|
|
2018-08-31 06:25:32 +00:00
|
|
|
// Adjust the indices, but don't let them go below -1.
|
2018-08-27 04:28:46 +00:00
|
|
|
mIndex -= aNumEntries;
|
2018-08-31 06:25:32 +00:00
|
|
|
mIndex = std::max(mIndex, -1);
|
|
|
|
mRequestedIndex -= aNumEntries;
|
|
|
|
mRequestedIndex = std::max(mRequestedIndex, -1);
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
if (mRootDocShell) {
|
2018-08-27 04:28:46 +00:00
|
|
|
mRootDocShell->HistoryPurged(aNumEntries);
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2008-09-11 21:54:40 +00:00
|
|
|
|
2005-08-18 11:15:59 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:00 +00:00
|
|
|
NS_IMETHODIMP
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::AddSHistoryListener(nsISHistoryListener* aListener)
|
2005-08-18 11:16:00 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aListener);
|
|
|
|
|
|
|
|
// Check if the listener supports Weak Reference. This is a must.
|
2015-05-06 17:57:23 +00:00
|
|
|
// This listener functionality is used by embedders and we want to
|
2005-08-18 11:16:00 +00:00
|
|
|
// have the right ownership with who ever listens to SHistory
|
2005-08-18 11:16:50 +00:00
|
|
|
nsWeakPtr listener = do_GetWeakReference(aListener);
|
2015-05-06 17:57:23 +00:00
|
|
|
if (!listener) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2012-09-20 14:41:18 +00:00
|
|
|
|
2018-10-14 16:12:23 +00:00
|
|
|
mListeners.AppendElementUnlessExists(listener);
|
|
|
|
return NS_OK;
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::RemoveSHistoryListener(nsISHistoryListener* aListener)
|
2005-08-18 11:16:00 +00:00
|
|
|
{
|
2005-08-18 11:16:22 +00:00
|
|
|
// Make sure the listener that wants to be removed is the
|
2015-05-06 17:57:23 +00:00
|
|
|
// one we have in store.
|
2012-09-20 14:41:18 +00:00
|
|
|
nsWeakPtr listener = do_GetWeakReference(aListener);
|
|
|
|
mListeners.RemoveElement(listener);
|
|
|
|
return NS_OK;
|
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
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::ReplaceEntry(int32_t aIndex, nsISHEntry* aReplaceEntry)
|
2005-08-18 11:16:24 +00:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aReplaceEntry);
|
|
|
|
|
2018-09-04 23:02:37 +00:00
|
|
|
if (aIndex < 0 || aIndex >= Length()) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsISHistory> shistoryOfEntry = aReplaceEntry->GetSHistory();
|
2018-09-04 22:53:28 +00:00
|
|
|
if (shistoryOfEntry && shistoryOfEntry != this) {
|
|
|
|
NS_WARNING("The entry has been associated to another nsISHistory instance. "
|
|
|
|
"Try nsISHEntry.clone() and nsISHEntry.abandonBFCacheEntry() "
|
|
|
|
"first if you're copying an entry from another nsISHistory.");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2005-08-18 11:16:24 +00:00
|
|
|
|
2018-09-04 22:53:28 +00:00
|
|
|
aReplaceEntry->SetSHistory(this);
|
2017-05-22 07:36:06 +00:00
|
|
|
|
2018-09-04 22:53:28 +00:00
|
|
|
NOTIFY_LISTENERS(OnHistoryReplaceEntry, (aIndex));
|
2014-04-24 19:12:15 +00:00
|
|
|
|
2018-09-04 23:02:37 +00:00
|
|
|
aReplaceEntry->SetPersist(true);
|
2018-09-04 23:03:22 +00:00
|
|
|
mEntries[aIndex] = aReplaceEntry;
|
2018-09-04 22:53:28 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
2005-08-18 11:16:24 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:30 +00:00
|
|
|
NS_IMETHODIMP
|
2012-09-20 14:41:18 +00:00
|
|
|
nsSHistory::NotifyOnHistoryReload(nsIURI* aReloadURI, uint32_t aReloadFlags,
|
|
|
|
bool* aCanReload)
|
2005-08-18 11:16:30 +00:00
|
|
|
{
|
2012-09-20 14:41:18 +00:00
|
|
|
NOTIFY_LISTENERS_CANCELABLE(OnHistoryReload, *aCanReload,
|
|
|
|
(aReloadURI, aReloadFlags, aCanReload));
|
2005-08-18 11:16:30 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:17:00 +00:00
|
|
|
NS_IMETHODIMP
|
2012-08-22 15:56:38 +00:00
|
|
|
nsSHistory::EvictOutOfRangeContentViewers(int32_t 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
|
2011-10-21 15:26:34 +00:00
|
|
|
EvictOutOfRangeWindowContentViewers(aIndex);
|
2005-09-23 18:16:40 +00:00
|
|
|
// Check our total limit across all SHistory objects
|
2011-10-21 15:26:34 +00:00
|
|
|
GloballyEvictContentViewers();
|
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.
|
2018-08-27 04:28:46 +00:00
|
|
|
for (int32_t i = 0; i < Length(); i++) {
|
2018-09-04 23:03:22 +00:00
|
|
|
EvictContentViewerForEntry(mEntries[i]);
|
2011-10-21 15:26:34 +00:00
|
|
|
}
|
|
|
|
|
2009-01-13 19:32:30 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-02 23:27:37 +00:00
|
|
|
nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
nsSHistory::Reload(uint32_t aReloadFlags)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2018-07-02 23:32:47 +00:00
|
|
|
uint32_t loadType;
|
2015-05-06 17:57:23 +00:00
|
|
|
if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY &&
|
|
|
|
aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) {
|
2018-07-02 23:32:47 +00:00
|
|
|
loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
|
2015-05-06 17:57:23 +00:00
|
|
|
} else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY) {
|
2018-07-02 23:32:47 +00:00
|
|
|
loadType = LOAD_RELOAD_BYPASS_PROXY;
|
2015-05-06 17:57:23 +00:00
|
|
|
} else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) {
|
2018-07-02 23:32:47 +00:00
|
|
|
loadType = LOAD_RELOAD_BYPASS_CACHE;
|
2015-05-06 17:57:23 +00:00
|
|
|
} else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE) {
|
2018-07-02 23:32:47 +00:00
|
|
|
loadType = LOAD_RELOAD_CHARSET_CHANGE;
|
2015-05-06 17:57:23 +00:00
|
|
|
} else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
|
2018-07-02 23:32:47 +00:00
|
|
|
loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
|
2015-05-06 17:57:23 +00:00
|
|
|
} else {
|
2018-07-02 23:32:47 +00:00
|
|
|
loadType = LOAD_RELOAD_NORMAL;
|
2006-04-17 07:50:02 +00:00
|
|
|
}
|
2013-01-30 08:04:31 +00:00
|
|
|
|
2012-09-20 14:41:18 +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.
|
2011-09-29 06:19:26 +00:00
|
|
|
bool canNavigate = true;
|
2012-09-20 14:41:18 +00:00
|
|
|
nsCOMPtr<nsIURI> currentURI;
|
2013-02-05 08:39:24 +00:00
|
|
|
GetCurrentURI(getter_AddRefs(currentURI));
|
2012-09-20 14:41:18 +00:00
|
|
|
NOTIFY_LISTENERS_CANCELABLE(OnHistoryReload, canNavigate,
|
|
|
|
(currentURI, aReloadFlags, &canNavigate));
|
2015-05-06 17:57:23 +00:00
|
|
|
if (!canNavigate) {
|
2005-08-18 11:16:00 +00:00
|
|
|
return NS_OK;
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2005-08-18 11:16:00 +00:00
|
|
|
|
2006-04-17 07:50:02 +00:00
|
|
|
return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD);
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
2010-12-27 21:22:46 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::ReloadCurrentEntry()
|
|
|
|
{
|
|
|
|
// Notify listeners
|
2012-09-20 14:41:18 +00:00
|
|
|
nsCOMPtr<nsIURI> currentURI;
|
|
|
|
GetCurrentURI(getter_AddRefs(currentURI));
|
2018-09-06 06:51:58 +00:00
|
|
|
NOTIFY_LISTENERS(OnHistoryGotoIndex, (mIndex, currentURI));
|
2010-12-27 21:22:46 +00:00
|
|
|
|
2018-07-02 23:32:47 +00:00
|
|
|
return LoadEntry(mIndex, LOAD_HISTORY, HIST_CMD_RELOAD);
|
2010-12-27 21:22:46 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:17:00 +00:00
|
|
|
void
|
2012-08-22 15:56:38 +00:00
|
|
|
nsSHistory::EvictOutOfRangeWindowContentViewers(int32_t aIndex)
|
2005-08-18 11:17:00 +00:00
|
|
|
{
|
2011-10-21 15:26:34 +00:00
|
|
|
// XXX rename method to EvictContentViewersExceptAroundIndex, or something.
|
|
|
|
|
|
|
|
// We need to release all content viewers that are no longer in the range
|
|
|
|
//
|
2016-12-15 05:28:40 +00:00
|
|
|
// aIndex - VIEWER_WINDOW to aIndex + VIEWER_WINDOW
|
2011-10-21 15:26:34 +00:00
|
|
|
//
|
|
|
|
// to ensure that this SHistory object isn't responsible for more than
|
2016-12-15 05:28:40 +00:00
|
|
|
// VIEWER_WINDOW content viewers. But our job is complicated by the
|
2018-09-04 23:03:22 +00:00
|
|
|
// fact that two entries which are related by either hash navigations or
|
2011-10-21 15:26:34 +00:00
|
|
|
// history.pushState will have the same content viewer.
|
|
|
|
//
|
2016-12-15 05:28:40 +00:00
|
|
|
// To illustrate the issue, suppose VIEWER_WINDOW = 3 and we have four
|
2018-09-04 23:03:22 +00:00
|
|
|
// linked entries in our history. Suppose we then add a new content
|
2011-10-21 15:26:34 +00:00
|
|
|
// viewer and call into this function. So the history looks like:
|
|
|
|
//
|
|
|
|
// A A A A B
|
|
|
|
// + *
|
|
|
|
//
|
|
|
|
// where the letters are content viewers and + and * denote the beginning and
|
2016-12-15 05:28:40 +00:00
|
|
|
// end of the range aIndex +/- VIEWER_WINDOW.
|
2011-05-13 19:42:36 +00:00
|
|
|
//
|
2011-10-21 15:26:34 +00:00
|
|
|
// Although one copy of the content viewer A exists outside the range, we
|
|
|
|
// don't want to evict A, because it has other copies in range!
|
|
|
|
//
|
|
|
|
// We therefore adjust our eviction strategy to read:
|
|
|
|
//
|
|
|
|
// Evict each content viewer outside the range aIndex -/+
|
2016-12-15 05:28:40 +00:00
|
|
|
// VIEWER_WINDOW, unless that content viewer also appears within the
|
2011-10-21 15:26:34 +00:00
|
|
|
// range.
|
|
|
|
//
|
|
|
|
// (Note that it's entirely legal to have two copies of one content viewer
|
|
|
|
// separated by a different content viewer -- call pushState twice, go back
|
|
|
|
// once, and refresh -- so we can't rely on identical viewers only appearing
|
|
|
|
// adjacent to one another.)
|
2005-09-23 18:16:40 +00:00
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
if (aIndex < 0) {
|
2005-09-23 18:16:40 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-08-27 04:28:46 +00:00
|
|
|
NS_ENSURE_TRUE_VOID(aIndex < Length());
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
// Calculate the range that's safe from eviction.
|
2018-08-28 02:00:41 +00:00
|
|
|
int32_t startSafeIndex, endSafeIndex;
|
|
|
|
WindowIndices(aIndex, &startSafeIndex, &endSafeIndex);
|
2011-10-13 00:15:28 +00:00
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
LOG(("EvictOutOfRangeWindowContentViewers(index=%d), "
|
2018-08-27 04:28:46 +00:00
|
|
|
"Length()=%d. Safe range [%d, %d]",
|
|
|
|
aIndex, Length(), startSafeIndex, endSafeIndex));
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2016-12-15 05:28:40 +00:00
|
|
|
// The content viewers in range aIndex -/+ VIEWER_WINDOW will not be
|
2011-10-21 15:26:34 +00:00
|
|
|
// evicted. Collect a set of them so we don't accidentally evict one of them
|
|
|
|
// if it appears outside this range.
|
|
|
|
nsCOMArray<nsIContentViewer> safeViewers;
|
2018-08-27 04:28:46 +00:00
|
|
|
for (int32_t i = startSafeIndex; i <= endSafeIndex; i++) {
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsIContentViewer> viewer = GetContentViewerForEntry(mEntries[i]);
|
2011-10-21 15:26:34 +00:00
|
|
|
safeViewers.AppendObject(viewer);
|
|
|
|
}
|
2011-10-13 00:15:28 +00:00
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
// Walk the SHistory list and evict any content viewers that aren't safe.
|
2018-08-27 04:28:46 +00:00
|
|
|
// (It's important that the condition checks Length(), rather than a cached
|
|
|
|
// copy of Length(), because the length might change between iterations.)
|
|
|
|
for (int32_t i = 0; i < Length(); i++) {
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> entry = mEntries[i];
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer = GetContentViewerForEntry(entry);
|
2011-10-21 15:26:34 +00:00
|
|
|
if (safeViewers.IndexOf(viewer) == -1) {
|
2018-09-04 23:03:22 +00:00
|
|
|
EvictContentViewerForEntry(entry);
|
2007-11-17 06:28:56 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-13 00:15:28 +00:00
|
|
|
}
|
2011-10-18 01:09:17 +00:00
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
namespace {
|
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
class EntryAndDistance
|
2007-09-21 09:19:59 +00:00
|
|
|
{
|
2011-10-21 15:26:34 +00:00
|
|
|
public:
|
2018-09-04 23:03:22 +00:00
|
|
|
EntryAndDistance(nsSHistory* aSHistory, nsISHEntry* aEntry, uint32_t aDist)
|
2017-01-24 06:56:37 +00:00
|
|
|
: mSHistory(aSHistory)
|
2018-09-04 23:03:22 +00:00
|
|
|
, mEntry(aEntry)
|
2016-01-12 18:16:59 +00:00
|
|
|
, mLastTouched(0)
|
2011-10-21 15:26:34 +00:00
|
|
|
, mDistance(aDist)
|
|
|
|
{
|
2018-09-04 23:03:22 +00:00
|
|
|
mViewer = GetContentViewerForEntry(aEntry);
|
|
|
|
NS_ASSERTION(mViewer, "Entry should have a content viewer");
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
mLastTouched = mEntry->GetLastTouched();
|
2011-10-21 15:26:34 +00:00
|
|
|
}
|
2005-08-18 11:17:00 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
bool operator<(const EntryAndDistance& aOther) const
|
2011-10-21 15:26:34 +00:00
|
|
|
{
|
|
|
|
// Compare distances first, and fall back to last-accessed times.
|
|
|
|
if (aOther.mDistance != this->mDistance) {
|
|
|
|
return this->mDistance < aOther.mDistance;
|
2005-08-18 11:17:00 +00:00
|
|
|
}
|
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
return this->mLastTouched < aOther.mLastTouched;
|
2011-10-18 01:09:17 +00:00
|
|
|
}
|
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
bool operator==(const EntryAndDistance& aOther) const
|
2011-10-21 15:26:34 +00:00
|
|
|
{
|
|
|
|
// This is a little silly; we need == so the default comaprator can be
|
|
|
|
// instantiated, but this function is never actually called when we sort
|
2018-09-04 23:03:22 +00:00
|
|
|
// the list of EntryAndDistance objects.
|
2011-10-21 15:26:34 +00:00
|
|
|
return aOther.mDistance == this->mDistance &&
|
|
|
|
aOther.mLastTouched == this->mLastTouched;
|
|
|
|
}
|
|
|
|
|
2017-01-24 06:56:37 +00:00
|
|
|
RefPtr<nsSHistory> mSHistory;
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> mEntry;
|
2011-10-21 15:26:34 +00:00
|
|
|
nsCOMPtr<nsIContentViewer> mViewer;
|
2012-08-22 15:56:38 +00:00
|
|
|
uint32_t mLastTouched;
|
|
|
|
int32_t mDistance;
|
2011-10-21 15:26:34 +00:00
|
|
|
};
|
|
|
|
|
2015-07-13 15:25:42 +00:00
|
|
|
} // namespace
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
// static
|
2005-09-23 18:16:40 +00:00
|
|
|
void
|
2011-10-21 15:26:34 +00:00
|
|
|
nsSHistory::GloballyEvictContentViewers()
|
2005-09-23 18:16:40 +00:00
|
|
|
{
|
2018-09-04 23:03:22 +00:00
|
|
|
// First, collect from each SHistory object the entries which have a cached
|
|
|
|
// content viewer. Associate with each entry its distance from its SHistory's
|
|
|
|
// current index.
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
nsTArray<EntryAndDistance> entries;
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2017-04-19 17:05:00 +00:00
|
|
|
for (auto shist : gSHistoryList) {
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// Maintain a list of the entries which have viewers and belong to
|
2011-10-21 15:26:34 +00:00
|
|
|
// this particular shist object. We'll add this list to the global list,
|
2018-09-04 23:03:22 +00:00
|
|
|
// |entries|, eventually.
|
|
|
|
nsTArray<EntryAndDistance> shEntries;
|
2011-10-21 15:26:34 +00:00
|
|
|
|
|
|
|
// Content viewers are likely to exist only within shist->mIndex -/+
|
2016-12-15 05:28:40 +00:00
|
|
|
// VIEWER_WINDOW, so only search within that range.
|
2011-10-21 15:26:34 +00:00
|
|
|
//
|
|
|
|
// A content viewer might exist outside that range due to either:
|
|
|
|
//
|
|
|
|
// * history.pushState or hash navigations, in which case a copy of the
|
|
|
|
// content viewer should exist within the range, or
|
|
|
|
//
|
|
|
|
// * bugs which cause us not to call nsSHistory::EvictContentViewers()
|
|
|
|
// often enough. Once we do call EvictContentViewers() for the
|
|
|
|
// SHistory object in question, we'll do a full search of its history
|
|
|
|
// and evict the out-of-range content viewers, so we don't bother here.
|
|
|
|
//
|
2018-08-28 02:00:41 +00:00
|
|
|
int32_t startIndex, endIndex;
|
|
|
|
shist->WindowIndices(shist->mIndex, &startIndex, &endIndex);
|
2018-08-27 04:28:46 +00:00
|
|
|
for (int32_t i = startIndex; i <= endIndex; i++) {
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> entry = shist->mEntries[i];
|
2011-10-21 15:26:34 +00:00
|
|
|
nsCOMPtr<nsIContentViewer> contentViewer =
|
2018-09-04 23:03:22 +00:00
|
|
|
GetContentViewerForEntry(entry);
|
2011-10-21 15:26:34 +00:00
|
|
|
|
|
|
|
if (contentViewer) {
|
|
|
|
// Because one content viewer might belong to multiple SHEntries, we
|
2018-09-04 23:03:22 +00:00
|
|
|
// have to search through shEntries to see if we already know
|
2011-10-21 15:26:34 +00:00
|
|
|
// about this content viewer. If we find the viewer, update its
|
|
|
|
// distance from the SHistory's index and continue.
|
|
|
|
bool found = false;
|
2018-09-04 23:03:22 +00:00
|
|
|
for (uint32_t j = 0; j < shEntries.Length(); j++) {
|
|
|
|
EntryAndDistance& container = shEntries[j];
|
2011-10-21 15:26:34 +00:00
|
|
|
if (container.mViewer == contentViewer) {
|
2015-05-06 17:57:23 +00:00
|
|
|
container.mDistance = std::min(container.mDistance,
|
|
|
|
DeprecatedAbs(i - shist->mIndex));
|
2011-10-21 15:26:34 +00:00
|
|
|
found = true;
|
|
|
|
break;
|
2011-01-19 19:57:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// If we didn't find a EntryAndDistance for this content viewer, make a
|
|
|
|
// new one.
|
2011-10-21 15:26:34 +00:00
|
|
|
if (!found) {
|
2018-09-04 23:03:22 +00:00
|
|
|
EntryAndDistance container(shist, entry,
|
|
|
|
DeprecatedAbs(i - shist->mIndex));
|
|
|
|
shEntries.AppendElement(container);
|
2011-10-13 00:15:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-05-13 19:42:36 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// We've found all the entries belonging to shist which have viewers.
|
|
|
|
// Add those entries to our global list and move on.
|
|
|
|
entries.AppendElements(shEntries);
|
2011-10-21 15:26:34 +00:00
|
|
|
}
|
2011-05-13 19:42:36 +00:00
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
// We now have collected all cached content viewers. First check that we
|
|
|
|
// have enough that we actually need to evict some.
|
2018-09-04 23:03:22 +00:00
|
|
|
if ((int32_t)entries.Length() <= sHistoryMaxTotalViewers) {
|
2011-10-21 15:26:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2011-10-18 01:09:17 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// If we need to evict, sort our list of entries and evict the largest
|
2011-10-21 15:26:34 +00:00
|
|
|
// ones. (We could of course get better algorithmic complexity here by using
|
|
|
|
// a heap or something more clever. But sHistoryMaxTotalViewers isn't large,
|
|
|
|
// so let's not worry about it.)
|
2018-09-04 23:03:22 +00:00
|
|
|
entries.Sort();
|
2011-10-18 01:09:17 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
for (int32_t i = entries.Length() - 1; i >= sHistoryMaxTotalViewers;
|
2015-05-06 17:57:23 +00:00
|
|
|
--i) {
|
2018-09-04 23:03:22 +00:00
|
|
|
(entries[i].mSHistory)->EvictContentViewerForEntry(entries[i].mEntry);
|
2011-10-21 15:26:34 +00:00
|
|
|
}
|
2005-09-23 18:16:40 +00:00
|
|
|
}
|
|
|
|
|
2011-10-21 15:26:34 +00:00
|
|
|
nsresult
|
2018-09-04 23:03:22 +00:00
|
|
|
nsSHistory::FindEntryForBFCache(nsIBFCacheEntry* aBFEntry,
|
|
|
|
nsISHEntry** aResult,
|
|
|
|
int32_t* aResultIndex)
|
2007-09-21 09:19:59 +00:00
|
|
|
{
|
2017-08-24 06:32:23 +00:00
|
|
|
*aResult = nullptr;
|
|
|
|
*aResultIndex = -1;
|
|
|
|
|
2018-08-28 02:00:41 +00:00
|
|
|
int32_t startIndex, endIndex;
|
|
|
|
WindowIndices(mIndex, &startIndex, &endIndex);
|
2007-09-21 09:19:59 +00:00
|
|
|
|
2018-08-27 04:28:46 +00:00
|
|
|
for (int32_t i = startIndex; i <= endIndex; ++i) {
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> shEntry = mEntries[i];
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// Does shEntry have the same BFCacheEntry as the argument to this method?
|
|
|
|
if (shEntry->HasBFCacheEntry(aBFEntry)) {
|
|
|
|
shEntry.forget(aResult);
|
2018-08-27 04:28:46 +00:00
|
|
|
*aResultIndex = i;
|
|
|
|
return NS_OK;
|
2011-10-21 15:26:34 +00:00
|
|
|
}
|
2007-09-21 09:19:59 +00:00
|
|
|
}
|
2018-08-27 04:28:46 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2017-08-24 06:32:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2018-09-04 23:03:22 +00:00
|
|
|
nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aBFEntry)
|
2017-08-24 06:32:23 +00:00
|
|
|
{
|
|
|
|
int32_t index;
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> shEntry;
|
|
|
|
FindEntryForBFCache(aBFEntry, getter_AddRefs(shEntry), &index);
|
2017-08-24 06:32:23 +00:00
|
|
|
|
|
|
|
if (index == mIndex) {
|
2011-10-21 15:26:34 +00:00
|
|
|
NS_WARNING("How did the current SHEntry expire?");
|
2007-09-21 09:19:59 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
if (shEntry) {
|
|
|
|
EvictContentViewerForEntry(shEntry);
|
2017-08-24 06:32:23 +00:00
|
|
|
}
|
2011-10-21 15:26:34 +00:00
|
|
|
|
2007-09-21 09:19:59 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-09-11 06:08:39 +00:00
|
|
|
NS_IMETHODIMP_(void)
|
2018-09-04 23:03:22 +00:00
|
|
|
nsSHistory::AddToExpirationTracker(nsIBFCacheEntry* aBFEntry)
|
2017-04-27 10:59:11 +00:00
|
|
|
{
|
2018-09-04 23:03:22 +00:00
|
|
|
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aBFEntry);
|
2017-04-27 10:59:11 +00:00
|
|
|
if (!mHistoryTracker || !entry) {
|
2018-09-11 06:08:39 +00:00
|
|
|
return;
|
2017-04-27 10:59:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mHistoryTracker->AddObject(entry);
|
2018-09-11 06:08:39 +00:00
|
|
|
return;
|
2017-04-27 10:59:11 +00:00
|
|
|
}
|
|
|
|
|
2018-09-11 06:08:39 +00:00
|
|
|
NS_IMETHODIMP_(void)
|
2018-09-04 23:03:22 +00:00
|
|
|
nsSHistory::RemoveFromExpirationTracker(nsIBFCacheEntry* aBFEntry)
|
2017-04-27 10:59:11 +00:00
|
|
|
{
|
2018-09-04 23:03:22 +00:00
|
|
|
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aBFEntry);
|
2017-05-22 03:25:54 +00:00
|
|
|
MOZ_ASSERT(mHistoryTracker && !mHistoryTracker->IsEmpty());
|
2017-04-27 10:59:11 +00:00
|
|
|
if (!mHistoryTracker || !entry) {
|
2018-09-11 06:08:39 +00:00
|
|
|
return;
|
2017-04-27 10:59:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mHistoryTracker->RemoveObject(entry);
|
2018-09-11 06:08:39 +00:00
|
|
|
return;
|
2017-04-27 10:59:11 +00:00
|
|
|
}
|
|
|
|
|
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.
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
// static
|
2005-09-29 20:24:27 +00:00
|
|
|
void
|
2011-10-21 15:26:34 +00:00
|
|
|
nsSHistory::GloballyEvictAllContentViewers()
|
2005-09-29 20:24:27 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t maxViewers = sHistoryMaxTotalViewers;
|
2005-09-29 20:24:27 +00:00
|
|
|
sHistoryMaxTotalViewers = 0;
|
2011-10-21 15:26:34 +00:00
|
|
|
GloballyEvictContentViewers();
|
2005-09-29 20:24:27 +00:00
|
|
|
sHistoryMaxTotalViewers = maxViewers;
|
|
|
|
}
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
void
|
2018-08-22 09:20:56 +00:00
|
|
|
GetDynamicChildren(nsISHEntry* aEntry,
|
2016-11-16 21:42:35 +00:00
|
|
|
nsTArray<nsID>& aDocshellIDs,
|
2015-05-06 17:57:23 +00:00
|
|
|
bool aOnlyTopLevelDynamic)
|
2010-08-17 14:13:55 +00:00
|
|
|
{
|
2018-09-07 01:56:23 +00:00
|
|
|
int32_t count = aEntry->GetChildCount();
|
2012-08-22 15:56:38 +00:00
|
|
|
for (int32_t i = 0; i < count; ++i) {
|
2010-08-17 14:13:55 +00:00
|
|
|
nsCOMPtr<nsISHEntry> child;
|
2018-08-22 09:20:56 +00:00
|
|
|
aEntry->GetChildAt(i, getter_AddRefs(child));
|
2010-08-17 14:13:55 +00:00
|
|
|
if (child) {
|
2018-09-12 01:59:06 +00:00
|
|
|
bool dynAdded = child->IsDynamicallyAdded();
|
2010-08-17 14:13:55 +00:00
|
|
|
if (dynAdded) {
|
2016-11-16 21:42:35 +00:00
|
|
|
nsID docshellID = child->DocshellID();
|
2010-08-17 14:13:55 +00:00
|
|
|
aDocshellIDs.AppendElement(docshellID);
|
|
|
|
}
|
|
|
|
if (!dynAdded || !aOnlyTopLevelDynamic) {
|
2018-08-22 09:20:56 +00:00
|
|
|
GetDynamicChildren(child, aDocshellIDs, aOnlyTopLevelDynamic);
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2018-08-22 09:20:56 +00:00
|
|
|
RemoveFromSessionHistoryEntry(nsISHEntry* aRoot, nsTArray<nsID>& aDocshellIDs)
|
2010-08-17 14:13:55 +00:00
|
|
|
{
|
2011-09-29 06:19:26 +00:00
|
|
|
bool didRemove = false;
|
2018-09-07 01:56:23 +00:00
|
|
|
int32_t childCount = aRoot->GetChildCount();
|
2012-08-22 15:56:38 +00:00
|
|
|
for (int32_t i = childCount - 1; i >= 0; --i) {
|
2010-08-17 14:13:55 +00:00
|
|
|
nsCOMPtr<nsISHEntry> child;
|
2018-08-22 09:20:56 +00:00
|
|
|
aRoot->GetChildAt(i, getter_AddRefs(child));
|
2010-08-17 14:13:55 +00:00
|
|
|
if (child) {
|
2016-11-16 21:42:35 +00:00
|
|
|
nsID docshelldID = child->DocshellID();
|
2010-08-17 14:13:55 +00:00
|
|
|
if (aDocshellIDs.Contains(docshelldID)) {
|
2011-10-17 14:59:28 +00:00
|
|
|
didRemove = true;
|
2018-08-22 09:20:56 +00:00
|
|
|
aRoot->RemoveChild(child);
|
2010-08-17 14:13:55 +00:00
|
|
|
} else {
|
2018-08-22 09:20:56 +00:00
|
|
|
bool childRemoved = RemoveFromSessionHistoryEntry(child, aDocshellIDs);
|
|
|
|
if (childRemoved) {
|
|
|
|
didRemove = true;
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return didRemove;
|
|
|
|
}
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
bool
|
|
|
|
RemoveChildEntries(nsISHistory* aHistory, int32_t aIndex,
|
2016-11-16 21:42:35 +00:00
|
|
|
nsTArray<nsID>& aEntryIDs)
|
2010-08-17 14:13:55 +00:00
|
|
|
{
|
2018-08-22 09:20:56 +00:00
|
|
|
nsCOMPtr<nsISHEntry> root;
|
2018-09-04 23:02:37 +00:00
|
|
|
aHistory->GetEntryAtIndex(aIndex, getter_AddRefs(root));
|
2018-08-22 09:20:56 +00:00
|
|
|
return root ? RemoveFromSessionHistoryEntry(root, aEntryIDs) : false;
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
bool
|
|
|
|
IsSameTree(nsISHEntry* aEntry1, nsISHEntry* aEntry2)
|
2010-09-05 18:10:35 +00:00
|
|
|
{
|
|
|
|
if (!aEntry1 && !aEntry2) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
|
|
|
if ((!aEntry1 && aEntry2) || (aEntry1 && !aEntry2)) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
2018-09-07 01:56:23 +00:00
|
|
|
uint32_t id1 = aEntry1->GetID();
|
|
|
|
uint32_t id2 = aEntry2->GetID();
|
2010-09-05 18:10:35 +00:00
|
|
|
if (id1 != id2) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
int32_t count1 = aEntry1->GetChildCount();
|
|
|
|
int32_t count2 = aEntry2->GetChildCount();
|
2010-09-05 18:10:35 +00:00
|
|
|
// We allow null entries in the end of the child list.
|
2013-01-15 12:22:03 +00:00
|
|
|
int32_t count = std::max(count1, count2);
|
2012-08-22 15:56:38 +00:00
|
|
|
for (int32_t i = 0; i < count; ++i) {
|
2010-09-05 18:10:35 +00:00
|
|
|
nsCOMPtr<nsISHEntry> child1, child2;
|
2018-08-22 09:20:56 +00:00
|
|
|
aEntry1->GetChildAt(i, getter_AddRefs(child1));
|
|
|
|
aEntry2->GetChildAt(i, getter_AddRefs(child2));
|
2010-09-05 18:10:35 +00:00
|
|
|
if (!IsSameTree(child1, child2)) {
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-06 17:57:23 +00:00
|
|
|
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
|
|
|
|
2011-09-29 06:19:26 +00:00
|
|
|
bool
|
2012-08-22 15:56:38 +00:00
|
|
|
nsSHistory::RemoveDuplicate(int32_t aIndex, bool 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!");
|
2011-08-24 12:48:17 +00:00
|
|
|
NS_ASSERTION(aIndex != 0 || aKeepNext,
|
|
|
|
"If we're removing index 0 we must be keeping the next");
|
2010-11-15 10:11:51 +00:00
|
|
|
NS_ASSERTION(aIndex != mIndex, "Shouldn't remove mIndex!");
|
2018-08-27 04:28:46 +00:00
|
|
|
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t compareIndex = aKeepNext ? aIndex + 1 : aIndex - 1;
|
2018-08-27 04:28:46 +00:00
|
|
|
|
|
|
|
nsresult rv;
|
2013-08-30 04:14:59 +00:00
|
|
|
nsCOMPtr<nsISHEntry> root1, root2;
|
2018-09-04 23:02:37 +00:00
|
|
|
rv = GetEntryAtIndex(aIndex, getter_AddRefs(root1));
|
2018-08-27 04:28:46 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
2018-09-04 23:02:37 +00:00
|
|
|
rv = GetEntryAtIndex(compareIndex, getter_AddRefs(root2));
|
2018-08-27 04:28:46 +00:00
|
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
|
2010-09-05 18:10:35 +00:00
|
|
|
if (IsSameTree(root1, root2)) {
|
2018-09-04 23:03:22 +00:00
|
|
|
mEntries.RemoveElementAt(aIndex);
|
2010-11-15 10:11:51 +00:00
|
|
|
|
2010-11-19 12:01:10 +00:00
|
|
|
if (mRootDocShell) {
|
2018-09-04 23:03:22 +00:00
|
|
|
static_cast<nsDocShell*>(mRootDocShell)->HistoryEntryRemoved(aIndex);
|
2010-11-19 12:01:10 +00:00
|
|
|
}
|
2011-08-24 12:48:17 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// Adjust our indices to reflect the removed entry.
|
2010-11-15 10:11:51 +00:00
|
|
|
if (mIndex > aIndex) {
|
2010-09-05 18:10:35 +00:00
|
|
|
mIndex = mIndex - 1;
|
|
|
|
}
|
2011-08-24 12:48:17 +00:00
|
|
|
|
2018-09-04 23:03:22 +00:00
|
|
|
// NB: If the entry we are removing is the entry currently
|
2011-08-24 12:48:17 +00:00
|
|
|
// being navigated to (mRequestedIndex) then we adjust the index
|
|
|
|
// only if we're not keeping the next entry (because if we are keeping
|
|
|
|
// the next entry (because the current is a duplicate of the next), then
|
|
|
|
// that entry slides into the spot that we're currently pointing to.
|
|
|
|
// We don't do this adjustment for mIndex because mIndex cannot equal
|
|
|
|
// aIndex.
|
|
|
|
|
|
|
|
// NB: We don't need to guard on mRequestedIndex being nonzero here,
|
|
|
|
// because either they're strictly greater than aIndex which is at least
|
|
|
|
// zero, or they are equal to aIndex in which case aKeepNext must be true
|
|
|
|
// if aIndex is zero.
|
|
|
|
if (mRequestedIndex > aIndex || (mRequestedIndex == aIndex && !aKeepNext)) {
|
2011-08-01 21:45:45 +00:00
|
|
|
mRequestedIndex = mRequestedIndex - 1;
|
|
|
|
}
|
2011-10-17 14:59:28 +00:00
|
|
|
return true;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
2011-10-17 14:59:28 +00:00
|
|
|
return false;
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
NS_IMETHODIMP_(void)
|
2016-11-16 21:42:35 +00:00
|
|
|
nsSHistory::RemoveEntries(nsTArray<nsID>& aIDs, int32_t aStartIndex)
|
2010-08-17 14:13:55 +00:00
|
|
|
{
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t index = aStartIndex;
|
2015-05-06 17:57:23 +00:00
|
|
|
while (index >= 0 && RemoveChildEntries(this, --index, aIDs)) {
|
|
|
|
}
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t minIndex = index;
|
2010-08-17 14:13:55 +00:00
|
|
|
index = aStartIndex;
|
2015-05-06 17:57:23 +00:00
|
|
|
while (index >= 0 && RemoveChildEntries(this, index++, aIDs)) {
|
|
|
|
}
|
|
|
|
|
2010-09-05 18:10:35 +00:00
|
|
|
// We need to remove duplicate nsSHEntry trees.
|
2011-09-29 06:19:26 +00:00
|
|
|
bool didRemove = 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) {
|
2017-03-07 08:58:59 +00:00
|
|
|
mRootDocShell->DispatchLocationChangeEvent();
|
2010-09-05 18:10:35 +00:00
|
|
|
}
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-08-22 09:20:56 +00:00
|
|
|
nsSHistory::RemoveDynEntries(int32_t aIndex, nsISHEntry* aEntry)
|
2010-08-17 14:13:55 +00:00
|
|
|
{
|
2017-01-24 06:56:37 +00:00
|
|
|
// Remove dynamic entries which are at the index and belongs to the container.
|
2018-08-22 09:20:56 +00:00
|
|
|
nsCOMPtr<nsISHEntry> entry(aEntry);
|
|
|
|
if (!entry) {
|
2018-09-04 23:02:37 +00:00
|
|
|
GetEntryAtIndex(aIndex, getter_AddRefs(entry));
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
2017-01-24 06:56:37 +00:00
|
|
|
|
2018-08-22 09:20:56 +00:00
|
|
|
if (entry) {
|
2017-01-24 06:56:37 +00:00
|
|
|
AutoTArray<nsID, 16> toBeRemovedEntries;
|
2018-08-22 09:20:56 +00:00
|
|
|
GetDynamicChildren(entry, toBeRemovedEntries, true);
|
2017-01-24 06:56:37 +00:00
|
|
|
if (toBeRemovedEntries.Length()) {
|
|
|
|
RemoveEntries(toBeRemovedEntries, aIndex);
|
|
|
|
}
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-24 06:32:23 +00:00
|
|
|
void
|
2018-09-04 23:03:22 +00:00
|
|
|
nsSHistory::RemoveDynEntriesForBFCacheEntry(nsIBFCacheEntry* aBFEntry)
|
2017-08-24 06:32:23 +00:00
|
|
|
{
|
|
|
|
int32_t index;
|
2018-09-04 23:03:22 +00:00
|
|
|
nsCOMPtr<nsISHEntry> shEntry;
|
|
|
|
FindEntryForBFCache(aBFEntry, getter_AddRefs(shEntry), &index);
|
|
|
|
if (shEntry) {
|
|
|
|
RemoveDynEntries(index, shEntry);
|
2017-08-24 06:32:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:15 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSHistory::UpdateIndex()
|
|
|
|
{
|
2015-05-06 17:57:23 +00:00
|
|
|
// Update the actual index with the right value.
|
2005-08-18 11:17:00 +00:00
|
|
|
if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
|
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;
|
|
|
|
}
|
|
|
|
|
2018-09-02 23:27:37 +00:00
|
|
|
nsresult
|
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
|
|
|
|
2013-08-30 04:14:59 +00:00
|
|
|
nsCOMPtr<nsISHEntry> currentEntry;
|
2018-09-04 23:02:37 +00:00
|
|
|
rv = GetEntryAtIndex(mIndex, getter_AddRefs(currentEntry));
|
2015-05-06 17:57:23 +00:00
|
|
|
if (NS_FAILED(rv) && !currentEntry) {
|
|
|
|
return rv;
|
|
|
|
}
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsIURI> uri = currentEntry->GetURI();
|
|
|
|
uri.forget(aResultURI);
|
2005-08-18 11:16:01 +00:00
|
|
|
return rv;
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2018-09-11 06:08:39 +00:00
|
|
|
NS_IMETHODIMP
|
2017-12-14 22:03:14 +00:00
|
|
|
nsSHistory::GotoIndex(int32_t aIndex)
|
2005-08-18 11:15:37 +00:00
|
|
|
{
|
2018-07-02 23:32:47 +00:00
|
|
|
return LoadEntry(aIndex, LOAD_HISTORY, HIST_CMD_GOTOINDEX);
|
2005-08-18 11:15:37 +00:00
|
|
|
}
|
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
nsresult
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::LoadNextPossibleEntry(int32_t aNewIndex, long aLoadType,
|
|
|
|
uint32_t aHistCmd)
|
2010-08-17 14:13:55 +00:00
|
|
|
{
|
|
|
|
mRequestedIndex = -1;
|
|
|
|
if (aNewIndex < mIndex) {
|
|
|
|
return LoadEntry(aNewIndex - 1, aLoadType, aHistCmd);
|
|
|
|
}
|
|
|
|
if (aNewIndex > mIndex) {
|
|
|
|
return LoadEntry(aNewIndex + 1, aLoadType, aHistCmd);
|
|
|
|
}
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2017-08-24 03:27:11 +00:00
|
|
|
nsresult
|
2012-08-22 15:56:38 +00:00
|
|
|
nsSHistory::LoadEntry(int32_t aIndex, long aLoadType, uint32_t aHistCmd)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2016-10-20 09:33:22 +00:00
|
|
|
if (!mRootDocShell) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2018-08-27 04:28:46 +00:00
|
|
|
if (aIndex < 0 || aIndex >= Length()) {
|
2017-12-14 22:03:14 +00:00
|
|
|
// The index is out of range
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2016-10-14 07:18:29 +00:00
|
|
|
|
2017-12-14 22:03:14 +00:00
|
|
|
// This is a normal local history navigation.
|
|
|
|
// Keep note of requested history index in mRequestedIndex.
|
|
|
|
mRequestedIndex = aIndex;
|
2016-10-14 07:18:29 +00:00
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsISHEntry> prevEntry;
|
|
|
|
nsCOMPtr<nsISHEntry> nextEntry;
|
2018-09-04 23:02:37 +00:00
|
|
|
GetEntryAtIndex(mIndex, getter_AddRefs(prevEntry));
|
|
|
|
GetEntryAtIndex(mRequestedIndex, getter_AddRefs(nextEntry));
|
2017-12-14 22:03:14 +00:00
|
|
|
if (!nextEntry || !prevEntry) {
|
|
|
|
mRequestedIndex = -1;
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2017-12-14 22:03:14 +00:00
|
|
|
// Remember that this entry is getting loaded at this point in the sequence
|
2009-09-01 16:45:05 +00:00
|
|
|
|
2018-08-22 09:13:57 +00:00
|
|
|
nextEntry->SetLastTouched(++gTouchCounter);
|
2009-09-01 16:45:05 +00:00
|
|
|
|
2017-12-14 22:03:14 +00:00
|
|
|
// Get the uri for the entry we are about to visit
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsIURI> nextURI = nextEntry->GetURI();
|
2017-12-14 22:03:14 +00:00
|
|
|
|
|
|
|
MOZ_ASSERT((prevEntry && nextEntry && nextURI), "prevEntry, nextEntry and nextURI can't be null");
|
2011-01-19 19:57:36 +00:00
|
|
|
|
2017-12-14 22:03:14 +00:00
|
|
|
// Send appropriate listener notifications.
|
2018-09-02 23:27:37 +00:00
|
|
|
if (aHistCmd == HIST_CMD_GOTOINDEX) {
|
2012-09-20 14:41:18 +00:00
|
|
|
// We are going somewhere else. This is not reload either
|
2018-09-06 06:51:58 +00:00
|
|
|
NOTIFY_LISTENERS(OnHistoryGotoIndex, (aIndex, nextURI));
|
2005-08-18 11:16:00 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:15 +00:00
|
|
|
if (mRequestedIndex == mIndex) {
|
2015-05-06 17:57:23 +00:00
|
|
|
// Possibly a reload case
|
2016-10-20 09:33:22 +00:00
|
|
|
return InitiateLoad(nextEntry, mRootDocShell, aLoadType);
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2016-10-20 09:33:22 +00:00
|
|
|
// Going back or forward.
|
|
|
|
bool differenceFound = false;
|
|
|
|
nsresult rv = LoadDifferingEntries(prevEntry, nextEntry, mRootDocShell,
|
|
|
|
aLoadType, differenceFound);
|
|
|
|
if (!differenceFound) {
|
|
|
|
// We did not find any differences. Go further in the history.
|
|
|
|
return LoadNextPossibleEntry(aIndex, aLoadType, aHistCmd);
|
2005-08-18 11:16:07 +00:00
|
|
|
}
|
2005-08-18 11:16:01 +00:00
|
|
|
|
2016-10-20 09:33:22 +00:00
|
|
|
return rv;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
nsresult
|
2016-10-20 09:33:22 +00:00
|
|
|
nsSHistory::LoadDifferingEntries(nsISHEntry* aPrevEntry, nsISHEntry* aNextEntry,
|
|
|
|
nsIDocShell* aParent, long aLoadType,
|
|
|
|
bool& aDifferenceFound)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
2015-05-06 17:57:23 +00:00
|
|
|
if (!aPrevEntry || !aNextEntry || !aParent) {
|
2010-08-17 14:13:55 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2010-08-17 14:13:55 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
nsresult result = NS_OK;
|
2018-09-07 01:56:23 +00:00
|
|
|
uint32_t prevID = aPrevEntry->GetID();
|
|
|
|
uint32_t nextID = aNextEntry->GetID();
|
2015-05-06 17:57:23 +00:00
|
|
|
|
2005-08-18 11:16:33 +00:00
|
|
|
// Check the IDs to verify if the pages are different.
|
|
|
|
if (prevID != nextID) {
|
2016-10-20 09:33:22 +00:00
|
|
|
aDifferenceFound = true;
|
|
|
|
|
|
|
|
// Set the Subframe flag if not navigating the root docshell.
|
|
|
|
aNextEntry->SetIsSubFrame(aParent != mRootDocShell);
|
|
|
|
return InitiateLoad(aNextEntry, aParent, aLoadType);
|
2005-08-18 11:16:33 +00:00
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2016-10-20 09:33:22 +00:00
|
|
|
// The entries are the same, so compare any child frames
|
2018-09-07 01:56:23 +00:00
|
|
|
int32_t pcnt = aPrevEntry->GetChildCount();
|
|
|
|
int32_t ncnt = aNextEntry->GetChildCount();
|
2015-05-06 17:57:23 +00:00
|
|
|
int32_t dsCount = 0;
|
2014-01-06 22:34:15 +00:00
|
|
|
aParent->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;
|
2012-08-22 15:56:38 +00:00
|
|
|
for (int32_t i = 0; i < dsCount; ++i) {
|
2010-08-17 14:13:55 +00:00
|
|
|
nsCOMPtr<nsIDocShellTreeItem> treeItem;
|
2014-01-06 22:34:15 +00:00
|
|
|
aParent->GetChildAt(i, getter_AddRefs(treeItem));
|
2010-08-17 14:13:55 +00:00
|
|
|
nsCOMPtr<nsIDocShell> shell = do_QueryInterface(treeItem);
|
|
|
|
if (shell) {
|
2016-06-20 22:38:10 +00:00
|
|
|
docshells.AppendElement(shell.forget());
|
2010-08-17 14:13:55 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
|
2010-08-17 14:13:55 +00:00
|
|
|
// Search for something to load next.
|
2012-08-22 15:56:38 +00:00
|
|
|
for (int32_t i = 0; i < ncnt; ++i) {
|
2010-08-17 14:13:55 +00:00
|
|
|
// First get an entry which may cause a new page to be loaded.
|
|
|
|
nsCOMPtr<nsISHEntry> nChild;
|
2018-08-22 09:20:56 +00:00
|
|
|
aNextEntry->GetChildAt(i, getter_AddRefs(nChild));
|
2010-08-17 14:13:55 +00:00
|
|
|
if (!nChild) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-11-16 21:42:35 +00:00
|
|
|
nsID docshellID = nChild->DocshellID();
|
2010-08-17 14:13:55 +00:00
|
|
|
|
|
|
|
// Then find the associated docshell.
|
2012-07-30 14:20:58 +00:00
|
|
|
nsIDocShell* dsChild = nullptr;
|
2012-08-22 15:56:38 +00:00
|
|
|
int32_t count = docshells.Count();
|
|
|
|
for (int32_t j = 0; j < count; ++j) {
|
2010-08-17 14:13:55 +00:00
|
|
|
nsIDocShell* shell = docshells[j];
|
2016-11-16 21:42:35 +00:00
|
|
|
nsID shellID = shell->HistoryID();
|
2010-08-17 14:13:55 +00:00
|
|
|
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;
|
2012-08-22 15:56:38 +00:00
|
|
|
for (int32_t k = 0; k < pcnt; ++k) {
|
2010-08-17 14:13:55 +00:00
|
|
|
nsCOMPtr<nsISHEntry> child;
|
2018-08-22 09:20:56 +00:00
|
|
|
aPrevEntry->GetChildAt(k, getter_AddRefs(child));
|
2010-08-17 14:13:55 +00:00
|
|
|
if (child) {
|
2016-11-16 21:42:35 +00:00
|
|
|
nsID dID = child->DocshellID();
|
2010-08-17 14:13:55 +00:00
|
|
|
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.
|
2016-10-20 09:33:22 +00:00
|
|
|
LoadDifferingEntries(pChild, nChild, dsChild, aLoadType, aDifferenceFound);
|
2015-05-06 17:57:23 +00:00
|
|
|
}
|
2005-08-18 11:16:33 +00:00
|
|
|
return result;
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|
|
|
|
|
2015-05-06 17:57:23 +00:00
|
|
|
nsresult
|
|
|
|
nsSHistory::InitiateLoad(nsISHEntry* aFrameEntry, nsIDocShell* aFrameDS,
|
|
|
|
long aLoadType)
|
2005-08-18 11:16:33 +00:00
|
|
|
{
|
2010-11-19 12:01:10 +00:00
|
|
|
NS_ENSURE_STATE(aFrameDS && aFrameEntry);
|
|
|
|
|
2018-10-26 03:50:37 +00:00
|
|
|
RefPtr<nsDocShellLoadState> loadState = new nsDocShellLoadState();
|
2005-08-18 11:16:33 +00:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
2015-05-06 17:57:23 +00:00
|
|
|
aFrameEntry->SetLoadType(aLoadType);
|
2005-08-18 11:16:33 +00:00
|
|
|
|
2018-10-26 03:50:37 +00:00
|
|
|
loadState->SetLoadType(aLoadType);
|
|
|
|
loadState->SetSHEntry(aFrameEntry);
|
2005-08-18 11:16:33 +00:00
|
|
|
|
2018-09-07 01:56:23 +00:00
|
|
|
nsCOMPtr<nsIURI> originalURI = aFrameEntry->GetOriginalURI();
|
2018-10-26 03:50:37 +00:00
|
|
|
loadState->SetOriginalURI(originalURI);
|
2015-09-30 06:54:39 +00:00
|
|
|
|
2018-10-26 03:50:37 +00:00
|
|
|
loadState->SetLoadReplace(aFrameEntry->GetLoadReplace());
|
2005-08-18 11:16:33 +00:00
|
|
|
|
2018-10-26 03:50:37 +00:00
|
|
|
nsCOMPtr<nsIURI> newURI = aFrameEntry->GetURI();
|
|
|
|
loadState->SetURI(newURI);
|
|
|
|
loadState->SetLoadFlags(nsIWebNavigation::LOAD_FLAGS_NONE);
|
|
|
|
loadState->SetFirstParty(false);
|
2018-10-19 07:11:33 +00:00
|
|
|
|
2018-10-26 03:50:37 +00:00
|
|
|
// Time to initiate a document load
|
|
|
|
return aFrameDS->LoadURI(loadState);
|
2005-08-18 11:16:33 +00:00
|
|
|
}
|
|
|
|
|
2018-09-11 06:08:39 +00:00
|
|
|
NS_IMETHODIMP_(void)
|
2015-05-06 17:57:23 +00:00
|
|
|
nsSHistory::SetRootDocShell(nsIDocShell* aDocShell)
|
2005-08-18 11:15:34 +00:00
|
|
|
{
|
|
|
|
mRootDocShell = aDocShell;
|
2017-04-27 10:59:11 +00:00
|
|
|
|
|
|
|
// Init mHistoryTracker on setting mRootDocShell so we can bind its event
|
|
|
|
// target to the tabGroup.
|
|
|
|
if (mRootDocShell) {
|
|
|
|
nsCOMPtr<nsPIDOMWindowOuter> win = mRootDocShell->GetWindow();
|
|
|
|
if (!win) {
|
2018-09-11 06:08:39 +00:00
|
|
|
return;
|
2017-04-27 10:59:11 +00:00
|
|
|
}
|
|
|
|
|
2017-05-22 07:36:06 +00:00
|
|
|
// Seamonkey moves shistory between <xul:browser>s when restoring a tab.
|
|
|
|
// Let's try not to break our friend too badly...
|
|
|
|
if (mHistoryTracker) {
|
|
|
|
NS_WARNING("Change the root docshell of a shistory is unsafe and "
|
|
|
|
"potentially problematic.");
|
|
|
|
mHistoryTracker->AgeAllGenerations();
|
|
|
|
}
|
|
|
|
|
2018-02-08 20:54:00 +00:00
|
|
|
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(win);
|
|
|
|
|
2017-04-27 10:59:11 +00:00
|
|
|
mHistoryTracker = mozilla::MakeUnique<HistoryTracker>(
|
|
|
|
this,
|
|
|
|
mozilla::Preferences::GetUint(CONTENT_VIEWER_TIMEOUT_SECONDS,
|
|
|
|
CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT),
|
2018-02-08 20:54:00 +00:00
|
|
|
global->EventTargetFor(mozilla::TaskCategory::Other));
|
2017-04-27 10:59:11 +00:00
|
|
|
}
|
2005-08-18 11:15:34 +00:00
|
|
|
}
|