Bug 1765615 - Handle most changes to CSS contain and content-visibility without needing to reconstruct frames. r=layout-reviewers,emilio

Right now, we reconstruct frames in response to a change in the CSS
`contain` property or `content-visibility`. This patch tries to optimize
this a bit:

1. Updates involving style containment change continue to force a
  reconstruction, due to the need to handle counters/quotes.

2. Updates involving paint/layout containment change only force a
   reconstruction if it's needed to handle absolutely/fixed
   positioned descendants or floats (for this one, see also bug 1874826).

3. Other containment changes will only force a reflow and repaint.

Per the CSS contain spec, layout, style and paint containments are
enabled for `content-visibility: hidden` and `content-visibility: auto`.
As a consequence, changing `content-visibility` between `hidden` and
`auto` values no longer requires reconstruction. Changing between these
values and `visible` may need a reconstruction although authors may
generally avoid that in practice by forcing `style` containment.

Differential Revision: https://phabricator.services.mozilla.com/D197043
This commit is contained in:
Frédéric Wang
2024-01-17 08:22:48 +00:00
parent 8cfb94f353
commit b5056e1feb
12 changed files with 485 additions and 112 deletions

View File

@@ -2192,8 +2192,6 @@ void PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) {
mPendingScrollAnchorAdjustment.Remove(scrollableFrame);
mPendingScrollResnap.Remove(scrollableFrame);
}
mContentVisibilityAutoFrames.Remove(aFrame);
}
}
@@ -11996,15 +11994,12 @@ void PresShell::UpdateRelevancyOfContentVisibilityAutoFrames() {
return;
}
bool isRelevantContentChanged = false;
for (nsIFrame* frame : mContentVisibilityAutoFrames) {
isRelevantContentChanged |=
frame->UpdateIsRelevantContent(mContentVisibilityRelevancyToUpdate);
frame->UpdateIsRelevantContent(mContentVisibilityRelevancyToUpdate);
}
if (isRelevantContentChanged) {
if (nsPresContext* presContext = GetPresContext()) {
presContext->UpdateHiddenByContentVisibilityForAnimations();
}
if (nsPresContext* presContext = GetPresContext()) {
presContext->UpdateHiddenByContentVisibilityForAnimationsIfNeeded();
}
mContentVisibilityRelevancyToUpdate.clear();
@@ -12038,7 +12033,6 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() {
auto input = DOMIntersectionObserver::ComputeInput(
*mDocument, /* aRoot = */ nullptr, &rootMargin);
bool isRelevantContentChanged = false;
for (nsIFrame* frame : mContentVisibilityAutoFrames) {
auto* element = frame->GetContent()->AsElement();
result.mAnyScrollIntoViewFlag |=
@@ -12059,8 +12053,7 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() {
.Intersects();
element->SetVisibleForContentVisibility(intersects);
if (oldVisibility.isNothing() || *oldVisibility != intersects) {
isRelevantContentChanged |=
frame->UpdateIsRelevantContent(ContentRelevancyReason::Visible);
frame->UpdateIsRelevantContent(ContentRelevancyReason::Visible);
}
// 14.2.3.3
@@ -12068,10 +12061,8 @@ PresShell::ProximityToViewportResult PresShell::DetermineProximityToViewport() {
result.mHadInitialDetermination = true;
}
}
if (isRelevantContentChanged) {
if (nsPresContext* presContext = GetPresContext()) {
presContext->UpdateHiddenByContentVisibilityForAnimations();
}
if (nsPresContext* presContext = GetPresContext()) {
presContext->UpdateHiddenByContentVisibilityForAnimationsIfNeeded();
}
return result;