Bug 1927255 - More subtly deal with preserveLayers in inactive tabs. r=mconley

PreserveLayers is propagated to child frames, and it'd be nice if it
could be used just the same way it's used for the top level tab, to
avoid discarding the resources.

For the top level, if you call preserveLayers() you also need to have
renderLayers = true.

It'd be better long-term, perhaps, to have renderLayers and
preserveLayers in the parent BC. Happy to work on that refactoring if
you agree.

Testing wise, I don't think this is easily testable...

Differential Revision: https://phabricator.services.mozilla.com/D227000
This commit is contained in:
Emilio Cobos Álvarez 2024-10-30 00:42:23 +00:00
parent f0c2b606ee
commit 6692e2b99f
3 changed files with 27 additions and 16 deletions

View File

@ -2750,6 +2750,9 @@ void BrowsingContext::DidSet(FieldIndex<IDX_ExplicitActive>,
PreOrderWalk([&](BrowsingContext* aContext) {
if (nsCOMPtr<nsIDocShell> ds = aContext->GetDocShell()) {
if (auto* bc = BrowserChild::GetFrom(ds)) {
bc->UpdateVisibility();
}
nsDocShell::Cast(ds)->ActivenessMaybeChanged();
}
});

View File

@ -16857,7 +16857,6 @@ void Document::UpdateIntersections(TimeStamp aNowTime) {
static void UpdateEffectsOnBrowsingContext(BrowsingContext* aBc,
const IntersectionInput& aInput,
bool aIsHidden,
bool aIncludeInactive) {
Element* el = aBc->GetEmbedderElement();
if (!el) {
@ -16870,8 +16869,14 @@ static void UpdateEffectsOnBrowsingContext(BrowsingContext* aBc,
const bool isInactiveTop = aBc->IsTop() && !aBc->IsActive();
nsSubDocumentFrame* subDocFrame = do_QueryFrame(el->GetPrimaryFrame());
rb->UpdateEffects([&] {
if (aIsHidden || isInactiveTop) {
// Fully hidden if in the background.
if (isInactiveTop) {
// We don't use the visible rect of top browsers, so if they're inactive
// don't waste time computing it. Note that for OOP iframes, it might seem
// a bit wasteful to bother computing this in background tabs, but:
// * We need it so that child frames know if they're visible or not, in
// case they're preserving layers for example.
// * If we're hidden, our refresh driver is throttled and we don't run
// this code very often anyways.
return EffectsInfo::FullyHidden();
}
const IntersectionOutput output = DOMIntersectionObserver::Intersect(
@ -16921,17 +16926,16 @@ void Document::UpdateRemoteFrameEffects(bool aIncludeInactive) {
auto margin = DOMIntersectionObserver::LazyLoadingRootMargin();
const IntersectionInput input = DOMIntersectionObserver::ComputeInput(
*this, /* aRoot = */ nullptr, &margin);
const bool hidden = Hidden();
if (auto* wc = GetWindowContext()) {
for (const RefPtr<BrowsingContext>& child : wc->Children()) {
UpdateEffectsOnBrowsingContext(child, input, hidden, aIncludeInactive);
UpdateEffectsOnBrowsingContext(child, input, aIncludeInactive);
}
}
if (XRE_IsParentProcess()) {
if (auto* bc = GetBrowsingContext(); bc && bc->IsTop()) {
bc->Canonical()->CallOnAllTopDescendants(
[&](CanonicalBrowsingContext* aDescendant) {
UpdateEffectsOnBrowsingContext(aDescendant, input, hidden,
UpdateEffectsOnBrowsingContext(aDescendant, input,
aIncludeInactive);
return CallState::Continue;
},

View File

@ -3028,20 +3028,23 @@ void BrowserChild::UpdateVisibility() {
if (mBrowsingContext && mBrowsingContext->IsUnderHiddenEmbedderElement()) {
return false;
}
// For OOP iframes, include viewport visibility. For top-level <browser>
// elements we don't use this, because the front-end relies on using
// `mRenderLayers` when invisible for tab warming purposes.
//
// An alternative, maybe more consistent approach would be to add an opt-in
// into this behavior for top-level tabs managed by the tab-switcher
// instead...
if (!mIsTopLevel && !mEffectsInfo.IsVisible()) {
return false;
}
// If we're explicitly told not to render layers, we're also invisible.
if (!mRenderLayers) {
return false;
}
if (!mIsTopLevel) {
// For OOP iframes, include viewport visibility.
if (!mEffectsInfo.IsVisible()) {
return false;
}
// Also include activeness, unless we're artificially preserving layers.
// An alternative to this would be to propagate mRenderLayers from the
// parent, perhaps, so that it applies to the whole tree...
if (!mIsPreservingLayers && mBrowsingContext &&
!mBrowsingContext->IsActive()) {
return false;
}
}
return true;
}();
@ -3091,6 +3094,7 @@ void BrowserChild::MakeHidden() {
IPCResult BrowserChild::RecvPreserveLayers(bool aPreserve) {
mIsPreservingLayers = aPreserve;
UpdateVisibility();
PresShellActivenessMaybeChanged();
return IPC_OK();