gecko-dev/dom/base/PartialSHistory.cpp
Michael Layzell d77310ec7b Bug 1310771 - Part 2: Emit BrowserWillChangeProcess and BrowserChangedProcess when doing cross-frameloader navigations, r=smaug
With GroupedSHistory, history navigations may now require the browser to
change which frameloader is stored internally from within Core. This
patch adds a mechanism to allow for chrome code to respond to these
changes and both delay the change, or respond once the change is
performed.

Delaying the change is accomplished through the BrowserWillChangeProcess
event, which is fired when it is determined that a process change will
happen for the given browser, but the change has not occured yet. During
this time the nsIFrameLoader::AddProcessChangeBlockingPromise method may
be called on the target browser's frameloader. Any promises passed to
this method will be waited on, and the process change will not occur
until they have all been fulfiled.

Once that has occured, the process change occurs, and the
BrowserChangedProcess event is fired.

This is useful for chrome code which needs to flush state from the
original process before the change, and then which needs to connect
state in the new process with state in the chrome process.

MozReview-Commit-ID: C0Xn6pfruB2
2016-11-18 16:00:43 -05:00

297 lines
7.6 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::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::OnSessionHistoryChange(uint32_t aCount)
{
mCount = aCount;
return OnLengthChange(aCount);
}
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::OnLengthChange(int32_t aCount)
{
if (!mOwnerFrameLoader) {
// Cycle collected?
return NS_ERROR_UNEXPECTED;
}
if (aCount < 0) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIGroupedSHistory> groupedHistory;
mOwnerFrameLoader->GetGroupedSessionHistory(getter_AddRefs(groupedHistory));
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->OnPartialSessionHistoryChange(this);
return NS_OK;
}
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