commit 37912600c566f976bfe8ee98ae362e241e5eaf0e
parent c8c8d52d0be3bef9fd739aae1748894c93b729db
Author: Ting-Yu Lin <tlin@mozilla.com>
Date: Fri, 19 Dec 2025 19:35:20 +0000
Bug 2007058 Part 1 - Generalize NS_FRAME_IS_PUSHED_FLOAT bit to NS_FRAME_IS_PUSHED_OUT_OF_FLOW. r=layout-reviewers,emilio
We need a similar concept to mark an abspos frame that is pushed to a later
absolute-containing-block continuation. A frame is either a float or an abspos
and thus lives in a different frame child list, so the same bit can be used in
both scenarios without conflicts.
Differential Revision: https://phabricator.services.mozilla.com/D277137
Diffstat:
8 files changed, 37 insertions(+), 38 deletions(-)
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
@@ -3934,7 +3934,7 @@ nsIFrame* nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(
}
nsIFrame* nsLayoutUtils::GetDisplayListParent(nsIFrame* aFrame) {
- if (aFrame->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT)) {
+ if (aFrame->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
return aFrame->GetParent();
}
return nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(aFrame);
diff --git a/layout/generic/BlockReflowState.cpp b/layout/generic/BlockReflowState.cpp
@@ -408,7 +408,7 @@ void BlockReflowState::ReconstructMarginBefore(nsLineList::iterator aLine) {
void BlockReflowState::AppendPushedFloatChain(nsIFrame* aFloatCont) {
nsFrameList* pushedFloats = mBlock->EnsurePushedFloats();
while (true) {
- aFloatCont->AddStateBits(NS_FRAME_IS_PUSHED_FLOAT);
+ aFloatCont->AddStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW);
pushedFloats->AppendFrame(mBlock, aFloatCont);
aFloatCont = aFloatCont->GetNextInFlow();
if (!aFloatCont || aFloatCont->GetParent() != mBlock) {
@@ -511,12 +511,12 @@ bool BlockReflowState::AddFloat(nsLineLayout* aLineLayout, nsIFrame* aFloat,
MOZ_ASSERT(aFloat->GetParent(), "float must have parent");
MOZ_ASSERT(aFloat->GetParent()->IsBlockFrameOrSubclass(),
"float's parent must be block");
- if (aFloat->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT) ||
+ if (aFloat->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW) ||
aFloat->GetParent() != mBlock) {
- MOZ_ASSERT(aFloat->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT |
+ MOZ_ASSERT(aFloat->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW |
NS_FRAME_FIRST_REFLOW),
"float should be in this block unless it was marked as "
- "pushed float, or just inserted");
+ "pushed out-of-flow, or just inserted");
MOZ_ASSERT(aFloat->GetParent()->FirstContinuation() ==
mBlock->FirstContinuation());
// If, in a previous reflow, the float was pushed entirely to
@@ -530,7 +530,7 @@ bool BlockReflowState::AddFloat(nsLineLayout* aLineLayout, nsIFrame* aFloat,
auto* floatParent = static_cast<nsBlockFrame*>(aFloat->GetParent());
floatParent->StealFrame(aFloat);
- aFloat->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
+ aFloat->RemoveStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW);
// Appending is fine, since if a float was pushed to the next
// page/column, all later floats were also pushed.
diff --git a/layout/generic/BlockReflowState.h b/layout/generic/BlockReflowState.h
@@ -329,7 +329,7 @@ class BlockReflowState {
* pushed floats list. aFloatCont should not be on any child list when making
* this call. Its next-in-flows will be removed from mBlock using StealFrame()
* before being added to mBlock's pushed floats list. All appended frames will
- * be marked NS_FRAME_IS_PUSHED_FLOAT.
+ * be marked NS_FRAME_IS_PUSHED_OUT_OF_FLOW.
*/
void AppendPushedFloatChain(nsIFrame* aFloatCont);
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
@@ -2903,7 +2903,7 @@ void nsBlockFrame::ReparentFloats(nsIFrame* aFirstFrame,
aOldParent->CollectFloats(aFirstFrame, list, aReparentSiblings);
if (list.NotEmpty()) {
for (nsIFrame* f : list) {
- MOZ_ASSERT(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT),
+ MOZ_ASSERT(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW),
"CollectFloats should've removed that bit");
ReparentFrame(f, aOldParent, this);
}
@@ -2979,8 +2979,8 @@ bool nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
bool needToRecoverState = false;
// Float continuations were reflowed in ReflowPushedFloats
bool reflowedFloat =
- HasFloats() &&
- GetFloats()->FirstChild()->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT);
+ HasFloats() && GetFloats()->FirstChild()->HasAnyStateBits(
+ NS_FRAME_IS_PUSHED_OUT_OF_FLOW);
bool lastLineMovedUp = false;
// We save up information about BR-clearance here
UsedClear inlineFloatClearType = aState.mTrailingClearFromPIF;
@@ -5306,7 +5306,7 @@ static bool CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine,
}
NS_ASSERTION(!aFloat->GetPrevContinuation(),
"float in a line should never be a continuation");
- NS_ASSERTION(!aFloat->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT),
+ NS_ASSERTION(!aFloat->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW),
"float in a line should never be a pushed float");
nsIFrame* ph = aFloat->FirstInFlow()->GetPlaceholderFrame();
for (nsIFrame* f = ph; f; f = f->GetParent()) {
@@ -5702,7 +5702,7 @@ void nsBlockFrame::PushLines(BlockReflowState& aState,
if (floats.NotEmpty()) {
#ifdef DEBUG
for (nsIFrame* f : floats) {
- MOZ_ASSERT(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT),
+ MOZ_ASSERT(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW),
"CollectFloats should've removed that bit");
}
#endif
@@ -5831,7 +5831,7 @@ bool nsBlockFrame::DrainOverflowLines() {
for (nsIFrame* f : oofs.mList) {
nsIFrame* nif = f->GetNextInFlow();
for (; nif && nif->GetParent() == this; nif = nif->GetNextInFlow()) {
- MOZ_ASSERT(nif->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT));
+ MOZ_ASSERT(nif->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW));
RemoveFloat(nif);
pushedFloats.AppendFrame(nullptr, nif);
}
@@ -5879,7 +5879,7 @@ bool nsBlockFrame::DrainSelfOverflowList() {
if (oofs.mList.NotEmpty()) {
#ifdef DEBUG
for (nsIFrame* f : oofs.mList) {
- MOZ_ASSERT(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT),
+ MOZ_ASSERT(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW),
"CollectFloats should've removed that bit");
}
#endif
@@ -5943,7 +5943,7 @@ void nsBlockFrame::DrainSelfPushedFloats() {
// FIXME: This isn't quite right! What if they're all pushed floats?
nsIFrame* insertionPrevSibling = nullptr; /* beginning of list */
for (nsIFrame* f = floats ? floats->FirstChild() : nullptr;
- f && f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT);
+ f && f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW);
f = f->GetNextSibling()) {
insertionPrevSibling = f;
}
@@ -7444,7 +7444,7 @@ void nsBlockFrame::ReflowPushedFloats(BlockReflowState& aState,
nsFrameList* floats = GetFloats();
nsIFrame* f = floats ? floats->FirstChild() : nullptr;
nsIFrame* prev = nullptr;
- while (f && f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT)) {
+ while (f && f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
MOZ_ASSERT(prev == f->GetPrevSibling());
// When we push a first-continuation float in a non-initial reflow,
// it's possible that we end up with two continuations with the same
@@ -7603,14 +7603,14 @@ bool nsBlockFrame::HasPushedFloatsFromPrevContinuation() const {
if (const nsFrameList* floats = GetFloats()) {
// If we have pushed floats, then they should be at the beginning of our
// float list.
- if (floats->FirstChild()->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT)) {
+ if (floats->FirstChild()->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
return true;
}
#ifdef DEBUG
// Double-check the above assertion that pushed floats should be at the
// beginning of our floats list.
for (nsIFrame* f : *floats) {
- NS_ASSERTION(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT),
+ NS_ASSERTION(!f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW),
"pushed floats must be at the beginning of the float list");
}
#endif
@@ -7761,7 +7761,7 @@ void nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DisplayOverflowContainers(aBuilder, aLists);
DisplayAbsoluteContinuations(aBuilder, aLists);
for (nsIFrame* f : GetChildList(FrameChildListID::Float)) {
- if (f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT)) {
+ if (f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
BuildDisplayListForChild(aBuilder, f, aLists);
}
}
@@ -8308,9 +8308,9 @@ void nsBlockFrame::DoCollectFloats(nsIFrame* aFrame, nsFrameList& aList,
: nullptr;
while (outOfFlowFrame && outOfFlowFrame->GetParent() == this) {
RemoveFloat(outOfFlowFrame);
- // Remove the IS_PUSHED_FLOAT bit, in case |outOfFlowFrame| came from
- // the PushedFloats list.
- outOfFlowFrame->RemoveStateBits(NS_FRAME_IS_PUSHED_FLOAT);
+ // Remove the NS_FRAME_IS_PUSHED_OUT_OF_FLOW bit, in case
+ // |outOfFlowFrame| came from the PushedFloats list.
+ outOfFlowFrame->RemoveStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW);
aList.AppendFrame(nullptr, outOfFlowFrame);
outOfFlowFrame = outOfFlowFrame->GetNextInFlow();
// FIXME: By not pulling floats whose parent is one of our
@@ -8354,7 +8354,7 @@ void nsBlockFrame::CheckFloats(BlockReflowState& aState) {
bool hasHiddenFloats = false;
uint32_t i = 0;
for (nsIFrame* f : GetChildList(FrameChildListID::Float)) {
- if (f->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT)) {
+ if (f->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
continue;
}
// There are chances that the float children won't be added to lines,
diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h
@@ -660,7 +660,7 @@ class nsBlockFrame : public nsContainerFrame {
* Determine if we have any pushed floats from a previous continuation.
*
* @returns true, if any of the floats at the beginning of our floats list
- * have the NS_FRAME_IS_PUSHED_FLOAT bit set; false otherwise.
+ * have the NS_FRAME_IS_PUSHED_OUT_OF_FLOW bit set; false otherwise.
*/
bool HasPushedFloatsFromPrevContinuation() const;
diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h
@@ -174,15 +174,14 @@ FRAME_STATE_BIT(Generic, 19, NS_FRAME_REFLOW_ROOT)
// NOTE: Bits 20-31 and 60-63 of the frame state are reserved for specific
// frame classes.
-// This bit is set on floats whose parent does not contain their
-// placeholder. This can happen for two reasons: (1) the float was
-// split, and this piece is the continuation, or (2) the entire float
-// didn't fit on the page.
-// Note that this bit is also shared by text frames for
-// TEXT_IS_IN_TOKEN_MATHML. That's OK because we only check the
-// NS_FRAME_IS_PUSHED_FLOAT bit on frames which we already know are
-// out-of-flow.
-FRAME_STATE_BIT(Generic, 32, NS_FRAME_IS_PUSHED_FLOAT)
+// This bit is set on out-of-flow frames (e.g. floats or absolutely positioned
+// elements) whose parent does not contain their placeholder. This can happen
+// for two reasons: (1) the frame was split, and this piece is the continuation,
+// or (2) the entire frame didn't fit on the fragmentainer (e.g. page/column).
+// Note that this bit is also shared by text frames for TEXT_IS_IN_TOKEN_MATHML.
+// That's OK because we only check the NS_FRAME_IS_PUSHED_OUT_OF_FLOW bit on
+// frames which we already know are out-of-flow.
+FRAME_STATE_BIT(Generic, 32, NS_FRAME_IS_PUSHED_OUT_OF_FLOW)
// This bit acts as a loop flag for recursive paint server drawing.
FRAME_STATE_BIT(Generic, 33, NS_FRAME_DRAWING_AS_PAINTSERVER)
@@ -493,7 +492,7 @@ FRAME_STATE_BIT(Text, 31, TEXT_HAS_NONCOLLAPSED_CHARACTERS)
// This state bit is set on children of token MathML elements.
// NOTE: TEXT_IS_IN_TOKEN_MATHML has a global state bit value that is shared
-// with NS_FRAME_IS_PUSHED_FLOAT.
+// with NS_FRAME_IS_PUSHED_OUT_OF_FLOW.
FRAME_STATE_BIT(Text, 32, TEXT_IS_IN_TOKEN_MATHML)
// Set when this text frame is mentioned in the userdata for the
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
@@ -4339,12 +4339,12 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
aBuilder->ClearWillChangeBudgetStatus(child);
}
- // If 'child' is a pushed float then it's owned by a block that's not an
- // ancestor of the placeholder, and it will be painted by that block and
+ // If 'child' is a pushed out-of-flow then it's owned by a block that's not
+ // an ancestor of the placeholder, and it will be painted by that block and
// should not be painted through the placeholder. Also recheck
// NS_FRAME_TOO_DEEP_IN_FRAME_TREE and NS_FRAME_IS_NONDISPLAY.
static const nsFrameState skipFlags =
- (NS_FRAME_IS_PUSHED_FLOAT | NS_FRAME_TOO_DEEP_IN_FRAME_TREE |
+ (NS_FRAME_IS_PUSHED_OUT_OF_FLOW | NS_FRAME_TOO_DEEP_IN_FRAME_TREE |
NS_FRAME_IS_NONDISPLAY);
if (child->HasAnyStateBits(skipFlags) || nsLayoutUtils::IsPopup(child)) {
return;
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
@@ -8850,7 +8850,7 @@ PaintTelemetry::AutoRecordPaint::~AutoRecordPaint() {
}
static nsIFrame* GetSelfOrPlaceholderFor(nsIFrame* aFrame) {
- if (aFrame->HasAnyStateBits(NS_FRAME_IS_PUSHED_FLOAT)) {
+ if (aFrame->HasAnyStateBits(NS_FRAME_IS_PUSHED_OUT_OF_FLOW)) {
return aFrame;
}