From ef150776cff5c9578179a6cadd78879db9e6f7cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 7 Mar 2024 16:36:56 +0000 Subject: [PATCH] Bug 1874823 - Remove NS_BLOCK_STATIC_BFC and NS_BLOCK_CLIP_PAGINATED_OVERFLOW. r=fredw Put all the "is this block a BFC" logic in nsBlockFrame.cpp. The CLIP_PAGINATED_OVERFLOW flag is also redundant, it can just be "has non-propagated overflow styles" check in ShouldApplyOverflowClipping(), and frees another bit. Shouldn't change behavior. Differential Revision: https://phabricator.services.mozilla.com/D203590 --- layout/base/nsCSSFrameConstructor.cpp | 90 ++++-------- layout/base/nsCSSFrameConstructor.h | 4 - layout/forms/nsFieldSetFrame.cpp | 10 -- layout/generic/BlockReflowState.h | 8 +- layout/generic/FrameClasses.py | 9 +- layout/generic/nsBlockFrame.cpp | 177 +++++++++++------------- layout/generic/nsBlockReflowContext.cpp | 2 +- layout/generic/nsFloatManager.h | 4 +- layout/generic/nsFrameStateBits.h | 31 ++--- layout/generic/nsHTMLParts.h | 4 - layout/generic/nsIFrame.cpp | 25 +++- layout/generic/nsIFrame.h | 5 + 12 files changed, 154 insertions(+), 215 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 309aa41d2b9b..149f2f24bf9c 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -321,7 +321,7 @@ static bool ShouldSuppressColumnSpanDescendants(nsIFrame* aFrame) { } if (!aFrame->IsBlockFrameOrSubclass() || - aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS | NS_FRAME_OUT_OF_FLOW) || + aFrame->HasAnyStateBits(NS_BLOCK_BFC | NS_FRAME_OUT_OF_FLOW) || aFrame->IsFixedPosContainingBlock()) { // Need to suppress column-span if we: // - Are a different block formatting context, @@ -2287,7 +2287,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructTableCell( aState, content, innerPseudoStyle, cellFrame, PseudoStyleType::scrolledContent, false, scrollFrame); } - cellInnerFrame = NS_NewBlockFormattingContext(mPresShell, innerPseudoStyle); + cellInnerFrame = NS_NewBlockFrame(mPresShell, innerPseudoStyle); } auto* parent = scrollFrame ? scrollFrame : cellFrame; InitAndRestoreFrame(aState, content, parent, cellInnerFrame); @@ -2567,7 +2567,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructDocElementFrame( MOZ_ASSERT(display->mDisplay == StyleDisplay::Block || display->mDisplay == StyleDisplay::FlowRoot, "Unhandled display type for root element"); - contentFrame = NS_NewBlockFormattingContext(mPresShell, computedStyle); + contentFrame = NS_NewBlockFrame(mPresShell, computedStyle); ConstructBlock( state, aDocElement, state.GetGeometricParent(*display, mDocElementContainingBlock), @@ -3147,8 +3147,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructFieldSetFrame( MOZ_ASSERT(fieldsetContentDisplay->mDisplay == StyleDisplay::Block, "bug in StyleAdjuster::adjust_for_fieldset_content?"); - contentFrame = - NS_NewBlockFormattingContext(mPresShell, fieldsetContentStyle); + contentFrame = NS_NewBlockFrame(mPresShell, fieldsetContentStyle); if (fieldsetContentStyle->StyleColumn()->IsColumnContainerStyle()) { contentFrameTop = BeginBuildingColumns( aState, content, parent, contentFrame, fieldsetContentStyle); @@ -3691,11 +3690,6 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal( CHECK_ONLY_ONE_BIT(FCDATA_WRAP_KIDS_IN_BLOCKS, FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS); #undef CHECK_ONLY_ONE_BIT - NS_ASSERTION(!(bits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) || - ((bits & FCDATA_FUNC_IS_FULL_CTOR) && - data->mFunc.mFullConstructor == - &nsCSSFrameConstructor::ConstructNonScrollableBlock), - "Unexpected FCDATA_FORCED_NON_SCROLLABLE_BLOCK flag"); MOZ_ASSERT( !(bits & FCDATA_IS_WRAPPER_ANON_BOX) || (bits & FCDATA_USE_CHILD_ITEMS), "Wrapper anon boxes should always have FCDATA_USE_CHILD_ITEMS"); @@ -3773,7 +3767,7 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal( innerFrame = outerFrame; break; default: { - innerFrame = NS_NewBlockFormattingContext(mPresShell, outerStyle); + innerFrame = NS_NewBlockFrame(mPresShell, outerStyle); if (outerStyle->StyleColumn()->IsColumnContainerStyle()) { outerFrame = BeginBuildingColumns(aState, content, container, innerFrame, outerStyle); @@ -3786,7 +3780,7 @@ void nsCSSFrameConstructor::ConstructFrameFromItemInternal( } } } else { - innerFrame = NS_NewBlockFormattingContext(mPresShell, outerStyle); + innerFrame = NS_NewBlockFrame(mPresShell, outerStyle); InitAndRestoreFrame(aState, content, container, innerFrame); outerFrame = innerFrame; } @@ -4336,14 +4330,14 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay, // XXX Ignore tables for the time being (except caption) const uint32_t kCaptionCtorFlags = FCDATA_IS_TABLE_PART | FCDATA_DESIRED_PARENT_TYPE_TO_BITS(eTypeTable); - bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption; - bool suppressScrollFrame = false; - bool needScrollFrame = + const bool caption = aDisplay.mDisplay == StyleDisplay::TableCaption; + const bool needScrollFrame = aDisplay.IsScrollableOverflow() && !propagatedScrollToViewport; if (needScrollFrame) { - suppressScrollFrame = mPresShell->GetPresContext()->IsPaginated() && - aDisplay.IsBlockOutsideStyle() && - !aElement.IsInNativeAnonymousSubtree(); + const bool suppressScrollFrame = + mPresShell->GetPresContext()->IsPaginated() && + aDisplay.IsBlockOutsideStyle() && + !aElement.IsInNativeAnonymousSubtree(); if (!suppressScrollFrame) { static constexpr FrameConstructionData sScrollableBlockData[2] = { {&nsCSSFrameConstructor::ConstructScrollableBlock}, @@ -4351,27 +4345,14 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay& aDisplay, kCaptionCtorFlags}}; return &sScrollableBlockData[caption]; } - - // If the scrollable frame would have propagated its scrolling to the - // viewport, we still want to construct a regular block rather than a - // scrollframe so that it paginates correctly, but we don't want to set - // the bit on the block that tells it to clip at paint time. - if (mPresShell->GetPresContext()->ElementWouldPropagateScrollStyles( - aElement)) { - suppressScrollFrame = false; - } } // Handle various non-scrollable blocks. - static constexpr FrameConstructionData sNonScrollableBlockData[2][2] = { - {{&nsCSSFrameConstructor::ConstructNonScrollableBlock}, - {&nsCSSFrameConstructor::ConstructNonScrollableBlock, - kCaptionCtorFlags}}, - {{&nsCSSFrameConstructor::ConstructNonScrollableBlock, - FCDATA_FORCED_NON_SCROLLABLE_BLOCK}, - {&nsCSSFrameConstructor::ConstructNonScrollableBlock, - FCDATA_FORCED_NON_SCROLLABLE_BLOCK | kCaptionCtorFlags}}}; - return &sNonScrollableBlockData[suppressScrollFrame][caption]; + static constexpr FrameConstructionData sNonScrollableBlockData[2] = { + {&nsCSSFrameConstructor::ConstructNonScrollableBlock}, + {&nsCSSFrameConstructor::ConstructNonScrollableBlock, + kCaptionCtorFlags}}; + return &sNonScrollableBlockData[caption]; } case StyleDisplayInside::Table: { static constexpr FrameConstructionData data( @@ -4505,8 +4486,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructScrollableBlock( // Create our block frame // pass a temporary stylecontext, the correct one will be set later - nsContainerFrame* scrolledFrame = - NS_NewBlockFormattingContext(mPresShell, computedStyle); + nsContainerFrame* scrolledFrame = NS_NewBlockFrame(mPresShell, computedStyle); // Make sure to AddChild before we call ConstructBlock so that we // end up before our descendants in fixed-pos lists as needed. @@ -4529,26 +4509,7 @@ nsIFrame* nsCSSFrameConstructor::ConstructNonScrollableBlock( nsContainerFrame* aParentFrame, const nsStyleDisplay* aDisplay, nsFrameList& aFrameList) { ComputedStyle* const computedStyle = aItem.mComputedStyle; - - // We want a block formatting context root in paginated contexts for - // every block that would be scrollable in a non-paginated context. - // We mark our blocks with a bit here if this condition is true, so - // we can check it later in nsIFrame::ApplyPaginatedOverflowClipping. - bool clipPaginatedOverflow = - (aItem.mFCData->mBits & FCDATA_FORCED_NON_SCROLLABLE_BLOCK) != 0; - nsFrameState flags = nsFrameState(0); - if ((aDisplay->IsAbsolutelyPositionedStyle() || aDisplay->IsFloatingStyle() || - aDisplay->DisplayInside() == StyleDisplayInside::FlowRoot || - clipPaginatedOverflow) && - !aParentFrame->IsInSVGTextSubtree()) { - flags = NS_BLOCK_STATIC_BFC; - if (clipPaginatedOverflow) { - flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW; - } - } - nsContainerFrame* newFrame = NS_NewBlockFrame(mPresShell, computedStyle); - newFrame->AddStateBits(flags); ConstructBlock(aState, aItem.mContent, aState.GetGeometricParent(*aDisplay, aParentFrame), aParentFrame, computedStyle, &newFrame, aFrameList, @@ -8707,15 +8668,14 @@ void nsCSSFrameConstructor::CreateNeededAnonFlexOrGridItems( mPresShell->StyleSet()->ResolveInheritingAnonymousBoxStyle( PseudoStyleType::anonymousItem, aParentFrame->Style()); - static constexpr FrameConstructionData sBlockFormattingContextFCData( - ToCreationFunc(NS_NewBlockFormattingContext), - FCDATA_SKIP_FRAMESET | FCDATA_USE_CHILD_ITEMS | - FCDATA_IS_WRAPPER_ANON_BOX); + static constexpr FrameConstructionData sBlockFCData( + ToCreationFunc(NS_NewBlockFrame), FCDATA_SKIP_FRAMESET | + FCDATA_USE_CHILD_ITEMS | + FCDATA_IS_WRAPPER_ANON_BOX); - FrameConstructionItem* newItem = new (this) - FrameConstructionItem(&sBlockFormattingContextFCData, - // Use the content of our parent frame - parentContent, wrapperStyle.forget(), true); + // Use the content of our parent frame + auto* newItem = new (this) FrameConstructionItem( + &sBlockFCData, parentContent, wrapperStyle.forget(), true); newItem->mIsAllInline = newItem->mComputedStyle->StyleDisplay()->IsInlineOutsideStyle(); diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h index ee6b3a5e14eb..283d1385ce1b 100644 --- a/layout/base/nsCSSFrameConstructor.h +++ b/layout/base/nsCSSFrameConstructor.h @@ -723,10 +723,6 @@ class nsCSSFrameConstructor final : public nsFrameManager { This can be used with or without FCDATA_FUNC_IS_FULL_CTOR. The child items might still need table pseudo processing. */ #define FCDATA_USE_CHILD_ITEMS 0x10000 - /* If FCDATA_FORCED_NON_SCROLLABLE_BLOCK is set, then this block - would have been scrollable but has been forced to be - non-scrollable due to being in a paginated context. */ -#define FCDATA_FORCED_NON_SCROLLABLE_BLOCK 0x20000 /* If FCDATA_CREATE_BLOCK_WRAPPER_FOR_ALL_KIDS is set, then create a block formatting context wrapper around the kids of this frame using the FrameConstructionData's mPseudoAtom for its anonymous diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index 03781da8bd9a..c96b293e8253 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -785,11 +785,6 @@ void nsFieldSetFrame::Reflow(nsPresContext* aPresContext, void nsFieldSetFrame::SetInitialChildList(ChildListID aListID, nsFrameList&& aChildList) { nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList)); - 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_STATIC_BFC); - } MOZ_ASSERT( aListID != FrameChildListID::Principal || GetInner() || GetLegend(), "Setting principal child list should populate our inner frame " @@ -816,11 +811,6 @@ void nsFieldSetFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, nsContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine, std::move(aFrameList)); MOZ_ASSERT(GetLegend()); - 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_STATIC_BFC); - } } #ifdef DEBUG diff --git a/layout/generic/BlockReflowState.h b/layout/generic/BlockReflowState.h index 6fd1bfabc1f4..6f05b6ab0a52 100644 --- a/layout/generic/BlockReflowState.h +++ b/layout/generic/BlockReflowState.h @@ -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 any of the NS_BLOCK_BFC_STATE_BITS flag - // set, for which margins apply by default). + // root" frame (i.e. a frame with any of the NS_BLOCK_BFC 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 any of the NS_BLOCK_BFC_STATE_BITS flag - // set, for which margins apply by default). + // root" frame (i.e. a frame with any of the NS_BLOCK_BFC 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. diff --git a/layout/generic/FrameClasses.py b/layout/generic/FrameClasses.py index ecd2401598c5..36c1af10d138 100644 --- a/layout/generic/FrameClasses.py +++ b/layout/generic/FrameClasses.py @@ -14,6 +14,7 @@ COMMON = { LEAF = {"Leaf"} MATHML = {"MathML"} SVG = {"SVG"} +BFC = {"BlockFormattingContext"} BLOCK = COMMON | {"CanContainOverflowContainers"} @@ -54,13 +55,13 @@ FRAME_CLASSES = [ Frame("nsCheckboxRadioFrame", "CheckboxRadio", REPLACED_WITH_BLOCK | LEAF), Frame("nsColorControlFrame", "ColorControl", REPLACED_WITH_BLOCK | LEAF), Frame("nsColumnSetFrame", "ColumnSet", COMMON), - Frame("ColumnSetWrapperFrame", "ColumnSetWrapper", BLOCK), + Frame("ColumnSetWrapperFrame", "ColumnSetWrapper", BLOCK | BFC), Frame("nsComboboxControlFrame", "ComboboxControl", REPLACED_WITH_BLOCK | LEAF), Frame("ComboboxLabelFrame", "Block", BLOCK), Frame("nsContinuingTextFrame", "Text", TEXT), Frame("nsDateTimeControlFrame", "DateTimeControl", REPLACED_WITH_BLOCK), Frame("nsFieldSetFrame", "FieldSet", BLOCK), - Frame("nsFileControlFrame", "Block", REPLACED_WITH_BLOCK | LEAF), + Frame("nsFileControlFrame", "Block", REPLACED_WITH_BLOCK | LEAF | BFC), Frame("FileControlLabelFrame", "Block", BLOCK | LEAF), Frame("nsFirstLetterFrame", "Letter", INLINE), Frame("nsFloatingFirstLetterFrame", "Letter", INLINE - {"LineParticipant"}), @@ -79,7 +80,7 @@ FRAME_CLASSES = [ Frame("nsImageFrame", "Image", REPLACED_SIZING | {"LeafDynamic"}), Frame("nsInlineFrame", "Inline", INLINE), Frame("nsListControlFrame", "ListControl", REPLACED_WITH_BLOCK), - Frame("nsMathMLmathBlockFrame", "Block", BLOCK | MATHML), + Frame("nsMathMLmathBlockFrame", "Block", BLOCK | MATHML | BFC), Frame("nsMathMLmathInlineFrame", "Inline", INLINE | MATHML), Frame("nsMathMLmencloseFrame", "None", MATHML_CONTAINER), Frame("nsMathMLmfracFrame", "None", MATHML_CONTAINER), @@ -115,7 +116,7 @@ FRAME_CLASSES = [ Frame("nsScrollbarButtonFrame", "SimpleXULLeaf", COMMON | LEAF), Frame("nsScrollbarFrame", "Scrollbar", COMMON), Frame("nsSearchControlFrame", "SearchControl", LEAF), - Frame("nsSelectsAreaFrame", "Block", BLOCK), + Frame("nsSelectsAreaFrame", "Block", BLOCK | BFC), Frame("nsPageSequenceFrame", "PageSequence", COMMON), Frame("nsSliderFrame", "Slider", COMMON), Frame("nsSplitterFrame", "SimpleXULLeaf", COMMON | LEAF), diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 48d542ed3ea0..a25e4e996e99 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -41,7 +41,6 @@ #include "nsPresContextInlines.h" #include "nsHTMLParts.h" #include "nsGkAtoms.h" -#include "nsAttrValueInlines.h" #include "mozilla/Sprintf.h" #include "nsFloatManager.h" #include "prenv.h" @@ -50,22 +49,15 @@ #include #include "nsLayoutUtils.h" #include "nsDisplayList.h" -#include "nsCSSAnonBoxes.h" #include "nsCSSFrameConstructor.h" #include "TextOverflow.h" #include "nsIFrameInlines.h" #include "CounterStyleManager.h" -#include "mozilla/dom/HTMLDetailsElement.h" -#include "mozilla/dom/HTMLSummaryElement.h" #include "mozilla/dom/Selection.h" #include "mozilla/PresShell.h" #include "mozilla/RestyleManager.h" #include "mozilla/ServoStyleSet.h" -#include "mozilla/Telemetry.h" #include "nsFlexContainerFrame.h" -#include "nsFileControlFrame.h" -#include "nsMathMLContainerFrame.h" -#include "nsSelectsAreaFrame.h" #include "nsBidiPresUtils.h" @@ -95,7 +87,7 @@ static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock) { static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock) { nsBlockFrame* blockWithFloatMgr = aBlock; - while (!blockWithFloatMgr->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + while (!blockWithFloatMgr->HasAnyStateBits(NS_BLOCK_BFC)) { nsBlockFrame* bf = do_QueryFrame(blockWithFloatMgr->GetParent()); if (!bf) { break; @@ -436,13 +428,6 @@ nsBlockFrame* NS_NewBlockFrame(PresShell* aPresShell, ComputedStyle* aStyle) { return new (aPresShell) nsBlockFrame(aStyle, aPresShell->GetPresContext()); } -nsBlockFrame* NS_NewBlockFormattingContext(PresShell* aPresShell, - ComputedStyle* aComputedStyle) { - nsBlockFrame* blockFrame = NS_NewBlockFrame(aPresShell, aComputedStyle); - blockFrame->AddStateBits(NS_BLOCK_STATIC_BFC); - return blockFrame; -} - NS_IMPL_FRAMEARENA_HELPERS(nsBlockFrame) nsBlockFrame::~nsBlockFrame() = default; @@ -1184,7 +1169,7 @@ static LogicalSize CalculateContainingBlockSizeForAbsolutes( */ static const nsBlockFrame* GetAsLineClampDescendant(const nsIFrame* aFrame) { if (const nsBlockFrame* block = do_QueryFrame(aFrame)) { - if (!block->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + if (!block->HasAnyStateBits(NS_BLOCK_BFC)) { return block; } } @@ -1201,7 +1186,7 @@ static bool IsLineClampRoot(const nsBlockFrame* aFrame) { return false; } - if (!aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + if (!aFrame->HasAnyStateBits(NS_BLOCK_BFC)) { return false; } @@ -3925,7 +3910,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_BFC_STATE_BITS)) { + if (HasAnyStateBits(NS_BLOCK_BFC)) { return false; } @@ -5249,7 +5234,7 @@ void nsBlockFrame::SplitFloat(BlockReflowState& aState, nsIFrame* aFloat, } aState.AppendPushedFloatChain(nextInFlow); - if (MOZ_LIKELY(!HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) || + if (MOZ_LIKELY(!HasAnyStateBits(NS_BLOCK_BFC)) || MOZ_UNLIKELY(IsTrueOverflowContainer())) { aState.mReflowStatus.SetOverflowIncomplete(); } else { @@ -6497,6 +6482,20 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame, *aFoundValidLine = FindValidLine(); } +static bool AnonymousBoxIsBFC(const ComputedStyle* aStyle) { + switch (aStyle->GetPseudoType()) { + case PseudoStyleType::fieldsetContent: + case PseudoStyleType::columnContent: + case PseudoStyleType::buttonContent: + case PseudoStyleType::cellContent: + case PseudoStyleType::scrolledContent: + case PseudoStyleType::anonymousItem: + return true; + default: + return false; + } +} + static bool StyleEstablishesBFC(const ComputedStyle* aStyle) { // paint/layout containment boxes and multi-column containers establish an // independent formatting context. @@ -6504,11 +6503,59 @@ static bool StyleEstablishesBFC(const ComputedStyle* aStyle) { // https://drafts.csswg.org/css-contain/#containment-layout // https://drafts.csswg.org/css-align/#distribution-block // https://drafts.csswg.org/css-multicol/#columns - return aStyle->StyleDisplay()->IsContainPaint() || - aStyle->StyleDisplay()->IsContainLayout() || + const auto* disp = aStyle->StyleDisplay(); + return disp->IsContainPaint() || disp->IsContainLayout() || + disp->DisplayInside() == StyleDisplayInside::FlowRoot || + disp->IsAbsolutelyPositionedStyle() || disp->IsFloatingStyle() || aStyle->StylePosition()->mAlignContent.primary != StyleAlignFlags::NORMAL || - aStyle->GetPseudoType() == PseudoStyleType::columnContent; + aStyle->IsRootElementStyle() || AnonymousBoxIsBFC(aStyle); +} + +static bool EstablishesBFC(const nsBlockFrame* aFrame) { + if (aFrame->HasAnyClassFlag(LayoutFrameClassFlags::BlockFormattingContext)) { + return true; + } + + if (nsIFrame* parent = aFrame->GetParent()) { + if (parent->IsFieldSetFrame()) { + // A rendered legend always establishes a new formatting context, and so + // does the fieldset content frame, so we can just return true here. + // https://html.spec.whatwg.org/#rendered-legend + return true; + } + + const auto wm = aFrame->GetWritingMode(); + const auto parentWM = parent->GetWritingMode(); + if (wm.GetBlockDir() != parentWM.GetBlockDir() || + wm.IsVerticalSideways() != parentWM.IsVerticalSideways()) { + // If a box has a different writing-mode value than its containing block + // [...] if the box is a block container, then it establishes a new block + // formatting context. + // https://drafts.csswg.org/css-writing-modes/#block-flow + return true; + } + } + + if (aFrame->IsColumnSpan()) { + return true; + } + + if (aFrame->IsSuppressedScrollableBlockForPrint()) { + return true; + } + + const auto* style = aFrame->Style(); + if (style->GetPseudoType() == PseudoStyleType::marker) { + if (aFrame->GetParent() && + aFrame->GetParent()->StyleList()->mListStylePosition == + StyleListStylePosition::Outside) { + // An outside ::marker needs to be an independent formatting context + // to avoid being influenced by the float manager etc. + return true; + } + } + return StyleEstablishesBFC(style); } void nsBlockFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) { @@ -6517,24 +6564,16 @@ void nsBlockFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) { return; } - // If NS_BLOCK_STATIC_BFC flag was set when the frame was initialized, it - // remains set during the lifetime of the frame and always forces it to be - // treated as a BFC, independently of the value of NS_BLOCK_DYNAMIC_BFC. - // Consequently, we don't bother invalidating or updating that latter flag. - if (HasAnyStateBits(NS_BLOCK_STATIC_BFC)) { - return; - } - - bool isBFC = StyleEstablishesBFC(Style()); - if (StyleEstablishesBFC(aOldStyle) != isBFC) { + const bool isBFC = EstablishesBFC(this); + if (HasAnyStateBits(NS_BLOCK_BFC) != isBFC) { if (MaybeHasFloats()) { // If the frame contains floats, this update may change their float // manager. Be safe by dirtying all descendant lines of the nearest // ancestor's float manager. - RemoveStateBits(NS_BLOCK_DYNAMIC_BFC); + RemoveStateBits(NS_BLOCK_BFC); MarkSameFloatManagerLinesDirty(this); } - AddOrRemoveStateBits(NS_BLOCK_DYNAMIC_BFC, isBFC); + AddOrRemoveStateBits(NS_BLOCK_BFC, isBFC); } } @@ -7837,35 +7876,15 @@ void nsBlockFrame::ChildIsDirty(nsIFrame* aChild) { nsContainerFrame::ChildIsDirty(aChild); } -static bool AlwaysEstablishesBFC(const nsBlockFrame* aFrame) { - switch (aFrame->Type()) { - case LayoutFrameType::ColumnSetWrapper: - // 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. - case LayoutFrameType::ComboboxControl: - return true; - case LayoutFrameType::Block: - return static_cast(do_QueryFrame(aFrame)) || - // Ensure that the options inside the select aren't expanded by - // right floats outside the select. - static_cast(do_QueryFrame(aFrame)) || - // See bug 1373767 and bug 353894. - static_cast(do_QueryFrame(aFrame)); - default: - return false; - } -} - void nsBlockFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) { // These are all the block specific frame bits, they are copied from // 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_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; + NS_BLOCK_BFC | 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. @@ -7887,37 +7906,12 @@ void nsBlockFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION); } - // A display:flow-root box establishes a block formatting context. - // - // If a box has a different writing-mode value than its containing block: - // ... - // If the box is a block container, then it establishes a new block - // formatting context. - // (https://drafts.csswg.org/css-writing-modes/#block-flow) - // - // If the box has contain: paint or contain:layout (or contain:strict), - // then it should also establish a formatting context. - // - // Per spec, a column-span always establishes a new block formatting context. - // - // Other more specific frame types also always establish a BFC. - // - if (StyleDisplay()->mDisplay == StyleDisplay::FlowRoot || - (GetParent() && - (GetWritingMode().GetBlockDir() != - GetParent()->GetWritingMode().GetBlockDir() || - GetWritingMode().IsVerticalSideways() != - GetParent()->GetWritingMode().IsVerticalSideways())) || - IsColumnSpan() || AlwaysEstablishesBFC(this)) { - AddStateBits(NS_BLOCK_STATIC_BFC); - } - - if (StyleEstablishesBFC(Style())) { - AddStateBits(NS_BLOCK_DYNAMIC_BFC); + if (EstablishesBFC(this)) { + AddStateBits(NS_BLOCK_BFC); } if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER) && - HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + HasAnyStateBits(NS_BLOCK_BFC)) { AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT); } } @@ -7970,11 +7964,6 @@ void nsBlockFrame::SetMarkerFrameForListItem(nsIFrame* aMarkerFrame) { SetProperty(InsideMarkerProperty(), aMarkerFrame); AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_MARKER); } else { - 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_STATIC_BFC); - } SetProperty(OutsideMarkerProperty(), new (PresShell()) nsFrameList(aMarkerFrame, aMarkerFrame)); AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER); @@ -8175,7 +8164,7 @@ void nsBlockFrame::CheckFloats(BlockReflowState& aState) { void nsBlockFrame::IsMarginRoot(bool* aBStartMarginRoot, bool* aBEndMarginRoot) { nsIFrame* parent = GetParent(); - if (!HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + if (!HasAnyStateBits(NS_BLOCK_BFC)) { if (!parent || parent->IsFloatContainingBlock()) { *aBStartMarginRoot = false; *aBEndMarginRoot = false; @@ -8202,14 +8191,14 @@ bool nsBlockFrame::BlockNeedsFloatManager(nsIFrame* aBlock) { NS_ASSERTION(aBlock->IsBlockFrameOrSubclass(), "aBlock must be a block"); nsIFrame* parent = aBlock->GetParent(); - return aBlock->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS) || + return aBlock->HasAnyStateBits(NS_BLOCK_BFC) || (parent && !parent->IsFloatContainingBlock()); } /* static */ bool nsBlockFrame::BlockCanIntersectFloats(nsIFrame* aFrame) { return aFrame->IsBlockFrameOrSubclass() && !aFrame->IsReplaced() && - !aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS); + !aFrame->HasAnyStateBits(NS_BLOCK_BFC); } // Note that this width can vary based on the vertical position. diff --git a/layout/generic/nsBlockReflowContext.cpp b/layout/generic/nsBlockReflowContext.cpp index ceae9f484994..23f3b83645d9 100644 --- a/layout/generic/nsBlockReflowContext.cpp +++ b/layout/generic/nsBlockReflowContext.cpp @@ -275,7 +275,7 @@ void nsBlockReflowContext::ReflowBlock(const LogicalRect& aSpace, tI = space.LineLeft(mWritingMode, mContainerSize); tB = mBCoord; - if (!mFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + if (!mFrame->HasAnyStateBits(NS_BLOCK_BFC)) { aFrameRI.mBlockDelta = mOuterReflowInput.mBlockDelta + mBCoord - aLine->BStart(); } diff --git a/layout/generic/nsFloatManager.h b/layout/generic/nsFloatManager.h index f9475673835f..eb12d44e1d67 100644 --- a/layout/generic/nsFloatManager.h +++ b/layout/generic/nsFloatManager.h @@ -70,8 +70,8 @@ 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_BFC_STATE_BITS. During reflow, the float manager for - * the nearest such ancestor block is found in ReflowInput::mFloatManager. + * any block with NS_BLOCK_BFC. 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], * line-right and line-left are calculated with respect to the writing mode diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index a9a1700737f1..db00deab954f 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -541,41 +541,30 @@ FRAME_STATE_BIT(Block, 21, NS_BLOCK_HAS_PUSHED_FLOATS) // 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) +FRAME_STATE_BIT(Block, 22, NS_BLOCK_BFC) -// 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) +FRAME_STATE_BIT(Block, 23, NS_BLOCK_HAS_LINE_CURSOR) -// 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_OVERFLOW_LINES) -FRAME_STATE_BIT(Block, 24, NS_BLOCK_HAS_LINE_CURSOR) - -FRAME_STATE_BIT(Block, 25, NS_BLOCK_HAS_OVERFLOW_LINES) - -FRAME_STATE_BIT(Block, 26, NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) +FRAME_STATE_BIT(Block, 25, NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS) // Set on any block that has descendant frames in the normal // flow with 'clear' set to something other than 'none' // (including
frames) -FRAME_STATE_BIT(Block, 27, NS_BLOCK_HAS_CLEAR_CHILDREN) - -// NS_BLOCK_CLIP_PAGINATED_OVERFLOW is only set in paginated prescontexts, on -// blocks which were forced to not have scrollframes but still need to clip -// the display of their kids. -FRAME_STATE_BIT(Block, 28, NS_BLOCK_CLIP_PAGINATED_OVERFLOW) +FRAME_STATE_BIT(Block, 26, NS_BLOCK_HAS_CLEAR_CHILDREN) // NS_BLOCK_HAS_FIRST_LETTER_STYLE means that the block has first-letter style, // even if it has no actual first-letter frame among its descendants. -FRAME_STATE_BIT(Block, 29, NS_BLOCK_HAS_FIRST_LETTER_STYLE) +FRAME_STATE_BIT(Block, 27, NS_BLOCK_HAS_FIRST_LETTER_STYLE) // NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER and NS_BLOCK_FRAME_HAS_INSIDE_MARKER // means the block has an associated ::marker frame, they are mutually // exclusive. -FRAME_STATE_BIT(Block, 30, NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER) -FRAME_STATE_BIT(Block, 31, NS_BLOCK_FRAME_HAS_INSIDE_MARKER) +FRAME_STATE_BIT(Block, 28, NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER) +FRAME_STATE_BIT(Block, 29, NS_BLOCK_FRAME_HAS_INSIDE_MARKER) + +// bits 30 and 31 free. // NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS indicates that exactly one line in this // block has the LineClampEllipsis flag set, and that such a line must be found diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h index e1d7ef4d2ddc..e3cab483430c 100644 --- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -57,10 +57,6 @@ nsresult NS_NewAttributeContent(nsNodeInfoManager* aNodeInfoManager, nsContainerFrame* NS_NewSelectsAreaFrame(mozilla::PresShell* aPresShell, mozilla::ComputedStyle* aStyle); -// Create a block formatting context blockframe -nsBlockFrame* NS_NewBlockFormattingContext(mozilla::PresShell* aPresShell, - mozilla::ComputedStyle* aStyle); - nsIFrame* NS_NewBRFrame(mozilla::PresShell* aPresShell, mozilla::ComputedStyle* aStyle); diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp index 34b0c1657110..479c26d18b14 100644 --- a/layout/generic/nsIFrame.cpp +++ b/layout/generic/nsIFrame.cpp @@ -2484,7 +2484,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() && !HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) { + if (IsBlockFrameOrSubclass() && !HasAnyStateBits(NS_BLOCK_BFC)) { return false; } @@ -11563,11 +11563,24 @@ nsIFrame::PhysicalAxes nsIFrame::ShouldApplyOverflowClipping( return PhysicalAxes::None; } - // If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW - // set, then we want to clip our overflow. - bool clip = HasAnyStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW) && - PresContext()->IsPaginated() && IsBlockFrame(); - return clip ? PhysicalAxes::Both : PhysicalAxes::None; + return IsSuppressedScrollableBlockForPrint() ? PhysicalAxes::Both + : PhysicalAxes::None; +} + +bool nsIFrame::IsSuppressedScrollableBlockForPrint() const { + // This condition needs to match the suppressScrollFrame logic in the frame + // constructor. + if (!PresContext()->IsPaginated() || !IsBlockFrame() || + !StyleDisplay()->IsScrollableOverflow() || + !StyleDisplay()->IsBlockOutsideStyle() || + mContent->IsInNativeAnonymousSubtree()) { + return false; + } + if (auto* element = Element::FromNode(mContent); + element && PresContext()->ElementWouldPropagateScrollStyles(*element)) { + return false; + } + return true; } bool nsIFrame::HasUnreflowedContainerQueryAncestor() const { diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 0dced06f357e..16f3d17d640a 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -562,6 +562,8 @@ enum class LayoutFrameClassFlags : uint16_t { SupportsContainLayoutAndPaint = 1 << 13, // Whether this frame class supports the `aspect-ratio` property. SupportsAspectRatio = 1 << 14, + // Whether this frame class is always a BFC. + BlockFormattingContext = 1 << 15, }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LayoutFrameClassFlags) @@ -3035,6 +3037,9 @@ class nsIFrame : public nsQueryFrame { nsSize OverflowClipMargin(PhysicalAxes aClipAxes) const; // Returns the axes on which this frame should apply overflow clipping. PhysicalAxes ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const; + // Returns whether this frame is a block that was supposed to be a + // scrollframe, but that was suppressed for print. + bool IsSuppressedScrollableBlockForPrint() const; /** * Helper method used by block reflow to identify runs of text so