diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp index 405ad6a0bef0..54bb69fc066d 100644 --- a/docshell/base/BrowsingContext.cpp +++ b/docshell/base/BrowsingContext.cpp @@ -2750,6 +2750,9 @@ void BrowsingContext::DidSet(FieldIndex, PreOrderWalk([&](BrowsingContext* aContext) { if (nsCOMPtr ds = aContext->GetDocShell()) { + if (auto* bc = BrowserChild::GetFrom(ds)) { + bc->UpdateVisibility(); + } nsDocShell::Cast(ds)->ActivenessMaybeChanged(); } }); diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp index f569af64324e..168d0b63f24f 100644 --- a/dom/base/Document.cpp +++ b/dom/base/Document.cpp @@ -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& 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; }, diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index 2d3a47d46e7c..163f4fc4b29b 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -3028,20 +3028,23 @@ void BrowserChild::UpdateVisibility() { if (mBrowsingContext && mBrowsingContext->IsUnderHiddenEmbedderElement()) { return false; } - // For OOP iframes, include viewport visibility. For top-level - // 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();