layout: Force outside ::marker to establish a BFC (#37252)

Even though we were continuing the parent BFC, we weren't updating the
SequentialLayoutState to have the correct containing block info. That
caused problem in the presence of floats.

This patch establishes an independent BFC, which avoids the problem.
This seems reasonable since outside markers are out-of-flow-ish, and it
matches Firefox. Blink implements them as inline-blocks, so they should
also establish a BFC.

Testing: Adding new tests. Some still fail because of a different issue.
Also, adding an expectation for several existing tests that were missing
it.
Fixes: #37222

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2025-06-06 18:01:27 +02:00 committed by GitHub
parent a1f43ab06d
commit 8540b0f6e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 768 additions and 245 deletions

View file

@ -744,9 +744,14 @@ impl BlockLevelJob<'_> {
self.propagated_data,
false, /* is_list_item */
);
// An outside ::marker must establish a BFC, and can't contain floats.
let block_formatting_context = BlockFormattingContext {
contents: block_container,
contains_floats: false,
};
ArcRefCell::new(BlockLevelBox::OutsideMarker(OutsideMarker {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
block_container,
block_formatting_context,
list_item_style,
}))
},

View file

@ -308,7 +308,7 @@ pub(crate) struct CollapsibleWithParentStartMargin(bool);
pub(crate) struct OutsideMarker {
pub list_item_style: Arc<ComputedValues>,
pub base: LayoutBoxBase,
pub block_container: BlockContainer,
pub block_formatting_context: BlockFormattingContext,
}
impl OutsideMarker {
@ -317,8 +317,11 @@ impl OutsideMarker {
layout_context: &LayoutContext,
constraint_space: &ConstraintSpace,
) -> InlineContentSizesResult {
self.base
.inline_content_sizes(layout_context, constraint_space, &self.block_container)
self.base.inline_content_sizes(
layout_context,
constraint_space,
&self.block_formatting_context.contents,
)
}
fn layout(
@ -326,8 +329,6 @@ impl OutsideMarker {
layout_context: &LayoutContext<'_>,
containing_block: &ContainingBlock<'_>,
positioning_context: &mut PositioningContext,
sequential_layout_state: Option<&mut SequentialLayoutState>,
collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
) -> Fragment {
let constraint_space = ConstraintSpace::new_for_style_and_ratio(
&self.base.style,
@ -342,17 +343,11 @@ impl OutsideMarker {
style: &self.base.style,
};
// A ::marker can't have a stretch size (must be auto), so this doesn't matter.
// https://drafts.csswg.org/css-sizing-4/#stretch-fit-sizing
let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
let flow_layout = self.block_container.layout(
let flow_layout = self.block_formatting_context.layout(
layout_context,
positioning_context,
&containing_block_for_children,
sequential_layout_state,
collapsible_with_parent_start_margin.unwrap_or(CollapsibleWithParentStartMargin(false)),
ignore_block_margins_for_stretch,
false, /* depends_on_block_constraints */
);
let max_inline_size =
@ -900,13 +895,9 @@ impl BlockLevelBox {
BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new(
float_box.layout(layout_context, positioning_context, containing_block),
)),
BlockLevelBox::OutsideMarker(outside_marker) => outside_marker.layout(
layout_context,
containing_block,
positioning_context,
sequential_layout_state,
collapsible_with_parent_start_margin,
),
BlockLevelBox::OutsideMarker(outside_marker) => {
outside_marker.layout(layout_context, containing_block, positioning_context)
},
};
self.with_base(|base| base.set_fragment(fragment.clone()));