Bug 1789255: Anonymous children of elements with content-visibility should not be skipped for layout r=emilio

Some anonymous children are important for properly sizing their parents
even when those parents hide content with `content-visibility`. This is
shown by regressions in the proper layout of some form elements with
`content-visibility`.

This change introduces a more conservative approach for avoiding layout
of hidden content. Instead of leaving all children dirty during reflow,
reflow anonymous frames (and nsComboboxDisplayFrame, a specialized kind
of anonymous frame). This change means that frames may only lay out some
of their children, so it must introduce some more changes to assumptions
during line layout.

In addition, this change renames `content-visibility` related methods in
nsIFrame in order to make it more obvious what they do.

Differential Revision: https://phabricator.services.mozilla.com/D157306
This commit is contained in:
Martin Robinson
2022-09-15 20:32:27 +00:00
parent 4bf3708fbb
commit d6b19e86ff
19 changed files with 115 additions and 60 deletions

View File

@@ -1314,7 +1314,7 @@ void nsBlockFrame::ClearLineClampEllipsis() { ::ClearLineClampEllipsis(this); }
void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
if (GetInFlowParent() && GetInFlowParent()->IsContentHiddenForLayout()) {
if (IsHiddenByContentVisibilityOfInFlowParentForLayout()) {
FinishAndStoreOverflow(&aMetrics, aReflowInput.mStyleDisplay);
return;
}
@@ -2579,10 +2579,6 @@ static bool LinesAreEmpty(const nsLineList& aList) {
}
void nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
if (IsContentHiddenForLayout()) {
return;
}
bool keepGoing = true;
bool repositionViews = false; // should we really need this?
bool foundAnyClears = aState.mFloatBreakType != StyleClear::None;
@@ -3369,6 +3365,15 @@ void nsBlockFrame::ReflowLine(BlockReflowState& aState, LineIterator aLine,
aLine->InvalidateCachedIsEmpty();
aLine->ClearHadFloatPushed();
// If this line contains a single block that is hidden by `content-visibility`
// don't reflow the line. If this line contains inlines and the first one is
// hidden by `content-visibility`, all of them are, so avoid reflow in that
// case as well.
nsIFrame* firstChild = aLine->mFirstChild;
if (firstChild->IsHiddenByContentVisibilityOfInFlowParentForLayout()) {
return;
}
// Now that we know what kind of line we have, reflow it
if (aLine->IsBlock()) {
ReflowBlockFrame(aState, aLine, aKeepReflowGoing);
@@ -3577,6 +3582,10 @@ static inline bool IsNonAutoNonZeroBSize(const StyleSize& aCoord) {
/* virtual */
bool nsBlockFrame::IsSelfEmpty() {
if (IsHiddenByContentVisibilityOfInFlowParentForLayout()) {
return true;
}
// Blocks which are margin-roots (including inline-blocks) cannot be treated
// as empty for margin-collapsing and other purposes. They're more like
// replaced elements.