Avoid bad calls to solve_containing_block_padding_border_and_margin_for_in_flow_box (#30073)

Avoid solve_containing_block_padding_border_and_margin_for_in_flow_box()
for a block-level box that establishes an independent formatting context
(or is replaced) in the presence of floats, since the margins and inline
size could then be incorrect.

No actual change in behavior: this patch still resolves the margins
incorrectly with solve_block_margins_for_in_flow_block_level(),
and also keeps the old logic for width:auto.

However, this refactoring prepares the terrain to address these issues
in #30072 and #30057.
This commit is contained in:
Oriol Brufau 2023-08-07 19:47:49 +02:00 committed by GitHub
parent cedd59361e
commit 1346c34083
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -805,6 +805,15 @@ impl NonReplacedFormattingContext {
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
sequential_layout_state: Option<&mut SequentialLayoutState>, sequential_layout_state: Option<&mut SequentialLayoutState>,
) -> BoxFragment { ) -> BoxFragment {
if let Some(sequential_layout_state) = sequential_layout_state {
return self.layout_in_flow_block_level_sequentially(
layout_context,
positioning_context,
containing_block,
sequential_layout_state,
);
}
let ContainingBlockPaddingBorderAndMargin { let ContainingBlockPaddingBorderAndMargin {
containing_block: containing_block_for_children, containing_block: containing_block_for_children,
pbm, pbm,
@ -816,15 +825,6 @@ impl NonReplacedFormattingContext {
&self.style, &self.style,
); );
if let Some(sequential_layout_state) = sequential_layout_state {
return self.layout_in_flow_block_level_sequentially(
layout_context,
positioning_context,
containing_block,
sequential_layout_state,
);
}
let layout = self.layout( let layout = self.layout(
layout_context, layout_context,
positioning_context, positioning_context,
@ -872,28 +872,21 @@ impl NonReplacedFormattingContext {
containing_block: &ContainingBlock<'_>, containing_block: &ContainingBlock<'_>,
sequential_layout_state: &mut SequentialLayoutState, sequential_layout_state: &mut SequentialLayoutState,
) -> BoxFragment { ) -> BoxFragment {
let ContainingBlockPaddingBorderAndMargin { let pbm = self.style.padding_border_margin(containing_block);
containing_block: containing_block_for_children, let box_size = self.style.content_box_size(containing_block, &pbm);
pbm, let max_box_size = self.style.content_max_box_size(containing_block, &pbm);
min_box_size, let min_box_size = self
max_box_size, .style
margin, .content_min_box_size(containing_block, &pbm)
} = solve_containing_block_padding_border_and_margin_for_in_flow_box( .auto_is(Length::zero);
containing_block, let block_size = box_size.block.map(|block_size| {
&self.style, block_size.clamp_between_extremums(min_box_size.block, max_box_size.block)
);
let layout = self.layout(
layout_context,
positioning_context,
&containing_block_for_children,
);
let block_size = containing_block_for_children.block_size.auto_is(|| {
layout
.content_block_size
.clamp_between_extremums(min_box_size.block, max_box_size.block)
}); });
let (margin_block_start, margin_block_end) =
solve_block_margins_for_in_flow_block_level(&pbm);
let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
// From https://drafts.csswg.org/css2/#floats: // From https://drafts.csswg.org/css2/#floats:
// "The border box of a table, a block-level replaced element, or an element in // "The border box of a table, a block-level replaced element, or an element in
// the normal flow that establishes a new block formatting context (such as an // the normal flow that establishes a new block formatting context (such as an
@ -906,49 +899,94 @@ impl NonReplacedFormattingContext {
// element next to the float or by how much said element may become narrower." // element next to the float or by how much said element may become narrower."
let clearance; let clearance;
let inline_adjustment_from_floats; let inline_adjustment_from_floats;
let inline_size_is_auto = self let content_size;
.style let layout;
.box_size(containing_block.style.writing_mode) if let LengthOrAuto::LengthPercentage(ref inline_size) = box_size.inline {
.inline let inline_size =
.is_auto(); inline_size.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
let block_start_margin = CollapsedMargin::new(margin.block_start); layout = self.layout(
if inline_size_is_auto { layout_context,
// TODO: Use PlacementAmongFloats to avoid overlapping floats. positioning_context,
clearance = sequential_layout_state &ContainingBlock {
.calculate_clearance(self.style.get_box().clear, &block_start_margin); inline_size,
inline_adjustment_from_floats = Length::zero(); block_size,
} else { style: &self.style,
let size = &Vec2 { },
inline: containing_block_for_children.inline_size, );
block: block_size, content_size = Vec2 {
} + &pbm.padding_border_sums; inline: inline_size,
block: block_size.auto_is(|| {
layout
.content_block_size
.clamp_between_extremums(min_box_size.block, max_box_size.block)
}),
};
(clearance, inline_adjustment_from_floats) = sequential_layout_state (clearance, inline_adjustment_from_floats) = sequential_layout_state
.calculate_clearance_and_inline_adjustment( .calculate_clearance_and_inline_adjustment(
self.style.get_box().clear, self.style.get_box().clear,
&block_start_margin, &collapsed_margin_block_start,
size.clone(), &content_size + &pbm.padding_border_sums,
); );
} else {
// TODO: Use PlacementAmongFloats to avoid overlapping floats.
let inline_size = (containing_block.inline_size -
pbm.padding_border_sums.inline -
pbm.margin.inline_start.auto_is(Length::zero) -
pbm.margin.inline_end.auto_is(Length::zero))
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
layout = self.layout(
layout_context,
positioning_context,
&ContainingBlock {
inline_size,
block_size,
style: &self.style,
},
);
content_size = Vec2 {
inline: inline_size,
block: block_size.auto_is(|| {
layout
.content_block_size
.clamp_between_extremums(min_box_size.block, max_box_size.block)
}),
};
clearance = sequential_layout_state
.calculate_clearance(self.style.get_box().clear, &collapsed_margin_block_start);
inline_adjustment_from_floats = Length::zero();
} }
// TODO: solve_inline_margins_for_in_flow_block_level() doesn't take floats into account.
let (margin_inline_start, margin_inline_end) = solve_inline_margins_for_in_flow_block_level(
&containing_block,
&pbm,
content_size.inline,
);
let margin = Sides {
inline_start: margin_inline_start,
inline_end: margin_inline_end,
block_start: margin_block_start,
block_end: margin_block_end,
};
// Clearance prevents margin collapse between this block and previous ones, // Clearance prevents margin collapse between this block and previous ones,
// so in that case collapse margins before adjoining them below. // so in that case collapse margins before adjoining them below.
if clearance.is_some() { if clearance.is_some() {
sequential_layout_state.collapse_margins(); sequential_layout_state.collapse_margins();
} }
sequential_layout_state.adjoin_assign(&block_start_margin); sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
// Margins can never collapse into independent formatting contexts. // Margins can never collapse into independent formatting contexts.
sequential_layout_state.collapse_margins(); sequential_layout_state.collapse_margins();
sequential_layout_state.advance_block_position( sequential_layout_state.advance_block_position(
pbm.padding_border_sums.block + block_size + clearance.unwrap_or_else(Length::zero), pbm.padding_border_sums.block +
content_size.block +
clearance.unwrap_or_else(Length::zero),
); );
sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end)); sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
let block_size = containing_block_for_children.block_size.auto_is(|| {
layout
.content_block_size
.clamp_between_extremums(min_box_size.block, max_box_size.block)
});
let content_rect = Rect { let content_rect = Rect {
start_corner: Vec2 { start_corner: Vec2 {
block: pbm.padding.block_start + block: pbm.padding.block_start +
@ -959,10 +997,7 @@ impl NonReplacedFormattingContext {
margin.inline_start + margin.inline_start +
inline_adjustment_from_floats, inline_adjustment_from_floats,
}, },
size: Vec2 { size: content_size,
block: block_size,
inline: containing_block_for_children.inline_size,
},
}; };
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin); let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
BoxFragment::new( BoxFragment::new(
@ -992,6 +1027,7 @@ fn layout_in_flow_replaced_block_level<'a>(
let pbm = style.padding_border_margin(containing_block); let pbm = style.padding_border_margin(containing_block);
let size = replaced.used_size_as_if_inline_element(containing_block, style, None, &pbm); let size = replaced.used_size_as_if_inline_element(containing_block, style, None, &pbm);
// TODO: solve_inline_margins_for_in_flow_block_level() doesn't take floats into account.
let (margin_inline_start, margin_inline_end) = let (margin_inline_start, margin_inline_end) =
solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, size.inline); solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, size.inline);
let margin = Sides { let margin = Sides {
@ -1077,6 +1113,9 @@ struct ContainingBlockPaddingBorderAndMargin<'a> {
/// Given the style for in in flow box and its containing block, determine the containing /// Given the style for in in flow box and its containing block, determine the containing
/// block for its children and the margin it should use. /// block for its children and the margin it should use.
/// Note that in the presence of floats, this shouldn't be used for a block-level box
/// that establishes an independent formatting context (or is replaced), since the margins
/// and inline size could then be incorrect.
fn solve_containing_block_padding_border_and_margin_for_in_flow_box<'a>( fn solve_containing_block_padding_border_and_margin_for_in_flow_box<'a>(
containing_block: &ContainingBlock<'_>, containing_block: &ContainingBlock<'_>,
style: &'a Arc<ComputedValues>, style: &'a Arc<ComputedValues>,
@ -1104,11 +1143,12 @@ fn solve_containing_block_padding_border_and_margin_for_in_flow_box<'a>(
let inline_margins = let inline_margins =
solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, inline_size); solve_inline_margins_for_in_flow_block_level(containing_block, &pbm, inline_size);
let block_margins = solve_block_margins_for_in_flow_block_level(&pbm);
let margin = Sides { let margin = Sides {
inline_start: inline_margins.0, inline_start: inline_margins.0,
inline_end: inline_margins.1, inline_end: inline_margins.1,
block_start: pbm.margin.block_start.auto_is(Length::zero), block_start: block_margins.0,
block_end: pbm.margin.block_end.auto_is(Length::zero), block_end: block_margins.1,
}; };
// https://drafts.csswg.org/css2/#the-height-property // https://drafts.csswg.org/css2/#the-height-property
@ -1137,6 +1177,12 @@ fn solve_containing_block_padding_border_and_margin_for_in_flow_box<'a>(
} }
} }
/// Resolves the margins of an in-flow block-level box in the inline axis,
/// distributing free space into 'auto' values and solving over-constrained cases.
/// <https://drafts.csswg.org/css2/#blockwidth>
///
/// Note that in the presence of floats, this shouldn't be used for a block-level box
/// that establishes an independent formatting context (or is replaced).
fn solve_inline_margins_for_in_flow_block_level( fn solve_inline_margins_for_in_flow_block_level(
containing_block: &ContainingBlock, containing_block: &ContainingBlock,
pbm: &PaddingBorderMargin, pbm: &PaddingBorderMargin,
@ -1153,6 +1199,16 @@ fn solve_inline_margins_for_in_flow_block_level(
(margin_inline_start, free_space - margin_inline_start) (margin_inline_start, free_space - margin_inline_start)
} }
/// Resolves the margins of an in-flow block-level box in the block axis.
/// <https://drafts.csswg.org/css2/#normal-block>
/// <https://drafts.csswg.org/css2/#block-root-margin>
fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Length, Length) {
(
pbm.margin.block_start.auto_is(Length::zero),
pbm.margin.block_end.auto_is(Length::zero),
)
}
/// State that we maintain when placing blocks. /// State that we maintain when placing blocks.
/// ///
/// In parallel mode, this placement is done after all child blocks are laid out. In /// In parallel mode, this placement is done after all child blocks are laid out. In