Bug 1765615 - Introduce NS_BLOCK_DYNAMIC_BFC state bit. r=layout-reviewers,emilio

After D198523, NS_BLOCK_FLOAT_MGR and NS_BLOCK_MARGIN_ROOT are always
set simultaneously when initiating a frame, so we can merge them into a
single NS_BLOCK_STATIC_BFC flag. The freed bit is used to define a new
NS_BLOCK_DYNAMIC_BFC flag that has the same effect and is now used for
frames with paint/layout containment so that in D197043 they can be
updated later without having to reconstruct the frame tree. Finally
NS_BLOCK_BFC_STATE_BITS is the bitwise union of these BFC flags.

The following changes are made and cause no behavior changes:

- Instead of testing whether NS_BLOCK_FLOAT_MGR or NS_BLOCK_MARGIN_ROOT
  is set, or whether all of the bits from
  NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS are set, we test whether any
  of the NS_BLOCK_BFC_STATE_BITS is set.

- Instead of adding NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS when
  constructing a frame, we add NS_BLOCK_STATIC_BFC. The exception is
  for frame with paint/layout containment, for which we set
  NS_BLOCK_DYNAMIC_BFC instead.

Differential Revision: https://phabricator.services.mozilla.com/D198530
This commit is contained in:
Frédéric Wang 2024-01-16 07:58:47 +00:00
Родитель 7172371e21
Коммит 477553d92b
15 изменённых файлов: 57 добавлений и 51 удалений

Просмотреть файл

