зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1640019 - Part 2: Use new process switch logic in tabbrowser, r=mattwoodrow,Gijs
Add a series of extra hooks and methods to allow tabbrowser to use the new process switching codepath. This duplicates some of the logic from `updateBrowserRemoteness` into event handlers. Differential Revision: https://phabricator.services.mozilla.com/D78970
This commit is contained in:
Родитель
212943c862
Коммит
0e74912c80
|
@ -2056,8 +2056,14 @@
|
|||
// doesn't keep the window alive.
|
||||
b.permanentKey = new (Cu.getGlobalForObject(Services).Object)();
|
||||
|
||||
// Ensure that SessionStore has flushed any session history state from the
|
||||
// content process before we this browser's remoteness.
|
||||
b.prepareToChangeRemoteness = () =>
|
||||
SessionStore.prepareToChangeRemoteness(b);
|
||||
|
||||
const defaultBrowserAttributes = {
|
||||
contextmenu: "contentAreaContextMenu",
|
||||
maychangeremoteness: "true",
|
||||
message: "true",
|
||||
messagemanagergroup: "browsers",
|
||||
selectmenulist: "ContentSelectDropdown",
|
||||
|
@ -2702,6 +2708,9 @@
|
|||
gFissionBrowser,
|
||||
preferredRemoteType
|
||||
);
|
||||
if (sameProcessAsFrameLoader) {
|
||||
remoteType = sameProcessAsFrameLoader.messageManager.remoteType;
|
||||
}
|
||||
|
||||
// If we open a new tab with the newtab URL in the default
|
||||
// userContext, check if there is a preloaded browser ready.
|
||||
|
@ -5708,6 +5717,138 @@
|
|||
);
|
||||
this.tabContainer.addEventListener("mouseover", tabContextFTLInserter);
|
||||
this.tabContainer.addEventListener("focus", tabContextFTLInserter, true);
|
||||
|
||||
// Fired when Gecko has decided a <browser> element will change
|
||||
// remoteness. This allows persisting some state on this element across
|
||||
// process switches.
|
||||
this.addEventListener("WillChangeBrowserRemoteness", event => {
|
||||
let browser = event.originalTarget;
|
||||
let tab = this.getTabForBrowser(browser);
|
||||
if (!tab) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch the `BeforeTabRemotenessChange` event, allowing other code
|
||||
// to react to this tab's process switch.
|
||||
let evt = document.createEvent("Events");
|
||||
evt.initEvent("BeforeTabRemotenessChange", true, false);
|
||||
tab.dispatchEvent(evt);
|
||||
|
||||
let wasActive = document.activeElement == browser;
|
||||
|
||||
// Unmap the old outerWindowId
|
||||
this._outerWindowIDBrowserMap.delete(browser.outerWindowID);
|
||||
|
||||
// Unhook our progress listener.
|
||||
let filter = this._tabFilters.get(tab);
|
||||
let oldListener = this._tabListeners.get(tab);
|
||||
browser.webProgress.removeProgressListener(filter);
|
||||
filter.removeProgressListener(oldListener);
|
||||
let stateFlags = oldListener.mStateFlags;
|
||||
let requestCount = oldListener.mRequestCount;
|
||||
|
||||
// We'll be creating a new listener, so destroy the old one.
|
||||
oldListener.destroy();
|
||||
|
||||
let oldDroppedLinkHandler = browser.droppedLinkHandler;
|
||||
let oldUserTypedValue = browser.userTypedValue;
|
||||
let hadStartedLoad = browser.didStartLoadSinceLastUserTyping();
|
||||
|
||||
let didChange = didChangeEvent => {
|
||||
browser.userTypedValue = oldUserTypedValue;
|
||||
if (hadStartedLoad) {
|
||||
browser.urlbarChangeTracker.startedLoad();
|
||||
}
|
||||
|
||||
browser.droppedLinkHandler = oldDroppedLinkHandler;
|
||||
|
||||
// Switching a browser's remoteness will create a new frameLoader.
|
||||
// As frameLoaders start out with an active docShell we have to
|
||||
// deactivate it if this is not the selected tab's browser or the
|
||||
// browser window is minimized.
|
||||
browser.docShellIsActive = this.shouldActivateDocShell(browser);
|
||||
|
||||
// Create a new tab progress listener for the new browser we just
|
||||
// injected, since tab progress listeners have logic for handling the
|
||||
// initial about:blank load
|
||||
let listener = new TabProgressListener(
|
||||
tab,
|
||||
browser,
|
||||
false,
|
||||
false,
|
||||
stateFlags,
|
||||
requestCount
|
||||
);
|
||||
this._tabListeners.set(tab, listener);
|
||||
filter.addProgressListener(listener, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
|
||||
// Restore the progress listener.
|
||||
browser.webProgress.addProgressListener(
|
||||
filter,
|
||||
Ci.nsIWebProgress.NOTIFY_ALL
|
||||
);
|
||||
|
||||
// Restore the securityUI state.
|
||||
let securityUI = browser.securityUI;
|
||||
let state = securityUI
|
||||
? securityUI.state
|
||||
: Ci.nsIWebProgressListener.STATE_IS_INSECURE;
|
||||
this._callProgressListeners(
|
||||
browser,
|
||||
"onSecurityChange",
|
||||
[browser.webProgress, null, state],
|
||||
true,
|
||||
false
|
||||
);
|
||||
let cbEvent = browser.getContentBlockingEvents();
|
||||
// Include the true final argument to indicate that this event is
|
||||
// simulated (instead of being observed by the webProgressListener).
|
||||
this._callProgressListeners(
|
||||
browser,
|
||||
"onContentBlockingEvent",
|
||||
[browser.webProgress, null, cbEvent, true],
|
||||
true,
|
||||
false
|
||||
);
|
||||
|
||||
if (browser.isRemoteBrowser) {
|
||||
// Switching the browser to be remote will connect to a new child
|
||||
// process so the browser can no longer be considered to be
|
||||
// crashed.
|
||||
tab.removeAttribute("crashed");
|
||||
} else {
|
||||
browser.sendMessageToActor(
|
||||
"Browser:AppTab",
|
||||
{ isAppTab: tab.pinned },
|
||||
"BrowserTab"
|
||||
);
|
||||
|
||||
// Register the new outerWindowID.
|
||||
this._outerWindowIDBrowserMap.set(browser.outerWindowID, browser);
|
||||
}
|
||||
|
||||
if (wasActive) {
|
||||
browser.focus();
|
||||
}
|
||||
|
||||
if (this.isFindBarInitialized(tab)) {
|
||||
this.getCachedFindBar(tab).browser = browser;
|
||||
}
|
||||
|
||||
browser.sendMessageToActor(
|
||||
"Browser:HasSiblings",
|
||||
this.tabs.length > 1,
|
||||
"BrowserTab"
|
||||
);
|
||||
|
||||
evt = document.createEvent("Events");
|
||||
evt.initEvent("TabRemotenessChange", true, false);
|
||||
tab.dispatchEvent(evt);
|
||||
};
|
||||
browser.addEventListener("DidChangeBrowserRemoteness", didChange, {
|
||||
once: true,
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setSuccessor(aTab, successorTab) {
|
||||
|
@ -5788,6 +5929,11 @@
|
|||
E10SUtils.log().debug(`new tabID: ${remoteTab.tabId}`);
|
||||
return remoteTab.contentProcessId;
|
||||
},
|
||||
|
||||
finishBrowserRemotenessChange(aBrowser, aSwitchId) {
|
||||
let tab = this.getTabForBrowser(aBrowser);
|
||||
SessionStore.finishTabRemotenessChange(tab, aSwitchId);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -511,6 +511,18 @@ var SessionStore = {
|
|||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepares to change the remoteness of the given browser, by ensuring that
|
||||
* the local instance of session history is up-to-date.
|
||||
*/
|
||||
async prepareToChangeRemoteness(aTab) {
|
||||
await SessionStoreInternal.prepareToChangeRemoteness(aTab);
|
||||
},
|
||||
|
||||
finishTabRemotenessChange(aTab, aSwitchId) {
|
||||
SessionStoreInternal.finishTabRemotenessChange(aTab, aSwitchId);
|
||||
},
|
||||
};
|
||||
|
||||
// Freeze the SessionStore object. We don't want anyone to modify it.
|
||||
|
@ -3870,13 +3882,9 @@ var SessionStoreInternal = {
|
|||
let permanentKey = tab.linkedBrowser.permanentKey;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
browser.messageManager.sendAsyncMessage(
|
||||
"SessionStore:prepareForProcessChange"
|
||||
);
|
||||
|
||||
// NOTE: This is currently the only async operation used, but this is likely
|
||||
// to change in the future.
|
||||
await TabStateFlusher.flush(browser);
|
||||
await this.prepareToChangeRemoteness(browser);
|
||||
|
||||
// Now that we have flushed state, our loadArguments, etc. may have been
|
||||
// overwritten by multiple calls to navigateAndRestore. Load the most
|
||||
|
@ -4663,6 +4671,7 @@ var SessionStoreInternal = {
|
|||
let window = tab.ownerGlobal;
|
||||
let tabbrowser = window.gBrowser;
|
||||
let forceOnDemand = options.forceOnDemand;
|
||||
let isRemotenessUpdate = options.isRemotenessUpdate;
|
||||
|
||||
let willRestoreImmediately =
|
||||
options.restoreImmediately || tabbrowser.selectedBrowser == browser;
|
||||
|
@ -4792,7 +4801,12 @@ var SessionStoreInternal = {
|
|||
// restoreTab will get called again when the browser is instantiated.
|
||||
TAB_STATE_FOR_BROWSER.set(browser, TAB_STATE_NEEDS_RESTORE);
|
||||
|
||||
this._sendRestoreHistory(browser, { tabData, epoch, loadArguments });
|
||||
this._sendRestoreHistory(browser, {
|
||||
tabData,
|
||||
epoch,
|
||||
loadArguments,
|
||||
isRemotenessUpdate,
|
||||
});
|
||||
|
||||
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
|
||||
// it ensures each window will have its selected tab loaded.
|
||||
|
@ -4874,44 +4888,48 @@ var SessionStoreInternal = {
|
|||
|
||||
this.markTabAsRestoring(aTab);
|
||||
|
||||
let newFrameloader = aOptions.newFrameloader;
|
||||
let replaceBrowsingContext = aOptions.replaceBrowsingContext;
|
||||
let redirectLoadSwitchId = aOptions.redirectLoadSwitchId;
|
||||
let isRemotenessUpdate;
|
||||
if (aOptions.remoteType !== undefined) {
|
||||
// We already have a selected remote type so we update to that.
|
||||
isRemotenessUpdate = tabbrowser.updateBrowserRemoteness(browser, {
|
||||
remoteType: aOptions.remoteType,
|
||||
newFrameloader,
|
||||
replaceBrowsingContext,
|
||||
redirectLoadSwitchId,
|
||||
});
|
||||
} else {
|
||||
isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL(
|
||||
browser,
|
||||
uri,
|
||||
{
|
||||
// If we aren't already updating the browser's remoteness, check if it's
|
||||
// necessary.
|
||||
let isRemotenessUpdate = aOptions.isRemotenessUpdate;
|
||||
if (!isRemotenessUpdate) {
|
||||
let newFrameloader = aOptions.newFrameloader;
|
||||
let replaceBrowsingContext = aOptions.replaceBrowsingContext;
|
||||
let redirectLoadSwitchId = aOptions.redirectLoadSwitchId;
|
||||
if (aOptions.remoteType !== undefined) {
|
||||
// We already have a selected remote type so we update to that.
|
||||
isRemotenessUpdate = tabbrowser.updateBrowserRemoteness(browser, {
|
||||
remoteType: aOptions.remoteType,
|
||||
newFrameloader,
|
||||
replaceBrowsingContext,
|
||||
redirectLoadSwitchId,
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL(
|
||||
browser,
|
||||
uri,
|
||||
{
|
||||
newFrameloader,
|
||||
replaceBrowsingContext,
|
||||
redirectLoadSwitchId,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (isRemotenessUpdate) {
|
||||
// We updated the remoteness, so we need to send the history down again.
|
||||
//
|
||||
// Start a new epoch to discard all frame script messages relating to a
|
||||
// previous epoch. All async messages that are still on their way to chrome
|
||||
// will be ignored and don't override any tab data set when restoring.
|
||||
let epoch = this.startNextEpoch(browser);
|
||||
if (isRemotenessUpdate) {
|
||||
// We updated the remoteness, so we need to send the history down again.
|
||||
//
|
||||
// Start a new epoch to discard all frame script messages relating to a
|
||||
// previous epoch. All async messages that are still on their way to chrome
|
||||
// will be ignored and don't override any tab data set when restoring.
|
||||
let epoch = this.startNextEpoch(browser);
|
||||
|
||||
this._sendRestoreHistory(browser, {
|
||||
tabData,
|
||||
epoch,
|
||||
loadArguments,
|
||||
isRemotenessUpdate,
|
||||
});
|
||||
this._sendRestoreHistory(browser, {
|
||||
tabData,
|
||||
epoch,
|
||||
loadArguments,
|
||||
isRemotenessUpdate,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent", {
|
||||
|
@ -6015,6 +6033,55 @@ var SessionStoreInternal = {
|
|||
browser.frameLoader.requestEpochUpdate(options.epoch);
|
||||
}
|
||||
},
|
||||
|
||||
// Flush out session history state so that it can be used to restore the state
|
||||
// into a new process in `finishTabRemotenessChange`.
|
||||
//
|
||||
// NOTE: This codepath is temporary while the Fission Session History rewrite
|
||||
// is in process, and will be removed & replaced once that rewrite is
|
||||
// complete. (bug 1645062)
|
||||
async prepareToChangeRemoteness(aBrowser) {
|
||||
aBrowser.messageManager.sendAsyncMessage(
|
||||
"SessionStore:prepareForProcessChange"
|
||||
);
|
||||
await TabStateFlusher.flush(aBrowser);
|
||||
},
|
||||
|
||||
// Handle finishing the remoteness change for a tab by restoring session
|
||||
// history state into it, and resuming the ongoing network load.
|
||||
//
|
||||
// NOTE: This codepath is temporary while the Fission Session History rewrite
|
||||
// is in process, and will be removed & replaced once that rewrite is
|
||||
// complete. (bug 1645062)
|
||||
finishTabRemotenessChange(aTab, aSwitchId) {
|
||||
let window = aTab.ownerGlobal;
|
||||
if (!window || !window.__SSi || window.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tabState = TabState.clone(aTab, TAB_CUSTOM_VALUES.get(aTab));
|
||||
let options = {
|
||||
restoreImmediately: true,
|
||||
restoreContentReason: RESTORE_TAB_CONTENT_REASON.NAVIGATE_AND_RESTORE,
|
||||
isRemotenessUpdate: true,
|
||||
loadArguments: {
|
||||
redirectLoadSwitchId: aSwitchId,
|
||||
// As we're resuming a load which has been redirected from another
|
||||
// process, record the history index which is currently being requested.
|
||||
// It has to be offset by 1 to get back to native history indices from
|
||||
// SessionStore history indicies.
|
||||
redirectHistoryIndex: tabState.requestedIndex - 1,
|
||||
},
|
||||
};
|
||||
|
||||
// Need to reset restoring tabs.
|
||||
if (TAB_STATE_FOR_BROWSER.has(aTab.linkedBrowser)) {
|
||||
this._resetLocalTabRestoringState(aTab);
|
||||
}
|
||||
|
||||
// Restore the state into the tab.
|
||||
this.restoreTab(aTab, tabState, options);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,12 +22,14 @@
|
|||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/net/DocumentLoadListener.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "mozilla/MozPromiseInlines.h"
|
||||
#include "nsGlobalWindowOuter.h"
|
||||
#include "nsIWebBrowserChrome.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsSHistory.h"
|
||||
#include "nsSecureBrowserUI.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsIBrowser.h"
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
|
@ -390,6 +392,26 @@ void CanonicalBrowsingContext::PendingRemotenessChange::ProcessReady(
|
|||
return;
|
||||
}
|
||||
|
||||
// Wait for our blocker promise to resolve, if present.
|
||||
if (mPrepareToChangePromise) {
|
||||
mPrepareToChangePromise->Then(
|
||||
GetMainThreadSerialEventTarget(), __func__,
|
||||
[self = RefPtr{this}, contentParent = RefPtr{aContentParent}](bool) {
|
||||
self->Finish(contentParent);
|
||||
},
|
||||
[self = RefPtr{this}](nsresult aRv) { self->Cancel(aRv); });
|
||||
return;
|
||||
}
|
||||
|
||||
Finish(aContentParent);
|
||||
}
|
||||
|
||||
void CanonicalBrowsingContext::PendingRemotenessChange::Finish(
|
||||
ContentParent* aContentParent) {
|
||||
if (!mPromise) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> target(mTarget);
|
||||
if (target->IsDiscarded()) {
|
||||
Cancel(NS_ERROR_FAILURE);
|
||||
|
@ -403,16 +425,29 @@ void CanonicalBrowsingContext::PendingRemotenessChange::ProcessReady(
|
|||
"We shouldn't be trying to change the remoteness of "
|
||||
"non-remote iframes");
|
||||
|
||||
nsCOMPtr<nsIBrowser> browser = browserElement->AsBrowser();
|
||||
if (!browser) {
|
||||
Cancel(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsFrameLoaderOwner> frameLoaderOwner =
|
||||
do_QueryObject(browserElement);
|
||||
MOZ_RELEASE_ASSERT(frameLoaderOwner,
|
||||
"embedder browser must be nsFrameLoaderOwner");
|
||||
|
||||
// Tell frontend code that this browser element is about to change process.
|
||||
nsresult rv = browser->BeforeChangeRemoteness();
|
||||
if (NS_FAILED(rv)) {
|
||||
Cancel(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
// The process has been created, hand off to nsFrameLoaderOwner to finish
|
||||
// the process switch.
|
||||
ErrorResult error;
|
||||
frameLoaderOwner->ChangeRemotenessToProcess(
|
||||
aContentParent, mPendingSwitchId, mReplaceBrowsingContext, error);
|
||||
frameLoaderOwner->ChangeRemotenessToProcess(aContentParent,
|
||||
mReplaceBrowsingContext, error);
|
||||
if (error.Failed()) {
|
||||
Cancel(error.StealNSResult());
|
||||
return;
|
||||
|
@ -420,15 +455,24 @@ void CanonicalBrowsingContext::PendingRemotenessChange::ProcessReady(
|
|||
|
||||
// We did it! The process switch is complete.
|
||||
RefPtr<nsFrameLoader> frameLoader = frameLoaderOwner->GetFrameLoader();
|
||||
if (RefPtr<BrowserParent> newBrowser = frameLoader->GetBrowserParent()) {
|
||||
mPromise->Resolve(newBrowser, __func__);
|
||||
Clear();
|
||||
RefPtr<BrowserParent> newBrowser = frameLoader->GetBrowserParent();
|
||||
if (!newBrowser) {
|
||||
// Failed to create the BrowserParent somehow! Abort the process switch
|
||||
// attempt.
|
||||
Cancel(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Failed to create the BrowserParent somehow! Abort the process switch
|
||||
// attempt.
|
||||
Cancel(NS_ERROR_UNEXPECTED);
|
||||
// Tell frontend the load is done, and potentially resume the load ourselves
|
||||
// if they don't do it.
|
||||
bool loadResumed = false;
|
||||
rv = browser->FinishChangeRemoteness(mPendingSwitchId, &loadResumed);
|
||||
if (NS_FAILED(rv) || !loadResumed) {
|
||||
newBrowser->ResumeLoad(mPendingSwitchId);
|
||||
}
|
||||
|
||||
mPromise->Resolve(newBrowser, __func__);
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -553,6 +597,7 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Clear() {
|
|||
|
||||
mPromise = nullptr;
|
||||
mTarget = nullptr;
|
||||
mPrepareToChangePromise = nullptr;
|
||||
}
|
||||
|
||||
CanonicalBrowsingContext::PendingRemotenessChange::PendingRemotenessChange(
|
||||
|
@ -639,6 +684,24 @@ CanonicalBrowsingContext::ChangeRemoteness(const nsAString& aRemoteType,
|
|||
this, promise, aPendingSwitchId, aReplaceBrowsingContext);
|
||||
mPendingRemotenessChange = change;
|
||||
|
||||
// Call `prepareToChangeRemoteness` in parallel with starting a new process
|
||||
// for <browser> loads.
|
||||
if (IsTop() && GetEmbedderElement()) {
|
||||
nsCOMPtr<nsIBrowser> browser = GetEmbedderElement()->AsBrowser();
|
||||
if (!browser) {
|
||||
change->Cancel(NS_ERROR_FAILURE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
RefPtr<Promise> blocker;
|
||||
nsresult rv = browser->PrepareToChangeRemoteness(getter_AddRefs(blocker));
|
||||
if (NS_FAILED(rv)) {
|
||||
change->Cancel(rv);
|
||||
return promise.forget();
|
||||
}
|
||||
change->mPrepareToChangePromise = GenericPromise::FromDomPromise(blocker);
|
||||
}
|
||||
|
||||
ContentParent::GetNewOrUsedBrowserProcessAsync(
|
||||
/* aFrameElement = */ nullptr,
|
||||
/* aRemoteType = */ aRemoteType,
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
class nsISHistory;
|
||||
#include "nsISecureBrowserUI.h"
|
||||
|
||||
class nsISHistory;
|
||||
class nsSecureBrowserUI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
class DocumentLoadListener;
|
||||
|
@ -185,14 +185,18 @@ class CanonicalBrowsingContext final : public BrowsingContext {
|
|||
bool aReplaceBrowsingContext);
|
||||
|
||||
void Cancel(nsresult aRv);
|
||||
void ProcessReady(ContentParent* aContentParent);
|
||||
|
||||
private:
|
||||
friend class CanonicalBrowsingContext;
|
||||
|
||||
~PendingRemotenessChange();
|
||||
void ProcessReady(ContentParent* aContentParent);
|
||||
void Finish(ContentParent* aContentParent);
|
||||
void Clear();
|
||||
|
||||
RefPtr<CanonicalBrowsingContext> mTarget;
|
||||
RefPtr<RemotenessPromise::Private> mPromise;
|
||||
RefPtr<GenericPromise> mPrepareToChangePromise;
|
||||
|
||||
uint64_t mPendingSwitchId;
|
||||
bool mReplaceBrowsingContext;
|
||||
|
|
|
@ -231,14 +231,22 @@ void nsFrameLoaderOwner::ChangeRemotenessWithBridge(BrowserBridgeChild* aBridge,
|
|||
}
|
||||
|
||||
void nsFrameLoaderOwner::ChangeRemotenessToProcess(
|
||||
ContentParent* aContentParent, uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext, mozilla::ErrorResult& rv) {
|
||||
ContentParent* aContentParent, bool aReplaceBrowsingContext,
|
||||
mozilla::ErrorResult& rv) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
std::function<void()> frameLoaderInit = [&] {
|
||||
mFrameLoader->ConfigRemoteProcess(aContentParent->GetRemoteType(),
|
||||
aContentParent);
|
||||
mFrameLoader->ResumeLoad(aPendingSwitchId);
|
||||
|
||||
// FIXME(bug 1644779): We'd like to stop triggering a load here, as this
|
||||
// reads the attributes, such as `src`, on the <browser> element, and could
|
||||
// start another load which will be clobbered shortly.
|
||||
//
|
||||
// This is OK for now, as we're mimicing the existing process switching
|
||||
// behaviour, and <browser> elements created by tabbrowser don't have the
|
||||
// `src` attribute specified.
|
||||
mFrameLoader->LoadFrame(false);
|
||||
};
|
||||
|
||||
auto shouldPreserve = ShouldPreserveBrowsingContext(
|
||||
|
|
|
@ -69,7 +69,6 @@ class nsFrameLoaderOwner : public nsISupports {
|
|||
// If `aReplaceBrowsingContext` is set, BrowsingContext preservation will be
|
||||
// disabled for this process switch.
|
||||
void ChangeRemotenessToProcess(mozilla::dom::ContentParent* aContentParent,
|
||||
uint64_t aPendingSwitchId,
|
||||
bool aReplaceBrowsingContext,
|
||||
mozilla::ErrorResult& rv);
|
||||
|
||||
|
|
|
@ -207,4 +207,22 @@ interface nsIBrowser : nsISupports
|
|||
Promise performProcessSwitch(in AString aRemoteType,
|
||||
in uint64_t aPendingSwitchId,
|
||||
in boolean aReplaceBrowsingContext);
|
||||
|
||||
/**
|
||||
* Called to perform any async tasks which must be completed before changing
|
||||
* remoteness. Gecko will wait for the returned promise to resolve before
|
||||
* performing the process switch.
|
||||
*/
|
||||
Promise prepareToChangeRemoteness();
|
||||
|
||||
/** Called immediately before changing remoteness */
|
||||
void beforeChangeRemoteness();
|
||||
|
||||
/**
|
||||
* Called immediately after changing remoteness.
|
||||
*
|
||||
* If this method returns `true`, Gecko will assume frontend handled resuming
|
||||
* the load, and will not attempt to resume the load itself.
|
||||
*/
|
||||
bool finishChangeRemoteness(in uint64_t aPendingSwitchId);
|
||||
};
|
||||
|
|
|
@ -1983,6 +1983,50 @@
|
|||
replaceBrowsingContext
|
||||
);
|
||||
}
|
||||
|
||||
// This method is replaced by frontend code in order to delay performing the
|
||||
// process switch until some async operatin is completed.
|
||||
//
|
||||
// This is used by tabbrowser to flush SessionStore before a process switch.
|
||||
async prepareToChangeRemoteness() {
|
||||
/* no-op unless replaced */
|
||||
}
|
||||
|
||||
// Called by Gecko before the remoteness change happens, allowing for
|
||||
// listeners, etc. to be stashed before the process switch.
|
||||
beforeChangeRemoteness() {
|
||||
// Fire the `WillChangeBrowserRemoteness` event, which may be hooked by
|
||||
// frontend code for custom behaviour.
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("WillChangeBrowserRemoteness", true, false);
|
||||
this.dispatchEvent(event);
|
||||
|
||||
// Destroy ourselves to unregister from observer notifications
|
||||
// FIXME: Can we get away with something less destructive here?
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
finishChangeRemoteness(redirectLoadSwitchId) {
|
||||
// Re-construct ourselves after the destroy in `beforeChangeRemoteness`.
|
||||
this.construct();
|
||||
|
||||
// Fire the `DidChangeBrowserRemoteness` event, which may be hooked by
|
||||
// frontend code for custom behaviour.
|
||||
let event = document.createEvent("Events");
|
||||
event.initEvent("DidChangeBrowserRemoteness", true, false);
|
||||
this.dispatchEvent(event);
|
||||
|
||||
// If we have a tabbrowser, we need to let it handle restoring session
|
||||
// history, and performing the `resumeRedirectedLoad`, in order to get
|
||||
// sesssion state set up correctly.
|
||||
// FIXME: This probably needs to be hookable by GeckoView.
|
||||
let tabbrowser = this.getTabBrowser();
|
||||
if (tabbrowser) {
|
||||
tabbrowser.finishBrowserRemotenessChange(this, redirectLoadSwitchId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
MozXULElement.implementCustomInterface(MozBrowser, [Ci.nsIBrowser]);
|
||||
|
|
Загрузка…
Ссылка в новой задаче