mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-16 23:05:42 +00:00
d77310ec7b
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
297 lines
7.6 KiB
C++
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
|