@ -320,7 +320,7 @@ static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) {
}
if (!aFrame->IsBlockFrameOrSubclass() ||
aFrame->HasAnyStateBits(NS_BLOCK_FLOAT_MGR | NS_FRAME_OUT_OF_FLOW) ||
aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS | NS_FRAME_OUT_OF_FLOW) ||
aFrame->IsFixedPosContainingBlock()) {
// Need to suppress column-span if we:
// - Are a different block formatting context,
@ -4602,7 +4602,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock(
aDisplay->DisplayInside() == StyleDisplayInside::FlowRoot ||
clipPaginatedOverflow) &&
!aParentFrame->IsInSVGTextSubtree()) {
flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS;
flags = NS_BLOCK_STATIC_BFC;
if (clipPaginatedOverflow) {
flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW;
}
@ -10738,7 +10738,7 @@ nsBlockFrame* nsCSSFrameConstructor::BeginBuildingColumns(
aColumnContent->SetComputedStyleWithoutNotification(blockStyle);
InitAndRestoreFrame(aState, aContent, columnSet, aColumnContent);
aColumnContent->AddStateBits(NS_FRAME_HAS_MULTI_COLUMN_ANCESTOR |
NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
NS_BLOCK_STATIC_BFC);
// Set up the parent-child chain.
SetInitialSingleChild(columnSetWrapper, columnSet);

Просмотреть файл

@ -82,7 +82,7 @@ nsComboboxControlFrame* NS_NewComboboxControlFrame(PresShell* aPresShell,
nsComboboxControlFrame(aStyle, aPresShell->GetPresContext());
if (it) {
it->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
it->AddStateBits(NS_BLOCK_STATIC_BFC);
}
return it;

Просмотреть файл

@ -788,7 +788,7 @@ void nsFieldSetFrame::SetInitialChildList(ChildListID aListID,
if (nsBlockFrame* legend = do_QueryFrame(GetLegend())) {
// A rendered legend always establish a new formatting context.
// https://html.spec.whatwg.org/multipage/rendering.html#rendered-legend
legend->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
legend->AddStateBits(NS_BLOCK_STATIC_BFC);
}
MOZ_ASSERT(
aListID != FrameChildListID::Principal || GetInner() || GetLegend(),
@ -819,7 +819,7 @@ void nsFieldSetFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame,
if (nsBlockFrame* legend = do_QueryFrame(GetLegend())) {
// A rendered legend always establish a new formatting context.
// https://html.spec.whatwg.org/multipage/rendering.html#rendered-legend
legend->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
legend->AddStateBits(NS_BLOCK_STATIC_BFC);
}
}

Просмотреть файл

@ -49,7 +49,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsFileControlFrame)
nsFileControlFrame::nsFileControlFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext)
: nsBlockFrame(aStyle, aPresContext, kClassID) {
AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
AddStateBits(NS_BLOCK_STATIC_BFC);
}
void nsFileControlFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,

Просмотреть файл

@ -18,9 +18,9 @@ nsContainerFrame* NS_NewSelectsAreaFrame(PresShell* aShell,
nsSelectsAreaFrame* it =
new (aShell) nsSelectsAreaFrame(aStyle, aShell->GetPresContext());
// We need NS_BLOCK_FLOAT_MGR to ensure that the options inside the select
// We need NS_BLOCK_STATIC_BFC to ensure that the options inside the select
// aren't expanded by right floats outside the select.
it->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
it->AddStateBits(NS_BLOCK_STATIC_BFC);
return it;
}

Просмотреть файл

@ -41,16 +41,16 @@ class BlockReflowState {
mCanHaveOverflowMarkers(false) {}
// Set in the BlockReflowState constructor when reflowing a "block margin
// root" frame (i.e. a frame with the NS_BLOCK_MARGIN_ROOT flag set, for
// which margins apply by default).
// root" frame (i.e. a frame with any of the NS_BLOCK_BFC_STATE_BITS flag
// set, for which margins apply by default).
//
// The flag is also set when reflowing a frame whose computed BStart border
// padding is non-zero.
bool mIsBStartMarginRoot : 1;
// Set in the BlockReflowState constructor when reflowing a "block margin
// root" frame (i.e. a frame with the NS_BLOCK_MARGIN_ROOT flag set, for
// which margins apply by default).
// root" frame (i.e. a frame with any of the NS_BLOCK_BFC_STATE_BITS flag
// set, for which margins apply by default).
//
// The flag is also set when reflowing a frame whose computed BEnd border
// padding is non-zero.
@ -79,7 +79,7 @@ class BlockReflowState {
// Set when mLineAdjacentToTop is valid.
bool mHasLineAdjacentToTop : 1;
// Set when the block has the equivalent of NS_BLOCK_FLOAT_MGR.
// Set when the block has the equivalent of NS_BLOCK_*_BFC.
bool mBlockNeedsFloatManager : 1;
// Set when nsLineLayout::LineIsEmpty was true at the end of reflowing

Просмотреть файл

@ -23,7 +23,7 @@ nsBlockFrame* NS_NewColumnSetWrapperFrame(PresShell* aPresShell,
// CSS Multi-column level 1 section 2: A multi-column container
// establishes a new block formatting context, as per CSS 2.1 section
// 9.4.1.
frame->AddStateBits(aStateFlags | NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
frame->AddStateBits(aStateFlags | NS_BLOCK_STATIC_BFC);
return frame;
}

Просмотреть файл

@ -92,7 +92,7 @@ static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock) {
static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock) {
nsBlockFrame* blockWithFloatMgr = aBlock;
while (!blockWithFloatMgr->HasAnyStateBits(NS_BLOCK_FLOAT_MGR)) {
while (!blockWithFloatMgr->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
nsBlockFrame* bf = do_QueryFrame(blockWithFloatMgr->GetParent());
if (!bf) {
break;
@ -446,7 +446,7 @@ nsBlockFrame* NS_NewBlockFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
nsBlockFrame* NS_NewBlockFormattingContext(PresShell* aPresShell,
ComputedStyle* aComputedStyle) {
nsBlockFrame* blockFrame = NS_NewBlockFrame(aPresShell, aComputedStyle);
blockFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
blockFrame->AddStateBits(NS_BLOCK_STATIC_BFC);
return blockFrame;
}
@ -1191,7 +1191,7 @@ static LogicalSize CalculateContainingBlockSizeForAbsolutes(
*/
static const nsBlockFrame* GetAsLineClampDescendant(const nsIFrame* aFrame) {
if (const nsBlockFrame* block = do_QueryFrame(aFrame)) {
if (!block->HasAllStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS)) {
if (!block->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
return block;
}
}
@ -1208,7 +1208,7 @@ static bool IsLineClampRoot(const nsBlockFrame* aFrame) {
return false;
}
if (!aFrame->HasAllStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS)) {
if (!aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
return false;
}
@ -3855,7 +3855,7 @@ bool nsBlockFrame::IsSelfEmpty() {
// 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.
if (HasAnyStateBits(NS_BLOCK_MARGIN_ROOT)) {
if (HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
return false;
}
@ -5161,7 +5161,7 @@ void nsBlockFrame::SplitFloat(BlockReflowState& aState, nsIFrame* aFloat,
}
aState.AppendPushedFloatChain(nextInFlow);
if (MOZ_LIKELY(!HasAnyStateBits(NS_BLOCK_FLOAT_MGR)) ||
if (MOZ_LIKELY(!HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) ||
MOZ_UNLIKELY(IsTrueOverflowContainer())) {
aState.mReflowStatus.SetOverflowIncomplete();
} else {
@ -7714,10 +7714,9 @@ void nsBlockFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
// the prev-in-flow to a newly created next-in-flow, except for the
// NS_BLOCK_FLAGS_NON_INHERITED_MASK bits below.
constexpr nsFrameState NS_BLOCK_FLAGS_MASK =
NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS |
NS_BLOCK_CLIP_PAGINATED_OVERFLOW | NS_BLOCK_HAS_FIRST_LETTER_STYLE |
NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER | NS_BLOCK_HAS_FIRST_LETTER_CHILD |
NS_BLOCK_FRAME_HAS_INSIDE_MARKER;
NS_BLOCK_BFC_STATE_BITS | NS_BLOCK_CLIP_PAGINATED_OVERFLOW |
NS_BLOCK_HAS_FIRST_LETTER_STYLE | NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER |
NS_BLOCK_HAS_FIRST_LETTER_CHILD | NS_BLOCK_FRAME_HAS_INSIDE_MARKER;
// This is the subset of NS_BLOCK_FLAGS_MASK that is NOT inherited
// by default. They should only be set on the first-in-flow.
@ -7757,12 +7756,16 @@ void nsBlockFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
GetParent()->GetWritingMode().GetBlockDir() ||
GetWritingMode().IsVerticalSideways() !=
GetParent()->GetWritingMode().IsVerticalSideways())) ||
StyleDisplay()->IsContainPaint() || StyleDisplay()->IsContainLayout() ||
IsColumnSpan()) {
AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
AddStateBits(NS_BLOCK_STATIC_BFC);
}
if (HasAllStateBits(NS_FRAME_FONT_INFLATION_CONTAINER | NS_BLOCK_FLOAT_MGR)) {
if (StyleDisplay()->IsContainPaint() || StyleDisplay()->IsContainLayout()) {
AddStateBits(NS_BLOCK_DYNAMIC_BFC);
}
if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER) &&
HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
}
}
@ -7818,7 +7821,7 @@ void nsBlockFrame::SetMarkerFrameForListItem(nsIFrame* aMarkerFrame) {
if (nsBlockFrame* marker = do_QueryFrame(aMarkerFrame)) {
// An outside ::marker needs to be an independent formatting context
// to avoid being influenced by the float manager etc.
marker->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
marker->AddStateBits(NS_BLOCK_STATIC_BFC);
}
SetProperty(OutsideMarkerProperty(),
new (PresShell()) nsFrameList(aMarkerFrame, aMarkerFrame));
@ -8020,7 +8023,7 @@ void nsBlockFrame::CheckFloats(BlockReflowState& aState) {
void nsBlockFrame::IsMarginRoot(bool* aBStartMarginRoot,
bool* aBEndMarginRoot) {
nsIFrame* parent = GetParent();
if (!HasAnyStateBits(NS_BLOCK_MARGIN_ROOT)) {
if (!HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
if (!parent || parent->IsFloatContainingBlock()) {
*aBStartMarginRoot = false;
*aBEndMarginRoot = false;
@ -8047,14 +8050,14 @@ bool nsBlockFrame::BlockNeedsFloatManager(nsIFrame* aBlock) {
NS_ASSERTION(aBlock->IsBlockFrameOrSubclass(), "aBlock must be a block");
nsIFrame* parent = aBlock->GetParent();
return aBlock->HasAnyStateBits(NS_BLOCK_FLOAT_MGR) ||
return aBlock->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS) ||
(parent && !parent->IsFloatContainingBlock());
}
/* static */
bool nsBlockFrame::BlockCanIntersectFloats(nsIFrame* aFrame) {
return aFrame->IsBlockFrameOrSubclass() && !aFrame->IsReplaced() &&
!aFrame->HasAnyStateBits(NS_BLOCK_FLOAT_MGR);
!aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS);
}
// Note that this width can vary based on the vertical position.

Просмотреть файл

@ -275,7 +275,7 @@ void nsBlockReflowContext::ReflowBlock(const LogicalRect& aSpace,
tI = space.LineLeft(mWritingMode, mContainerSize);
tB = mBCoord;
if (!mFrame->HasAnyStateBits(NS_BLOCK_FLOAT_MGR)) {
if (!mFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
aFrameRI.mBlockDelta =
mOuterReflowInput.mBlockDelta + mBCoord - aLine->BStart();
}

Просмотреть файл

@ -70,7 +70,7 @@ struct nsFlowAreaRect {
/**
* nsFloatManager is responsible for implementing CSS's rules for
* positioning floats. An nsFloatManager object is created during reflow for
* any block with NS_BLOCK_FLOAT_MGR. During reflow, the float manager for
* any block with NS_BLOCK_BFC_STATE_BITS. During reflow, the float manager for
* the nearest such ancestor block is found in ReflowInput::mFloatManager.
*
* According to the line-relative mappings in CSS Writing Modes spec [1],

Просмотреть файл

@ -528,24 +528,28 @@ FRAME_STATE_BIT(Block, 20, NS_BLOCK_NEEDS_BIDI_RESOLUTION)
FRAME_STATE_BIT(Block, 21, NS_BLOCK_HAS_PUSHED_FLOATS)
// This indicates that this is a frame from which child margins can be
// This indicates that the frame establishes a block formatting context i.e.
//
// 1. This indicates that this is a frame from which child margins can be
// calculated. The absence of this flag implies that child margin calculations
// should ignore the frame and look further up the parent chain. Used in
// nsBlockReflowContext::ComputeCollapsedBStartMargin() via
// nsBlockFrame::IsMarginRoot().
//
// This causes the BlockReflowState's constructor to set the
// mIsBStartMarginRoot and mIsBEndMarginRoot flags.
FRAME_STATE_BIT(Block, 22, NS_BLOCK_MARGIN_ROOT)
//
// 2. This indicates that a block frame should create its own float manager.
// This is required by each block frame that can contain floats. The float
// manager is used to reserve space for the floated frames.
FRAME_STATE_BIT(Block, 22, NS_BLOCK_STATIC_BFC)
// This indicates that a block frame should create its own float manager. This
// is required by each block frame that can contain floats. The float manager is
// used to reserve space for the floated frames.
FRAME_STATE_BIT(Block, 23, NS_BLOCK_FLOAT_MGR)
// This is the same as NS_BLOCK_STATIC_BFC but can be updated dynamically after
// the frame construction (e.g. paint/layout containment).
// FIXME(bug 1874823): Try and merge this and NS_BLOCK_STATIC_BFC.
FRAME_STATE_BIT(Block, 23, NS_BLOCK_DYNAMIC_BFC)
// For setting the relevant bits on a block formatting context:
#define NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS \
(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT)
// For testing the relevant bits on a block formatting context:
#define NS_BLOCK_BFC_STATE_BITS (NS_BLOCK_STATIC_BFC | NS_BLOCK_DYNAMIC_BFC)
FRAME_STATE_BIT(Block, 24, NS_BLOCK_HAS_LINE_CURSOR)

Просмотреть файл

@ -2473,8 +2473,7 @@ bool nsIFrame::CanBeDynamicReflowRoot() const {
// If we participate in a container's block reflow context, or margins
// can collapse through us, we can't be a dynamic reflow root.
if (IsBlockFrameOrSubclass() &&
!HasAllStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS)) {
if (IsBlockFrameOrSubclass() && !HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
return false;
}

Просмотреть файл

@ -641,7 +641,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1508420
// We use 'display:block' on the candidate (overriding 'display:flow-root')
// so that it won't be a block formatting context. (See usage/definition of
// NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS in our c++ layout code.)
// NS_BLOCK_BFC_STATE_BITS in our c++ layout code.)
let cand = createStyledDiv(gReflowRootCandidateStyles +
"display: block; \
background: purple;");
@ -679,7 +679,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1508420
// We use 'display:block' on the candidate (overriding 'display:flow-root')
// so that it won't be a block formatting context. (See usage/definition of
// NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS in our c++ layout code.)
// NS_BLOCK_BFC_STATE_BITS in our c++ layout code.)
// This allows floats inside the candidate to affect the position of
// inline-level content outside of it.
let cand = createStyledDiv(gReflowRootCandidateStyles +

Просмотреть файл

@ -1444,7 +1444,7 @@ nsContainerFrame* NS_NewMathMLmathBlockFrame(PresShell* aPresShell,
ComputedStyle* aStyle) {
auto newFrame = new (aPresShell)
nsMathMLmathBlockFrame(aStyle, aPresShell->GetPresContext());
newFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS);
newFrame->AddStateBits(NS_BLOCK_STATIC_BFC);
return newFrame;
}

Просмотреть файл

@ -432,8 +432,8 @@ class nsMathMLmathBlockFrame final : public nsBlockFrame {
: nsBlockFrame(aStyle, aPresContext, kClassID) {
// We should always have a float manager. Not that things can really try
// to float out of us anyway, but we need one for line layout.
// Bug 1301881: Do we still need to set NS_BLOCK_FLOAT_MGR?
// AddStateBits(NS_BLOCK_FLOAT_MGR);
// Bug 1301881: Do we still need to set NS_BLOCK_STATIC_BFC?
// AddStateBits(NS_BLOCK_STATIC_BFC);
}
virtual ~nsMathMLmathBlockFrame() = default;
};