Bug 1347823 - Part 2: Move HistoryTracker to nsSHistory and bind its event target to the TabGroup. r=smaug

Convert the singleton HistoryTracker implementation to a per-nsSHistory based
implementation so that it can be bound to a TabGroup.

MozReview-Commit-ID: 7cMtArsO5lQ

--HG--
extra : rebase_source : 3711bc7f7afaa40772035e24270d4fde1d17924a
This commit is contained in:
Samael Wang 2017-04-27 18:59:11 +08:00
parent c88a3d7711
commit ada8242de0
7 changed files with 120 additions and 88 deletions

View file

@ -21,6 +21,7 @@ interface nsIDocShellTreeItem;
interface nsIStructuredCloneContainer;
interface nsIBFCacheEntry;
interface nsIPrincipal;
interface nsISHistory;
%{C++
#include "nsRect.h"
@ -326,6 +327,11 @@ interface nsISHEntry : nsISupports
* if true == "manual", false == "auto".
*/
attribute boolean scrollRestorationIsManual;
/**
* Set the session history it belongs to. It's only set on root entries.
*/
[noscript] void setSHistory(in nsISHistory aSHistory);
};
[scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)]

View file

@ -96,6 +96,16 @@ interface nsISHistoryInternal: nsISupports
*/
void evictAllContentViewers();
/**
* Add a BFCache entry to expiration tracker so it gets evicted on expiration.
*/
void addToExpirationTracker(in nsIBFCacheEntry aEntry);
/**
* Remove a BFCache entry from expiration tracker.
*/
void removeFromExpirationTracker(in nsIBFCacheEntry aEntry);
/**
* Remove dynamic entries found at given index.
*

View file

@ -962,3 +962,10 @@ nsSHEntry::SetLastTouched(uint32_t aLastTouched)
mShared->mLastTouched = aLastTouched;
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::SetSHistory(nsISHistory* aSHistory)
{
mShared->mSHistory = do_GetWeakReference(aSHistory);
return NS_OK;
}

View file

@ -30,46 +30,9 @@ uint64_t gSHEntrySharedID = 0;
} // namespace
#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)
typedef nsExpirationTracker<nsSHEntryShared, 3> HistoryTrackerBase;
class HistoryTracker final : public HistoryTrackerBase
{
public:
explicit HistoryTracker(uint32_t aTimeout)
: HistoryTrackerBase(1000 * aTimeout / 2, "HistoryTracker")
{
}
protected:
virtual void NotifyExpired(nsSHEntryShared* aObj)
{
RemoveObject(aObj);
aObj->Expire();
}
};
static HistoryTracker* gHistoryTracker = nullptr;
void
nsSHEntryShared::EnsureHistoryTracker()
{
if (!gHistoryTracker) {
// nsExpirationTracker doesn't allow one to change the timer period,
// so just set it once when the history tracker is used for the first time.
gHistoryTracker = new HistoryTracker(
mozilla::Preferences::GetUint(CONTENT_VIEWER_TIMEOUT_SECONDS,
CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT));
}
}
void
nsSHEntryShared::Shutdown()
{
delete gHistoryTracker;
gHistoryTracker = nullptr;
}
nsSHEntryShared::nsSHEntryShared()
@ -88,20 +51,6 @@ nsSHEntryShared::nsSHEntryShared()
nsSHEntryShared::~nsSHEntryShared()
{
RemoveFromExpirationTracker();
#ifdef DEBUG
if (gHistoryTracker) {
// Check that we're not still on track to expire. We shouldn't be, because
// we just removed ourselves!
nsExpirationTracker<nsSHEntryShared, 3>::Iterator iterator(gHistoryTracker);
nsSHEntryShared* elem;
while ((elem = iterator.Next()) != nullptr) {
NS_ASSERTION(elem != this, "Found dead entry still in the tracker!");
}
}
#endif
if (mContentViewer) {
RemoveFromBFCacheSync();
}
@ -132,8 +81,9 @@ nsSHEntryShared::Duplicate(nsSHEntryShared* aEntry)
void
nsSHEntryShared::RemoveFromExpirationTracker()
{
if (gHistoryTracker && GetExpirationState()->IsTracked()) {
gHistoryTracker->RemoveObject(this);
nsCOMPtr<nsISHistoryInternal> shistory = do_QueryReferent(mSHistory);
if (shistory && GetExpirationState()->IsTracked()) {
shistory->RemoveFromExpirationTracker(this);
}
}
@ -174,34 +124,6 @@ nsSHEntryShared::DropPresentationState()
mEditorData = nullptr;
}
void
nsSHEntryShared::Expire()
{
// This entry has timed out. If we still have a content viewer, we need to
// evict it.
if (!mContentViewer) {
return;
}
nsCOMPtr<nsIDocShell> container;
mContentViewer->GetContainer(getter_AddRefs(container));
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(container);
if (!treeItem) {
return;
}
// We need to find the root DocShell since only that object has an
// SHistory and we need the SHistory to evict content viewers
nsCOMPtr<nsIDocShellTreeItem> root;
treeItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
nsCOMPtr<nsIWebNavigation> webNav = do_QueryInterface(root);
nsCOMPtr<nsISHistory> history;
webNav->GetSessionHistory(getter_AddRefs(history));
nsCOMPtr<nsISHistoryInternal> historyInt = do_QueryInterface(history);
if (!historyInt) {
return;
}
historyInt->EvictExpiredContentViewerForEntry(this);
}
nsresult
nsSHEntryShared::SetContentViewer(nsIContentViewer* aViewer)
{
@ -215,8 +137,13 @@ nsSHEntryShared::SetContentViewer(nsIContentViewer* aViewer)
mContentViewer = aViewer;
if (mContentViewer) {
EnsureHistoryTracker();
gHistoryTracker->AddObject(this);
// mSHistory is only set for root entries, but in general bfcache only
// applies to root entries as well. BFCache for subframe navigation has been
// disabled since 2005 in bug 304860.
nsCOMPtr<nsISHistoryInternal> shistory = do_QueryReferent(mSHistory);
if (shistory) {
shistory->AddToExpirationTracker(this);
}
nsCOMPtr<nsIDOMDocument> domDoc;
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));

View file

@ -15,6 +15,7 @@
#include "nsIMutationObserver.h"
#include "nsRect.h"
#include "nsString.h"
#include "nsWeakPtr.h"
#include "mozilla/Attributes.h"
@ -54,12 +55,9 @@ private:
friend class nsSHEntry;
friend class HistoryTracker;
static already_AddRefed<nsSHEntryShared> Duplicate(nsSHEntryShared* aEntry);
void RemoveFromExpirationTracker();
void Expire();
nsresult SyncPresentationState();
void DropPresentationState();
@ -89,11 +87,14 @@ private:
nsCOMPtr<nsIMutableArray> mRefreshURIList;
nsExpirationState mExpirationState;
nsAutoPtr<nsDocShellEditorData> mEditorData;
nsWeakPtr mSHistory;
bool mIsFrameNavigation;
bool mSaveLayoutState;
bool mSticky;
bool mDynamicallyCreated;
// This flag is about necko cache, not bfcache.
bool mExpired;
};

View file

@ -32,11 +32,16 @@
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/TabGroup.h"
using namespace mozilla;
#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
#define PREF_SHISTORY_MAX_TOTAL_VIEWERS "browser.sessionhistory.max_total_viewers"
#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)
static const char* kObservedPrefs[] = {
PREF_SHISTORY_SIZE,
@ -251,6 +256,7 @@ NS_INTERFACE_MAP_BEGIN(nsSHistory)
NS_INTERFACE_MAP_ENTRY(nsISHistory)
NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
NS_INTERFACE_MAP_ENTRY(nsISHistoryInternal)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
// static
@ -379,6 +385,8 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist)
{
NS_ENSURE_ARG(aSHEntry);
aSHEntry->SetSHistory(this);
// If we have a root docshell, update the docshell id of the root shentry to
// match the id of that docshell
if (mRootDocShell) {
@ -1296,6 +1304,30 @@ nsSHistory::EvictExpiredContentViewerForEntry(nsIBFCacheEntry* aEntry)
return NS_OK;
}
NS_IMETHODIMP
nsSHistory::AddToExpirationTracker(nsIBFCacheEntry* aEntry)
{
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aEntry);
if (!mHistoryTracker || !entry) {
return NS_ERROR_FAILURE;
}
mHistoryTracker->AddObject(entry);
return NS_OK;
}
NS_IMETHODIMP
nsSHistory::RemoveFromExpirationTracker(nsIBFCacheEntry* aEntry)
{
RefPtr<nsSHEntryShared> entry = static_cast<nsSHEntryShared*>(aEntry);
if (!mHistoryTracker || !entry) {
return NS_ERROR_FAILURE;
}
mHistoryTracker->RemoveObject(entry);
return NS_OK;
}
// 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
@ -1896,6 +1928,23 @@ NS_IMETHODIMP
nsSHistory::SetRootDocShell(nsIDocShell* aDocShell)
{
mRootDocShell = aDocShell;
// Init mHistoryTracker on setting mRootDocShell so we can bind its event
// target to the tabGroup.
if (mRootDocShell) {
nsCOMPtr<nsPIDOMWindowOuter> win = mRootDocShell->GetWindow();
if (!win) {
return NS_ERROR_UNEXPECTED;
}
RefPtr<mozilla::dom::TabGroup> tabGroup = win->TabGroup();
mHistoryTracker = mozilla::MakeUnique<HistoryTracker>(
this,
mozilla::Preferences::GetUint(CONTENT_VIEWER_TIMEOUT_SECONDS,
CONTENT_VIEWER_TIMEOUT_SECONDS_DEFAULT),
tabGroup->EventTargetFor(mozilla::TaskCategory::Other));
}
return NS_OK;
}

View file

@ -16,9 +16,10 @@
#include "nsIWebNavigation.h"
#include "nsSHEntryShared.h"
#include "nsTObserverArray.h"
#include "nsWeakPtr.h"
#include "nsWeakReference.h"
#include "mozilla/LinkedList.h"
#include "mozilla/UniquePtr.h"
class nsIDocShell;
class nsSHEnumerator;
@ -29,9 +30,37 @@ class nsISHTransaction;
class nsSHistory final : public mozilla::LinkedListElement<nsSHistory>,
public nsISHistory,
public nsISHistoryInternal,
public nsIWebNavigation
public nsIWebNavigation,
public nsSupportsWeakReference
{
public:
// The timer based history tracker is used to evict bfcache on expiration.
class HistoryTracker final : public nsExpirationTracker<nsSHEntryShared, 3>
{
public:
explicit HistoryTracker(nsSHistory* aSHistory,
uint32_t aTimeout,
nsIEventTarget* aEventTarget)
: nsExpirationTracker(1000 * aTimeout / 2, "HistoryTracker", aEventTarget)
{
MOZ_ASSERT(aSHistory);
mSHistory = aSHistory;
}
protected:
virtual void NotifyExpired(nsSHEntryShared* aObj)
{
RemoveObject(aObj);
mSHistory->EvictExpiredContentViewerForEntry(aObj);
}
private:
// HistoryTracker is owned by nsSHistory; it always outlives HistoryTracker
// so it's safe to use raw pointer here.
nsSHistory* mSHistory;
};
nsSHistory();
NS_DECL_ISUPPORTS
NS_DECL_NSISHISTORY
@ -87,6 +116,9 @@ private:
// otherwise comparison is done to aIndex - 1.
bool RemoveDuplicate(int32_t aIndex, bool aKeepNext);
// Track all bfcache entries and evict on expiration.
mozilla::UniquePtr<HistoryTracker> mHistoryTracker;
nsCOMPtr<nsISHTransaction> mListRoot;
int32_t mIndex;
int32_t mLength;