From 6b2c3b61b1c338ddec723482bd2c83427ef2e431 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Thu, 3 Sep 2020 18:55:28 -0500 Subject: Issue #1641 - Implement CSS flow-root keyword This is just a clean port of 1322191 and follow-up 1325970. It really seems to add create a new way to access existing code relating to block formatting and floating elements rather than implementing new functionality, and it is mercifully straightforwards. --- layout/base/nsCSSFrameConstructor.cpp | 8 +++++--- layout/base/nsLayoutUtils.cpp | 34 ++++++++++++++++++++++++++++++++++ layout/forms/nsLegendFrame.cpp | 4 +--- layout/generic/ReflowInput.cpp | 1 + layout/generic/nsBlockFrame.cpp | 7 ++++--- layout/generic/nsFrameStateBits.h | 3 +++ layout/generic/nsHTMLParts.h | 3 +-- layout/style/nsCSSKeywordList.h | 1 + layout/style/nsCSSProps.cpp | 3 +++ layout/style/nsRuleNode.cpp | 2 ++ layout/style/nsStyleConsts.h | 1 + layout/style/nsStyleStruct.h | 6 ++++-- layout/style/test/property_database.js | 4 ++++ layout/xul/nsXULLabelFrame.cpp | 4 +--- 14 files changed, 65 insertions(+), 16 deletions(-) (limited to 'layout') diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index fc458b5eb..21068b673 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -2618,7 +2618,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle newFrame = frameItems.FirstChild(); NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames"); } else { - MOZ_ASSERT(display->mDisplay == StyleDisplay::Block, + MOZ_ASSERT(display->mDisplay == StyleDisplay::Block || + display->mDisplay == StyleDisplay::FlowRoot, "Unhandled display type for root element"); contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext); nsFrameItems frameItems; @@ -4741,6 +4742,7 @@ nsCSSFrameConstructor::FindDisplayData(const nsStyleDisplay* aDisplay, static const FrameConstructionDataByDisplay sDisplayData[] = { FCDATA_FOR_DISPLAY(StyleDisplay::None, UNREACHABLE_FCDATA()), FCDATA_FOR_DISPLAY(StyleDisplay::Block, UNREACHABLE_FCDATA()), + FCDATA_FOR_DISPLAY(StyleDisplay::FlowRoot, UNREACHABLE_FCDATA()), // To keep the hash table small don't add inline frames (they're // typically things like FONT and B), because we can quickly // find them if we need to. @@ -4926,7 +4928,7 @@ nsCSSFrameConstructor::ConstructNonScrollableBlockWithConstructor( StyleDisplay::InlineBlock == aDisplay->mDisplay || clipPaginatedOverflow) && !aParentFrame->IsSVGText()) { - flags = NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT; + flags = NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS; if (clipPaginatedOverflow) { flags |= NS_BLOCK_CLIP_PAGINATED_OVERFLOW; } @@ -5119,7 +5121,7 @@ nsCSSFrameConstructor::FlushAccumulatedBlock(nsFrameConstructorState& aState, // is not a suitable block. nsContainerFrame* blockFrame = NS_NewMathMLmathBlockFrame(mPresShell, blockContext); - blockFrame->AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); + blockFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS); InitAndRestoreFrame(aState, aContent, aParentFrame, blockFrame); ReparentFrames(this, blockFrame, aBlockItems); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 74dbd63e6..c8455c1c9 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -149,6 +149,7 @@ using namespace mozilla::gfx; #define GRID_ENABLED_PREF_NAME "layout.css.grid.enabled" #define GRID_TEMPLATE_SUBGRID_ENABLED_PREF_NAME "layout.css.grid-template-subgrid-value.enabled" #define WEBKIT_PREFIXES_ENABLED_PREF_NAME "layout.css.prefixes.webkit" +#define DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME "layout.css.display-flow-root.enabled" #define DISPLAY_CONTENTS_ENABLED_PREF_NAME "layout.css.display-contents.enabled" #define TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME "layout.css.text-align-unsafe-value.enabled" #define FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME "layout.css.float-logical-values.enabled" @@ -314,6 +315,37 @@ WebkitPrefixEnabledPrefChangeCallback(const char* aPrefName, void* aClosure) } } +// When the pref "layout.css.display-flow-root.enabled" changes, this function is +// invoked to let us update kDisplayKTable, to selectively disable or restore +// the entries for "flow-root" in that table. +static void +DisplayFlowRootEnabledPrefChangeCallback(const char* aPrefName, void* aClosure) +{ + NS_ASSERTION(strcmp(aPrefName, DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME) == 0, + "Did you misspell " DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME " ?"); + + static bool sIsDisplayFlowRootKeywordIndexInitialized; + static int32_t sIndexOfFlowRootInDisplayTable; + bool isDisplayFlowRootEnabled = + Preferences::GetBool(DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME, false); + + if (!sIsDisplayFlowRootKeywordIndexInitialized) { + // First run: find the position of "flow-root" in kDisplayKTable. + sIndexOfFlowRootInDisplayTable = + nsCSSProps::FindIndexOfKeyword(eCSSKeyword_flow_root, + nsCSSProps::kDisplayKTable); + sIsDisplayFlowRootKeywordIndexInitialized = true; + } + + // OK -- now, stomp on or restore the "flow-root" entry in kDisplayKTable, + // depending on whether the pref is enabled vs. disabled. + if (sIndexOfFlowRootInDisplayTable >= 0) { + nsCSSProps::kDisplayKTable[sIndexOfFlowRootInDisplayTable].mKeyword = + isDisplayFlowRootEnabled ? eCSSKeyword_flow_root : eCSSKeyword_UNKNOWN; + } +} + + // When the pref "layout.css.display-contents.enabled" changes, this function is // invoked to let us update kDisplayKTable, to selectively disable or restore // the entries for "contents" in that table. @@ -7555,6 +7587,8 @@ static const PrefCallbacks kPrefCallbacks[] = { WebkitPrefixEnabledPrefChangeCallback }, { TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME, TextAlignUnsafeEnabledPrefChangeCallback }, + { DISPLAY_FLOW_ROOT_ENABLED_PREF_NAME, + DisplayFlowRootEnabledPrefChangeCallback }, { DISPLAY_CONTENTS_ENABLED_PREF_NAME, DisplayContentsEnabledPrefChangeCallback }, { FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME, diff --git a/layout/forms/nsLegendFrame.cpp b/layout/forms/nsLegendFrame.cpp index 95efc2c87..b985ed8fc 100644 --- a/layout/forms/nsLegendFrame.cpp +++ b/layout/forms/nsLegendFrame.cpp @@ -24,9 +24,7 @@ NS_NewLegendFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) #endif nsIFrame* f = new (aPresShell) nsLegendFrame(aContext); - if (f) { - f->AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); - } + f->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS); return f; } diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp index 9f7b4368c..077c68b5b 100644 --- a/layout/generic/ReflowInput.cpp +++ b/layout/generic/ReflowInput.cpp @@ -844,6 +844,7 @@ ReflowInput::InitFrameType(nsIAtom* aFrameType) case StyleDisplay::Flex: case StyleDisplay::WebkitBox: case StyleDisplay::Grid: + case StyleDisplay::FlowRoot: case StyleDisplay::RubyTextContainer: frameType = NS_CSS_FRAME_TYPE_BLOCK; break; diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 4742db07e..152b3d06a 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -305,7 +305,7 @@ NS_NewBlockFormattingContext(nsIPresShell* aPresShell, nsStyleContext* aStyleContext) { nsBlockFrame* blockFrame = NS_NewBlockFrame(aPresShell, aStyleContext); - blockFrame->AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); + blockFrame->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS); return blockFrame; } @@ -6893,10 +6893,11 @@ nsBlockFrame::Init(nsIContent* aContent, // (http://dev.w3.org/csswg/css-writing-modes/#block-flow) // If the box has contain: paint (or contain: strict), then it should also // establish a formatting context. - if ((GetParent() && StyleVisibility()->mWritingMode != + if (StyleDisplay()->mDisplay == mozilla::StyleDisplay::FlowRoot || + (GetParent() && StyleVisibility()->mWritingMode != GetParent()->StyleVisibility()->mWritingMode) || StyleDisplay()->IsContainPaint()) { - AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); + AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS); } if ((GetStateBits() & diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index f8b1e541c..ba43e37d4 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -483,6 +483,9 @@ FRAME_STATE_BIT(Block, 22, NS_BLOCK_MARGIN_ROOT) // used to reserve space for the floated frames. FRAME_STATE_BIT(Block, 23, NS_BLOCK_FLOAT_MGR) +// 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) + FRAME_STATE_BIT(Block, 24, NS_BLOCK_HAS_LINE_CURSOR) FRAME_STATE_BIT(Block, 25, NS_BLOCK_HAS_OVERFLOW_LINES) diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h index 243c432b2..97edaf75c 100644 --- a/layout/generic/nsHTMLParts.h +++ b/layout/generic/nsHTMLParts.h @@ -28,8 +28,7 @@ class nsTableColFrame; // 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. -#define NS_BLOCK_FLAGS_MASK (NS_BLOCK_MARGIN_ROOT | \ - NS_BLOCK_FLOAT_MGR | \ +#define 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_BULLET | \ diff --git a/layout/style/nsCSSKeywordList.h b/layout/style/nsCSSKeywordList.h index 34a46ffce..9045da9ff 100644 --- a/layout/style/nsCSSKeywordList.h +++ b/layout/style/nsCSSKeywordList.h @@ -285,6 +285,7 @@ CSS_KEY(flex, flex) CSS_KEY(flex-end, flex_end) CSS_KEY(flex-start, flex_start) CSS_KEY(flip, flip) +CSS_KEY(flow-root, flow_root) CSS_KEY(forwards, forwards) CSS_KEY(fraktur, fraktur) CSS_KEY(from-image, from_image) diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index ac2978c27..24c97cf33 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -1345,6 +1345,9 @@ KTableEntry nsCSSProps::kDisplayKTable[] = { // The next entry is controlled by the layout.css.display-contents.enabled // pref. { eCSSKeyword_contents, StyleDisplay::Contents }, + // The next entry is controlled by the layout.css.display-flow-root.enabled + // pref. + { eCSSKeyword_flow_root, StyleDisplay::FlowRoot }, { eCSSKeyword_UNKNOWN, -1 } }; diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 1a451a2ef..036d97f86 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -250,6 +250,7 @@ nsRuleNode::EnsureBlockDisplay(StyleDisplay& display, case StyleDisplay::Flex: case StyleDisplay::WebkitBox: case StyleDisplay::Grid: + case StyleDisplay::FlowRoot: // do not muck with these at all - already blocks // This is equivalent to nsStyleDisplay::IsBlockOutside. (XXX Maybe we // should just call that?) @@ -293,6 +294,7 @@ nsRuleNode::EnsureInlineDisplay(StyleDisplay& display) // see if the display value is already inline switch (display) { case StyleDisplay::Block: + case StyleDisplay::FlowRoot: display = StyleDisplay::InlineBlock; break; case StyleDisplay::Table: diff --git a/layout/style/nsStyleConsts.h b/layout/style/nsStyleConsts.h index 6d207aec9..f54387aa8 100644 --- a/layout/style/nsStyleConsts.h +++ b/layout/style/nsStyleConsts.h @@ -524,6 +524,7 @@ enum class FillMode : uint32_t; enum class StyleDisplay : uint8_t { None = 0, Block, + FlowRoot, Inline, InlineBlock, ListItem, diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 4bda817dd..f49cdc43e 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -2890,7 +2890,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay return mozilla::StyleDisplay::Block == mDisplay || mozilla::StyleDisplay::ListItem == mDisplay || mozilla::StyleDisplay::InlineBlock == mDisplay || - mozilla::StyleDisplay::TableCaption == mDisplay; + mozilla::StyleDisplay::TableCaption == mDisplay || + mozilla::StyleDisplay::FlowRoot == mDisplay; // Should TABLE_CELL be included here? They have // block frames nested inside of them. // (But please audit all callers before changing.) @@ -2902,7 +2903,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay mozilla::StyleDisplay::WebkitBox == mDisplay || mozilla::StyleDisplay::Grid == mDisplay || mozilla::StyleDisplay::ListItem == mDisplay || - mozilla::StyleDisplay::Table == mDisplay; + mozilla::StyleDisplay::Table == mDisplay || + mozilla::StyleDisplay::FlowRoot == mDisplay; } static bool IsDisplayTypeInlineOutside(mozilla::StyleDisplay aDisplay) { diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index c75f7b498..2d6352148 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -7892,6 +7892,10 @@ if (IsCSSPropertyPrefEnabled("layout.css.background-clip-text.enabled")) { ); } +if (IsCSSPropertyPrefEnabled("layout.css.display-flow-root.enabled")) { + gCSSProperties["display"].other_values.push("flow-root"); +} + // Copy aliased properties' fields from their alias targets. for (var prop in gCSSProperties) { var entry = gCSSProperties[prop]; diff --git a/layout/xul/nsXULLabelFrame.cpp b/layout/xul/nsXULLabelFrame.cpp index 22b875461..41e7e4d76 100644 --- a/layout/xul/nsXULLabelFrame.cpp +++ b/layout/xul/nsXULLabelFrame.cpp @@ -16,9 +16,7 @@ nsIFrame* NS_NewXULLabelFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { nsXULLabelFrame* it = new (aPresShell) nsXULLabelFrame(aContext); - - it->AddStateBits(NS_BLOCK_FLOAT_MGR | NS_BLOCK_MARGIN_ROOT); - + it->AddStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS); return it; } -- cgit v1.2.3