gecko-dev/dom/base/PartialSHistory.cpp
Michael Layzell 1b315d2194 Bug 1320391 - Part 1: Clean up PartialSHistories which are keeping old SHEntries alive, r=ehsan
MozReview-Commit-ID: FY36NdOUM66

--HG--
extra : rebase_source : 6dea22921c7b0e27868827e78503e8a7133e9127
2016-12-15 13:28:40 +08:00

328 lines
8.3 KiB
C++

/* -*- 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
* 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/. */
#include "PartialSHistory.h"
#include "nsIWebNavigation.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION(PartialSHistory, mOwnerFrameLoader)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PartialSHistory)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PartialSHistory)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PartialSHistory)
NS_INTERFACE_MAP_ENTRY(nsIPartialSHistory)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPartialSHistory)
NS_INTERFACE_MAP_ENTRY(nsISHistoryListener)
NS_INTERFACE_MAP_ENTRY(nsIPartialSHistoryListener)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
PartialSHistory::PartialSHistory(nsIFrameLoader* aOwnerFrameLoader)
: mCount(0),
mGlobalIndexOffset(0),
mOwnerFrameLoader(aOwnerFrameLoader)
{
MOZ_ASSERT(aOwnerFrameLoader);
}
already_AddRefed<nsISHistory>
PartialSHistory::GetSessionHistory()
{
if (!mOwnerFrameLoader) {
// Cycle collected?
return nullptr;
}
nsCOMPtr<nsIDocShell> docShell;
mOwnerFrameLoader->GetDocShell(getter_AddRefs(docShell));
if (!docShell) {
return nullptr;
}
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell));
nsCOMPtr<nsISHistory> shistory;
webNav->GetSessionHistory(getter_AddRefs(shistory));
return shistory.forget();
}
already_AddRefed<TabParent>
PartialSHistory::GetTabParent()
{
if (!mOwnerFrameLoader) {
// Cycle collected?
return nullptr;
}
nsCOMPtr<nsITabParent> tabParent;
mOwnerFrameLoader->GetTabParent(getter_AddRefs(tabParent));
return RefPtr<TabParent>(static_cast<TabParent*>(tabParent.get())).forget();
}
NS_IMETHODIMP
PartialSHistory::GetCount(uint32_t* aResult)
{
if (!aResult) {
return NS_ERROR_INVALID_POINTER;
}
// If we have direct reference to nsISHistory, simply pass through.
nsCOMPtr<nsISHistory> shistory(GetSessionHistory());
if (shistory) {
int32_t count;
nsresult rv = shistory->GetCount(&count);
if (NS_FAILED(rv) || count < 0) {
*aResult = 0;
return NS_ERROR_FAILURE;
}
*aResult = count;
return NS_OK;
}
// Otherwise use the cached value.
*aResult = mCount;
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::GetGlobalIndex(int32_t* aResult)
{
if (!aResult) {
return NS_ERROR_INVALID_POINTER;
}
nsCOMPtr<nsISHistory> shistory = GetSessionHistory();
if (shistory) {
int32_t idx;
nsresult rv = shistory->GetIndex(&idx);
NS_ENSURE_SUCCESS(rv, rv);
*aResult = idx + GetGlobalIndexOffset();
return NS_OK;
}
*aResult = mIndex + GetGlobalIndexOffset();
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::GetGlobalIndexOffset(uint32_t* aResult)
{
if (!aResult) {
return NS_ERROR_INVALID_POINTER;
}
// If we have direct reference to nsISHistory, simply pass through.
nsCOMPtr<nsISHistory> shistory(GetSessionHistory());
if (shistory) {
int32_t offset;
nsresult rv = shistory->GetGlobalIndexOffset(&offset);
if (NS_FAILED(rv) || offset < 0) {
*aResult = 0;
return NS_ERROR_FAILURE;
}
*aResult = offset;
return NS_OK;
}
// Otherwise use the cached value.
*aResult = mGlobalIndexOffset;
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::GetOwnerFrameLoader(nsIFrameLoader** aResult)
{
nsCOMPtr<nsIFrameLoader> loader(mOwnerFrameLoader);
loader.forget(aResult);
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::OnAttachGroupedSessionHistory(uint32_t aOffset)
{
mGlobalIndexOffset = aOffset;
// If we have direct reference to nsISHistory, simply pass through.
nsCOMPtr<nsISHistory> shistory(GetSessionHistory());
if (shistory) {
// nsISHistory uses int32_t
if (aOffset > INT32_MAX) {
return NS_ERROR_FAILURE;
}
return shistory->OnAttachGroupedSessionHistory(aOffset);
}
// Otherwise notify through TabParent.
RefPtr<TabParent> tabParent(GetTabParent());
if (!tabParent) {
// We have neither shistory nor tabParent?
NS_WARNING("Unable to get shitory nor tabParent!");
return NS_ERROR_UNEXPECTED;
}
Unused << tabParent->SendNotifyAttachGroupedSessionHistory(aOffset);
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::HandleSHistoryUpdate(uint32_t aCount, uint32_t aIndex, bool aTruncate)
{
// Update our local cache of mCount and mIndex
mCount = aCount;
mIndex = aIndex;
return SHistoryDidUpdate(aTruncate);
}
nsresult
PartialSHistory::SHistoryDidUpdate(bool aTruncate /* = false */)
{
if (!mOwnerFrameLoader) {
// Cycle collected?
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIGroupedSHistory> groupedHistory;
mOwnerFrameLoader->GetGroupedSessionHistory(getter_AddRefs(groupedHistory));
if (NS_WARN_IF(!groupedHistory)) {
// Maybe we're not the active partial history, but in this case we shouldn't
// receive any update from session history object either.
return NS_ERROR_FAILURE;
}
groupedHistory->HandleSHistoryUpdate(this, aTruncate);
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::OnActive(uint32_t aGlobalLength, uint32_t aTargetLocalIndex)
{
// In-process case.
nsCOMPtr<nsISHistory> shistory(GetSessionHistory());
if (shistory) {
// nsISHistory uses int32_t
if (aGlobalLength > INT32_MAX || aTargetLocalIndex > INT32_MAX) {
return NS_ERROR_FAILURE;
}
return shistory->OnPartialSessionHistoryActive(aGlobalLength,
aTargetLocalIndex);
}
// Cross-process case.
RefPtr<TabParent> tabParent(GetTabParent());
if (!tabParent) {
// We have neither shistory nor tabParent?
NS_WARNING("Unable to get shitory nor tabParent!");
return NS_ERROR_UNEXPECTED;
}
Unused << tabParent->SendNotifyPartialSessionHistoryActive(aGlobalLength,
aTargetLocalIndex);
return NS_OK;
}
NS_IMETHODIMP
PartialSHistory::OnDeactive()
{
// In-process case.
nsCOMPtr<nsISHistory> shistory(GetSessionHistory());
if (shistory) {
if (NS_FAILED(shistory->OnPartialSessionHistoryDeactive())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
// Cross-process case.
RefPtr<TabParent> tabParent(GetTabParent());
if (!tabParent) {
// We have neither shistory nor tabParent?
NS_WARNING("Unable to get shitory nor tabParent!");
return NS_ERROR_UNEXPECTED;
}
Unused << tabParent->SendNotifyPartialSessionHistoryDeactive();
return NS_OK;
}
/*******************************************************************************
* nsIPartialSHistoryListener
******************************************************************************/
NS_IMETHODIMP
PartialSHistory::OnRequestCrossBrowserNavigation(uint32_t aIndex)
{
if (!mOwnerFrameLoader) {
// Cycle collected?
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsISupports> promise;
return mOwnerFrameLoader->RequestGroupedHistoryNavigation(aIndex, getter_AddRefs(promise));
}
/*******************************************************************************
* nsISHistoryListener
******************************************************************************/
NS_IMETHODIMP
PartialSHistory::OnLengthChanged(int32_t aCount)
{
return SHistoryDidUpdate(/* aTruncate = */ true);
}
NS_IMETHODIMP
PartialSHistory::OnIndexChanged(int32_t aIndex)
{
return SHistoryDidUpdate(/* aTruncate = */ false);
}
NS_IMETHODIMP
PartialSHistory::OnHistoryNewEntry(nsIURI *aNewURI, int32_t aOldIndex)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PartialSHistory::OnHistoryGoBack(nsIURI *aBackURI, bool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PartialSHistory::OnHistoryGoForward(nsIURI *aForwardURI, bool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PartialSHistory::OnHistoryReload(nsIURI *aReloadURI, uint32_t aReloadFlags, bool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PartialSHistory::OnHistoryGotoIndex(int32_t aIndex, nsIURI *aGotoURI, bool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PartialSHistory::OnHistoryPurge(int32_t aNumEntries, bool *_retval)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
PartialSHistory::OnHistoryReplaceEntry(int32_t aIndex)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
} // namespace dom
} // namespace mozilla