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
This commit is contained in:
Emilio Cobos Álvarez
2024-03-07 16:36:56 +00:00
parent f5f9f51513
commit ef150776cf
12 changed files with 154 additions and 215 deletions

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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),

View File

@@ -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 <algorithm>
#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<const nsFileControlFrame*>(do_QueryFrame(aFrame)) ||
// Ensure that the options inside the select aren't expanded by
// right floats outside the select.
static_cast<const nsSelectsAreaFrame*>(do_QueryFrame(aFrame)) ||
// See bug 1373767 and bug 353894.
static_cast<const nsMathMLmathBlockFrame*>(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.

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 <BR CLEAR="..."> 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

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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