/* -*- 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/. */
void CanonicalBrowsingContext::GetCurrentRemoteType(nsACString& aRemoteType,
ErrorResult& aRv) const { // If we're in the parent process, dump out the void string. if (mProcessId == 0) {
aRemoteType = NOT_REMOTE_TYPE; return;
}
ContentParent* cp = GetContentParent(); if (!cp) {
aRv.Throw(NS_ERROR_UNEXPECTED); return;
}
nsISecureBrowserUI* CanonicalBrowsingContext::GetSecureBrowserUI() { if (!IsTop()) { return nullptr;
} if (!mSecureBrowserUI) {
mSecureBrowserUI = new nsSecureBrowserUI(this);
} return mSecureBrowserUI;
}
namespace { // The DocShellProgressBridge is attached to a root content docshell loaded in // the parent process. Notifications are paired up with the docshell which they // came from, so that they can be fired to the correct // BrowsingContextWebProgress and bubble through this tree separately. // // Notifications are filtered by a nsBrowserStatusFilter before being received // by the DocShellProgressBridge. class DocShellProgressBridge : public nsIWebProgressListener { public:
NS_DECL_ISUPPORTS // NOTE: This relies in the expansion of `NS_FORWARD_SAFE` and all listener // methods accepting an `aWebProgress` argument. If this changes in the // future, this may need to be written manually.
NS_FORWARD_SAFE_NSIWEBPROGRESSLISTENER(GetTargetContext(aWebProgress))
void CanonicalBrowsingContext::MaybeAddAsProgressListener(
nsIWebProgress* aWebProgress) { // Only add as a listener if the created docshell is a toplevel content // docshell. We'll get notifications for all of our subframes through a single // listener. if (!IsTopContent()) { return;
}
if (!mDocShellProgressBridge) {
mDocShellProgressBridge = new DocShellProgressBridge(Id());
mStatusFilter = new nsBrowserStatusFilter();
mStatusFilter->AddProgressListener(mDocShellProgressBridge,
nsIWebProgress::NOTIFY_ALL);
}
// Use the Transaction for the fields which need to be updated whether or not // the new context has been attached before. // SetWithoutSyncing can be used if context hasn't been attached.
Transaction txn;
txn.SetBrowserId(GetBrowserId());
txn.SetIsAppTab(GetIsAppTab());
txn.SetHasSiblings(GetHasSiblings());
txn.SetTopLevelCreatedByWebContent(GetTopLevelCreatedByWebContent());
txn.SetHistoryID(GetHistoryID());
txn.SetExplicitActive(GetExplicitActive());
txn.SetEmbedderColorSchemes(GetEmbedderColorSchemes());
txn.SetHasRestoreData(GetHasRestoreData());
txn.SetShouldDelayMediaFromStart(GetShouldDelayMediaFromStart());
txn.SetForceOffline(GetForceOffline());
txn.SetTopInnerSizeForRFP(GetTopInnerSizeForRFP());
// Propagate some settings on BrowsingContext replacement so they're not lost // on bfcached navigations. These are important for GeckoView (see bug // 1781936).
txn.SetAllowJavascript(GetAllowJavascript());
txn.SetForceEnableTrackingProtection(GetForceEnableTrackingProtection());
txn.SetUserAgentOverride(GetUserAgentOverride());
txn.SetSuspendMediaWhenInactive(GetSuspendMediaWhenInactive());
txn.SetDisplayMode(GetDisplayMode());
txn.SetForceDesktopViewport(GetForceDesktopViewport());
txn.SetIsUnderHiddenEmbedderElement(GetIsUnderHiddenEmbedderElement());
// When using site-specific zoom, we let the frontend manage the zoom level // of BFCache'd contexts. Overriding those zoom levels can cause weirdness // like bug 1846141. We always copy to new contexts to avoid bug 1914149. if (!aNewContext->EverAttached() ||
!StaticPrefs::browser_zoom_siteSpecific()) {
txn.SetFullZoom(GetFullZoom());
txn.SetTextZoom(GetTextZoom());
}
// Propagate the default load flags so that the TRR mode flags are forwarded // to the new browsing context. See bug 1828643.
txn.SetDefaultLoadFlags(GetDefaultLoadFlags());
// As this is a different BrowsingContext, set InitialSandboxFlags to the // current flags in the new context so that they also apply to any initial // about:blank documents created in it.
txn.SetSandboxFlags(GetSandboxFlags());
txn.SetInitialSandboxFlags(GetSandboxFlags());
txn.SetTargetTopLevelLinkClicksToBlankInternal(
TargetTopLevelLinkClicksToBlank()); if (aNewContext->EverAttached()) {
MOZ_ALWAYS_SUCCEEDS(txn.Commit(aNewContext));
} else {
txn.CommitWithoutSyncing(aNewContext);
}
// XXXBFCache name handling is still a bit broken in Fission in general, // at least in case name should be cleared. if (aRemotenessOptions.mTryUseBFCache) {
MOZ_ASSERT(!aNewContext->EverAttached());
aNewContext->mFields.SetWithoutSyncing<IDX_Name>(GetName()); // We don't copy over HasLoadedNonInitialDocument here, we'll actually end // up loading a new initial document at this point, before the real load. // The real load will then end up setting HasLoadedNonInitialDocument to // true.
}
if (mSessionHistory) {
mSessionHistory->SetBrowsingContext(aNewContext); // At this point we will be creating a new ChildSHistory in the child. // That means that the child's epoch will be reset, so it makes sense to // reset the epoch in the parent too.
mSessionHistory->SetEpoch(0, Nothing());
mSessionHistory.swap(aNewContext->mSessionHistory);
RefPtr<ChildSHistory> childSHistory = ForgetChildSHistory();
aNewContext->SetChildSHistory(childSHistory);
}
// Transfer the ownership of the priority active status from the old context // to the new context.
aNewContext->mPriorityActive = mPriorityActive;
mPriorityActive = false;
already_AddRefed<nsIWidget>
CanonicalBrowsingContext::GetParentProcessWidgetContaining() { // If our document is loaded in-process, such as chrome documents, get the // widget directly from our outer window. Otherwise, try to get the widget // from the toplevel content's browser's element.
nsCOMPtr<nsIWidget> widget; if (nsGlobalWindowOuter* window = nsGlobalWindowOuter::Cast(GetDOMWindow())) {
widget = window->GetNearestWidget();
} elseif (Element* topEmbedder = Top()->GetEmbedderElement()) {
widget = nsContentUtils::WidgetForContent(topEmbedder); if (!widget) {
widget = nsContentUtils::WidgetForDocument(topEmbedder->OwnerDoc());
}
}
if (widget) {
widget = widget->GetTopLevelWidget();
}
CanonicalBrowsingContext* CanonicalBrowsingContext::TopCrossChromeBoundary() {
CanonicalBrowsingContext* bc = this; while (auto* parent = bc->GetParentCrossChromeBoundary()) {
bc = parent;
} return bc;
}
Nullable<WindowProxyHolder> CanonicalBrowsingContext::GetTopChromeWindow() {
RefPtr<CanonicalBrowsingContext> bc = TopCrossChromeBoundary(); if (bc->IsChrome()) { return WindowProxyHolder(bc.forget());
} return nullptr;
}
nsISHistory* CanonicalBrowsingContext::GetSessionHistory() { if (!IsTop()) { return Cast(Top())->GetSessionHistory();
}
// Check GetChildSessionHistory() to make sure that this BrowsingContext has // session history enabled. if (!mSessionHistory && GetChildSessionHistory()) {
mSessionHistory = new nsSHistory(this);
}
for (size_t i = 0; i < mLoadingEntries.Length(); ++i) { if (mLoadingEntries[i].mLoadId == aInfo->mLoadId) {
RefPtr<SessionHistoryEntry> loadingEntry = mLoadingEntries[i].mEntry;
loadingEntry->SetInfo(&newInfo);
if (IsTop()) { // Only top level pages care about Get/SetPersist.
nsCOMPtr<nsIURI> uri;
aNewChannel->GetURI(getter_AddRefs(uri));
loadingEntry->SetPersist(
nsDocShell::ShouldAddToSessionHistory(uri, aNewChannel));
} else {
loadingEntry->SetIsSubFrame(aInfo->mInfo.IsSubFrame());
}
loadingEntry->SetDocshellID(GetHistoryID());
loadingEntry->SetIsDynamicallyAdded(CreatedDynamically()); return MakeUnique<LoadingSessionHistoryInfo>(loadingEntry, aInfo);
}
} return nullptr;
}
using PrintPromise = CanonicalBrowsingContext::PrintPromise; #ifdef NS_PRINTING // Clients must call StaticCloneForPrintingCreated or // NoStaticCloneForPrintingWillBeCreated before the underlying promise can // resolve. class PrintListenerAdapter final : public nsIWebProgressListener { public: explicit PrintListenerAdapter(PrintPromise::Private* aPromise)
: mPromise(aPromise) {}
RefPtr<PrintPromise> CanonicalBrowsingContext::Print(
nsIPrintSettings* aPrintSettings) { #ifndef NS_PRINTING return PrintPromise::CreateAndReject(NS_ERROR_NOT_AVAILABLE, __func__); #else // Content analysis is not supported on non-Windows platforms. # ifdefined(XP_WIN) bool needContentAnalysis = false;
nsCOMPtr<nsIContentAnalysis> contentAnalysis =
mozilla::components::nsIContentAnalysis::Service();
Unused << NS_WARN_IF(!contentAnalysis); if (contentAnalysis) {
nsresult rv = contentAnalysis->GetIsActive(&needContentAnalysis);
Unused << NS_WARN_IF(NS_FAILED(rv));
} if (needContentAnalysis) { auto done = MakeRefPtr<PrintPromise::Private>(__func__);
contentanalysis::ContentAnalysis::PrintToPDFToDetermineIfPrintAllowed( this, aPrintSettings)
->Then(
GetCurrentSerialEventTarget(), __func__,
[done, aPrintSettings = RefPtr{aPrintSettings},
self = RefPtr{this}](
contentanalysis::ContentAnalysis::PrintAllowedResult aResponse)
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA mutable { if (aResponse.mAllowed) {
self->PrintWithNoContentAnalysis(
aPrintSettings, false,
aResponse.mCachedStaticDocumentBrowsingContext)
->ChainTo(done.forget(), __func__);
} else { // Since we are not doing the second print in this case, // release the clone that is no longer needed.
self->ReleaseClonedPrint(
aResponse.mCachedStaticDocumentBrowsingContext);
done->Reject(NS_ERROR_CONTENT_BLOCKED, __func__);
}
},
[done, self = RefPtr{this}](
contentanalysis::ContentAnalysis::PrintAllowedError
aErrorResponse) MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA { // Since we are not doing the second print in this case, release // the clone that is no longer needed.
self->ReleaseClonedPrint(
aErrorResponse.mCachedStaticDocumentBrowsingContext);
done->Reject(aErrorResponse.mError, __func__);
}); return done;
} # endif return PrintWithNoContentAnalysis(aPrintSettings, false, nullptr); #endif
}
layout::RemotePrintJobParent* remotePrintJob = new layout::RemotePrintJobParent(printSettings);
printData.remotePrintJob() =
browserParent->Manager()->SendPRemotePrintJobConstructor(remotePrintJob);
remotePrintJob->RegisterListener(listener);
if (!aCachedStaticDocument.IsNullOrDiscarded()) { // There is no cloned static browsing context that // SendPrintClonedPage() will return, so indicate this // so listener can resolve its promise.
listener->NoStaticCloneForPrintingWillBeCreated(); if (NS_WARN_IF(!browserParent->SendPrintClonedPage( this, printData, aCachedStaticDocument))) {
promise->Reject(NS_ERROR_FAILURE, __func__);
}
} else {
RefPtr<PBrowserParent::PrintPromise> printPromise =
browserParent->SendPrint(this, printData, aForceStaticDocument);
printPromise->Then(
GetMainThreadSerialEventTarget(), __func__,
[listener](MaybeDiscardedBrowsingContext cachedStaticDocument) { // promise will get resolved by the listener
listener->StaticCloneForPrintingCreated(
std::move(cachedStaticDocument));
},
[promise](ResponseRejectReason reason) {
NS_WARNING("SendPrint() failed");
promise->Reject(NS_ERROR_FAILURE, __func__);
});
} return promise.forget(); #endif
}
void CanonicalBrowsingContext::CallOnAllTopDescendants( const FunctionRef<CallState(CanonicalBrowsingContext*)>& aCallback, bool aIncludeNestedBrowsers) {
MOZ_ASSERT(IsTop(), "Should only call on top BC");
MOZ_ASSERT(
!aIncludeNestedBrowsers ||
(IsChrome() && !GetParentCrossChromeBoundary()), "If aIncludeNestedBrowsers is set, should only call on top chrome BC");
if (!IsInProcess()) { // We rely on top levels having to be embedded in the parent process, so // we can only have top level descendants if embedded here.. return;
}
AutoTArray<RefPtr<BrowsingContextGroup>, 32> groups;
BrowsingContextGroup::GetAllGroups(groups); for (auto& browsingContextGroup : groups) { for (auto& bc : browsingContextGroup->Toplevels()) { if (bc == this) { // Cannot be a descendent of myself so skip. continue;
}
if (aIncludeNestedBrowsers) { if (this != bc->Canonical()->TopCrossChromeBoundary()) { continue;
}
} else { auto* parent = bc->Canonical()->GetParentCrossChromeBoundary(); if (!parent || this != parent->Top()) { continue;
}
}
if (aCallback(bc->Canonical()) == CallState::Stop) { return;
}
}
}
}
void CanonicalBrowsingContext::SessionHistoryCommit(
uint64_t aLoadId, const nsID& aChangeID, uint32_t aLoadType, bool aPersist, bool aCloneEntryChildren, bool aChannelExpired, uint32_t aCacheKey) {
MOZ_LOG(gSHLog, LogLevel::Verbose,
("CanonicalBrowsingContext::SessionHistoryCommit %p %" PRIu64, this,
aLoadId));
MOZ_ASSERT(aLoadId != UINT64_MAX, "Must not send special about:blank loadinfo to parent."); for (size_t i = 0; i < mLoadingEntries.Length(); ++i) { if (mLoadingEntries[i].mLoadId == aLoadId) {
nsSHistory* shistory = static_cast<nsSHistory*>(GetSessionHistory()); if (!shistory) {
SessionHistoryEntry::RemoveLoadId(aLoadId);
mLoadingEntries.RemoveElementAt(i); return;
}
int32_t indexOfHistoryLoad = -1; if (loadFromSessionHistory) {
nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(newActiveEntry);
indexOfHistoryLoad = shistory->GetIndexOfEntry(root); if (indexOfHistoryLoad < 0) { // Entry has been removed from the session history. return;
}
}
// If there is a name in the new entry, clear the name of all contiguous // entries. This is for https://html.spec.whatwg.org/#history-traversal // Step 4.4.2.
nsAutoString nameOfNewEntry;
newActiveEntry->GetName(nameOfNewEntry); if (!nameOfNewEntry.IsEmpty()) {
nsSHistory::WalkContiguousEntries(
newActiveEntry,
[](nsISHEntry* aEntry) { aEntry->SetName(EmptyString()); });
}
bool addEntry = ShouldUpdateSessionHistory(aLoadType); if (IsTop()) { if (mActiveEntry && !mActiveEntry->GetFrameLoader()) { bool sharesDocument = true;
mActiveEntry->SharesDocumentWith(newActiveEntry, &sharesDocument); if (!sharesDocument) { // If the old page won't be in the bfcache, // clear the dynamic entries.
RemoveDynEntriesFromActiveSessionHistoryEntry();
}
}
if (LOAD_TYPE_HAS_FLAGS(aLoadType,
nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY)) { // Replace the current entry with the new entry.
int32_t index = shistory->GetIndexForReplace();
// If we're trying to replace an inexistant shistory entry then we // should append instead.
addEntry = index < 0; if (!addEntry) {
shistory->ReplaceEntry(index, newActiveEntry);
}
mActiveEntry = newActiveEntry;
} elseif (LOAD_TYPE_HAS_FLAGS(
aLoadType, nsIWebNavigation::LOAD_FLAGS_IS_REFRESH) &&
!ShouldAddEntryForRefresh(newActiveEntry) && mActiveEntry) {
addEntry = false;
mActiveEntry->ReplaceWith(*newActiveEntry);
} else {
mActiveEntry = newActiveEntry;
}
if (loadFromSessionHistory) { // XXX Synchronize browsing context tree and session history tree?
shistory->InternalSetRequestedIndex(indexOfHistoryLoad);
shistory->UpdateIndex();
if (IsTop()) {
mActiveEntry->SetWireframe(Nothing());
}
} elseif (addEntry) {
shistory->AddEntry(mActiveEntry, aPersist);
shistory->InternalSetRequestedIndex(-1);
}
} else { // FIXME The old implementations adds it to the parent's mLSHE if there // is one, need to figure out if that makes sense here (peterv // doesn't think it would). if (loadFromSessionHistory) { if (mActiveEntry) { // mActiveEntry is null if we're loading iframes from session // history while also parent page is loading from session history. // In that case there isn't anything to sync.
mActiveEntry->SyncTreesForSubframeNavigation(newActiveEntry, Top(), this);
}
mActiveEntry = newActiveEntry;
shistory->InternalSetRequestedIndex(indexOfHistoryLoad); // FIXME UpdateIndex() here may update index too early (but even the // old implementation seems to have similar issues).
shistory->UpdateIndex();
} elseif (addEntry) { if (mActiveEntry) { if (LOAD_TYPE_HAS_FLAGS(
aLoadType, nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY) ||
(LOAD_TYPE_HAS_FLAGS(aLoadType,
nsIWebNavigation::LOAD_FLAGS_IS_REFRESH) &&
!ShouldAddEntryForRefresh(newActiveEntry))) { // FIXME We need to make sure that when we create the info we // make a copy of the shared state.
mActiveEntry->ReplaceWith(*newActiveEntry);
} else { // AddChildSHEntryHelper does update the index of the session // history!
shistory->AddChildSHEntryHelper(mActiveEntry, newActiveEntry,
Top(), aCloneEntryChildren);
mActiveEntry = newActiveEntry;
}
} else {
SessionHistoryEntry* parentEntry = GetParent()->mActiveEntry; // XXX What should happen if parent doesn't have mActiveEntry? // Or can that even happen ever? if (parentEntry) {
mActiveEntry = newActiveEntry; // FIXME Using IsInProcess for aUseRemoteSubframes isn't quite // right, but aUseRemoteSubframes should be going away.
parentEntry->AddChild(
mActiveEntry,
CreatedDynamically() ? -1 : GetParent()->IndexOf(this),
IsInProcess());
}
}
shistory->InternalSetRequestedIndex(-1);
}
}
ResetSHEntryHasUserInteractionCache();
HistoryCommitIndexAndLength(aChangeID, caller);
shistory->LogHistory();
return;
} // XXX Should the loading entries before [i] be removed?
} // FIXME Should we throw an error if we don't find an entry for // aSessionHistoryEntryId?
}
shistory->NotifyOnHistoryReload(&aCanReload); if (!aCanReload) { return;
}
if (mActiveEntry) {
aLoadState.emplace(WrapMovingNotNull(RefPtr{CreateLoadInfo(mActiveEntry)}));
aReloadActiveEntry.emplace(true); if (aForceReload) {
shistory->RemoveFrameEntries(mActiveEntry);
}
} elseif (!mLoadingEntries.IsEmpty()) { const LoadingSessionHistoryEntry& loadingEntry =
mLoadingEntries.LastElement();
uint64_t loadId = loadingEntry.mLoadId;
aLoadState.emplace(
WrapMovingNotNull(RefPtr{CreateLoadInfo(loadingEntry.mEntry)}));
aReloadActiveEntry.emplace(false); if (aForceReload) {
SessionHistoryEntry::LoadingEntry* entry =
SessionHistoryEntry::GetByLoadId(loadId); if (entry) {
shistory->RemoveFrameEntries(entry->mEntry);
}
}
}
if (aLoadState) { // Use 0 as the offset, since aLoadState will be be used for reload.
aLoadState.ref()->SetLoadIsFromSessionHistory(0,
aReloadActiveEntry.value());
} // If we don't have an active entry and we don't have a loading entry then // the nsDocShell will create a load state based on its document.
}
void CanonicalBrowsingContext::ReplaceActiveSessionHistoryEntry(
SessionHistoryInfo* aInfo) { if (!mActiveEntry) { return;
}
// aInfo comes from the entry stored in the current document's docshell, whose // interaction state does not get updated. So we instead propagate state from // the previous canonical entry. See bug 1917369. constbool hasUserInteraction = mActiveEntry->GetHasUserInteraction();
mActiveEntry->SetInfo(aInfo);
mActiveEntry->SetHasUserInteraction(hasUserInteraction); // Notify children of the update
nsSHistory* shistory = static_cast<nsSHistory*>(GetSessionHistory()); if (shistory) {
shistory->NotifyOnHistoryReplaceEntry();
shistory->UpdateRootBrowsingContextState();
}
ResetSHEntryHasUserInteractionCache();
if (IsTop()) {
mActiveEntry->SetWireframe(Nothing());
}
// FIXME Need to do the equivalent of EvictDocumentViewersOrReplaceEntry.
}
void CanonicalBrowsingContext::RemoveDynEntriesFromActiveSessionHistoryEntry() {
nsISHistory* shistory = GetSessionHistory(); // In theory shistory can be null here if the method is called right after // CanonicalBrowsingContext::ReplacedBy call.
NS_ENSURE_TRUE_VOID(shistory);
nsCOMPtr<nsISHEntry> root = nsSHistory::GetRootSHEntry(mActiveEntry);
shistory->RemoveDynEntries(shistory->GetIndexOfEntry(root), mActiveEntry);
}
Maybe<int32_t> CanonicalBrowsingContext::HistoryGo(
int32_t aOffset, uint64_t aHistoryEpoch, bool aRequireUserInteraction, bool aUserActivation, Maybe<ContentParentId> aContentId) { if (aRequireUserInteraction && aOffset != -1 && aOffset != 1) {
NS_ERROR( "aRequireUserInteraction may only be used with an offset of -1 or 1"); return Nothing();
}
nsSHistory* shistory = static_cast<nsSHistory*>(GetSessionHistory()); if (!shistory) { return Nothing();
}
while (true) {
index += aOffset; if (!index.isValid()) {
MOZ_LOG(gSHLog, LogLevel::Debug, ("Invalid index")); return Nothing();
}
// Check for user interaction if desired, except for the first and last // history entries. We compare with >= to account for the case where // aOffset >= length. if (!StaticPrefs::browser_navigation_requireUserInteraction() ||
!aRequireUserInteraction || index.value() >= shistory->Length() - 1 ||
index.value() <= 0) { break;
} if (shistory->HasUserInteractionAtIndex(index.value())) { break;
}
}
// Implement aborting additional history navigations from within the same // event spin of the content process.
if (aContentId == id && epoch >= aHistoryEpoch) {
sameEpoch = true;
MOZ_LOG(gSHLog, LogLevel::Debug, ("Same epoch/id"));
} // Don't update the epoch until we know if the target index is valid
// GoToIndex checks that index is >= 0 and < length.
nsTArray<nsSHistory::LoadEntryResult> loadResults;
nsresult rv = shistory->GotoIndex(index.value(), loadResults, sameEpoch,
aOffset == 0, aUserActivation); if (NS_FAILED(rv)) {
MOZ_LOG(gSHLog, LogLevel::Debug,
("Dropping HistoryGo - bad index or same epoch (not in same doc)")); return Nothing();
} if (epoch < aHistoryEpoch || aContentId != id) {
MOZ_LOG(gSHLog, LogLevel::Debug, ("Set epoch"));
shistory->SetEpoch(aHistoryEpoch, aContentId);
}
int32_t requestedIndex = shistory->GetRequestedIndex();
nsSHistory::LoadURIs(loadResults); return Some(requestedIndex);
}
void CanonicalBrowsingContext::SetForceAppWindowActive(bool aForceActive,
ErrorResult& aRv) {
MOZ_DIAGNOSTIC_ASSERT(IsChrome());
MOZ_DIAGNOSTIC_ASSERT(IsTop()); if (!IsChrome() || !IsTop()) { return aRv.ThrowNotAllowedError( "You shouldn't need to force this BrowsingContext to be active, use " ".isActive instead");
} if (mForceAppWindowActive == aForceActive) { return;
}
mForceAppWindowActive = aForceActive;
RecomputeAppWindowVisibility();
}
SetIsActiveInternal(isNowActive, IgnoreErrors()); if (widget) { // Pause if we are not active, resume if we are active.
widget->PauseOrResumeCompositor(!isNowActive);
}
}
// As this function would only be called when user click the play icon on the // tab bar. That's clear user intent to play, so gesture activate the window // context so that the block-autoplay logic allows the media to autoplay.
windowContext->NotifyUserGestureActivation();
AUTOPLAY_LOG("NotifyStartDelayedAutoplayMedia for chrome bc 0x%08" PRIx64,
Id());
StartDelayedAutoplayMediaComponents(); // Notfiy all content browsing contexts which are related with the canonical // browsing content tree to start delayed autoplay media.
void CanonicalBrowsingContext::Stop(uint32_t aStopFlags) { if (IsDiscarded()) { return;
}
// Stop any known network loads if necessary. if (mCurrentLoad && (aStopFlags & nsIWebNavigation::STOP_NETWORK)) {
mCurrentLoad->Cancel(NS_BINDING_ABORTED, "CanonicalBrowsingContext::Stop"_ns);
}
// Ask the docshell to stop to handle loads that haven't // yet reached here, as well as non-network activity. if (auto* docShell = nsDocShell::Cast(GetDocShell())) {
docShell->Stop(aStopFlags);
} elseif (ContentParent* cp = GetContentParent()) {
Unused << cp->SendStopLoad(this, aStopFlags);
}
}
void CanonicalBrowsingContext::PendingRemotenessChange::ProcessLaunched() { if (!mPromise) { return;
}
if (mContentParentKeepAlive) { // If our new content process is still unloading from a previous process // switch, wait for that unload to complete before continuing. auto found = mTarget->FindUnloadingHost(mContentParentKeepAlive->ChildID()); if (found != mTarget->mUnloadingHosts.end()) {
found->mCallbacks.AppendElement(
[self = RefPtr{this}]()
MOZ_CAN_RUN_SCRIPT_BOUNDARY_LAMBDA { self->ProcessReady(); }); return;
}
}
ProcessReady();
}
void CanonicalBrowsingContext::PendingRemotenessChange::ProcessReady() { if (!mPromise) { return;
}
void CanonicalBrowsingContext::PendingRemotenessChange::MaybeFinish() { if (!mPromise) { return;
}
if (!mProcessReady || mWaitingForPrepareToChange) { return;
}
// If this BrowsingContext is embedded within the parent process, perform the // process switch directly.
nsresult rv = mTarget->IsTopContent() ? FinishTopContent() : FinishSubframe(); if (NS_FAILED(rv)) {
NS_WARNING("Error finishing PendingRemotenessChange!");
Cancel(rv);
} else {
Clear();
}
}
// Logic for finishing a toplevel process change embedded within the parent // process. Due to frontend integration the logic differs substantially from // subframe process switches, and is handled separately.
nsresult CanonicalBrowsingContext::PendingRemotenessChange::FinishTopContent() {
MOZ_DIAGNOSTIC_ASSERT(mTarget->IsTop(), "We shouldn't be trying to change the remoteness of " "non-remote iframes");
// Abort if our ContentParent died while process switching. if (mContentParentKeepAlive &&
NS_WARN_IF(mContentParentKeepAlive->IsShuttingDown())) { return NS_ERROR_FAILURE;
}
// While process switching, we need to check if any of our ancestors are // discarded or no longer current, in which case the process switch needs to // be aborted.
RefPtr<CanonicalBrowsingContext> target(mTarget); if (target->IsDiscarded() || !target->AncestorsAreCurrent()) { return NS_ERROR_FAILURE;
}
Element* browserElement = target->GetEmbedderElement(); if (!browserElement) { return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIBrowser> browser = browserElement->AsBrowser(); if (!browser) { return NS_ERROR_FAILURE;
}
RefPtr<nsFrameLoaderOwner> frameLoaderOwner = do_QueryObject(browserElement);
MOZ_RELEASE_ASSERT(frameLoaderOwner, "embedder browser must be nsFrameLoaderOwner");
// If we're process switching a browsing context in private browsing // mode we might decrease the private browsing count to '0', which // would make us fire "last-pb-context-exited" and drop the private // session. To prevent that we artificially increment the number of // private browsing contexts with '1' until the process switch is done. bool usePrivateBrowsing = mTarget->UsePrivateBrowsing(); if (usePrivateBrowsing) {
IncreasePrivateCount();
}
auto restorePrivateCount = MakeScopeExit([usePrivateBrowsing]() { if (usePrivateBrowsing) {
DecreasePrivateCount();
}
});
// Tell frontend code that this browser element is about to change process.
nsresult rv = browser->BeforeChangeRemoteness(); if (NS_FAILED(rv)) { return rv;
}
// Some frontend code checks the value of the `remote` attribute on the // browser to determine if it is remote, so update the value.
browserElement->SetAttr(kNameSpaceID_None, nsGkAtoms::remote,
mContentParentKeepAlive ? u"true"_ns : u"false"_ns, /* notify */ true);
// The process has been created, hand off to nsFrameLoaderOwner to finish
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.