Share more code for non-replaced float-avoiding blocks (#34585)

Block-level elements that establish an independent formatting context
(or are replaced) need to avoid overlapping floats.

In the non-replaced case, we have two different subcases, depending on
whether the inline size of the element is known. This patch makes them
share more logic.

Then `solve_clearance_and_inline_margins_avoiding_floats()` would only
be used in the replaced case, so it's removed, inlining its logic.

Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
Oriol Brufau 2024-12-12 13:53:44 +01:00 committed by GitHub
parent 0ffa5fa277
commit acf0074f8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 86 deletions

View file

@ -1103,11 +1103,8 @@ impl SequentialLayoutState {
let placement_rect = placement.place(); let placement_rect = placement.place();
let position = &placement_rect.start_corner; let position = &placement_rect.start_corner;
let has_clearance = clear_position.is_some() || position.block > ceiling; let has_clearance = clear_position.is_some() || position.block > ceiling;
let clearance = if has_clearance { let clearance = has_clearance
Some(position.block - self.position_with_zero_clearance(block_start_margin)) .then(|| position.block - self.position_with_zero_clearance(block_start_margin));
} else {
None
};
(clearance, placement_rect) (clearance, placement_rect)
} }

View file

@ -1121,9 +1121,6 @@ impl IndependentNonReplacedContents {
.clamp_between_extremums(content_min_box_size.block, content_max_box_size.block) .clamp_between_extremums(content_min_box_size.block, content_max_box_size.block)
}); });
let margin_inline_start;
let margin_inline_end;
let effective_margin_inline_start;
let (margin_block_start, margin_block_end) = let (margin_block_start, margin_block_end) =
solve_block_margins_for_in_flow_block_level(&pbm); solve_block_margins_for_in_flow_block_level(&pbm);
let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start); let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
@ -1138,10 +1135,22 @@ impl IndependentNonReplacedContents {
// sufficient space. They may even make the border box of said element narrower // sufficient space. They may even make the border box of said element narrower
// than defined by section 10.3.3. CSS 2 does not define when a UA may put said // than defined by section 10.3.3. CSS 2 does not define when a UA may put said
// 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 mut content_size; let mut content_size;
let mut layout; let mut layout;
let mut placement_rect;
let style = &base.style; let style = &base.style;
// First compute the clear position required by the 'clear' property.
// The code below may then add extra clearance when the element can't fit
// next to floats not covered by 'clear'.
let clear_position = sequential_layout_state.calculate_clear_position(
Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
&collapsed_margin_block_start,
);
let ceiling = clear_position.unwrap_or_else(|| {
sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
});
if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline { if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline {
let inline_size = inline_size let inline_size = inline_size
.clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline); .clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline);
@ -1175,30 +1184,14 @@ impl IndependentNonReplacedContents {
}; };
} }
( let mut placement = PlacementAmongFloats::new(
clearance, &sequential_layout_state.floats,
(margin_inline_start, margin_inline_end), ceiling,
effective_margin_inline_start,
) = solve_clearance_and_inline_margins_avoiding_floats(
sequential_layout_state,
&collapsed_margin_block_start,
containing_block,
&pbm,
content_size + pbm.padding_border_sums, content_size + pbm.padding_border_sums,
style, &pbm,
); );
placement_rect = placement.place();
} else { } else {
// First compute the clear position required by the 'clear' property.
// The code below may then add extra clearance when the element can't fit
// next to floats not covered by 'clear'.
let clear_position = sequential_layout_state.calculate_clear_position(
Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
&collapsed_margin_block_start,
);
let ceiling = clear_position.unwrap_or_else(|| {
sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
});
// Create a PlacementAmongFloats using the minimum size in all dimensions as the object size. // Create a PlacementAmongFloats using the minimum size in all dimensions as the object size.
let minimum_size_of_block = LogicalVec2 { let minimum_size_of_block = LogicalVec2 {
inline: content_min_box_size.inline, inline: content_min_box_size.inline,
@ -1210,7 +1203,6 @@ impl IndependentNonReplacedContents {
minimum_size_of_block, minimum_size_of_block,
&pbm, &pbm,
); );
let mut placement_rect;
loop { loop {
// First try to place the block using the minimum size as the object size. // First try to place the block using the minimum size as the object size.
@ -1284,31 +1276,26 @@ impl IndependentNonReplacedContents {
// attempt. // attempt.
positioning_context.truncate(&positioning_context_length); positioning_context.truncate(&positioning_context_length);
} }
}
// Only set clearance if we would have cleared or the placement among floats moves // Only set clearance if we would have cleared or the placement among floats moves
// the block further in the block direction. These two situations are the ones that // the block further in the block direction. These two situations are the ones that
// prevent margin collapse. // prevent margin collapse.
clearance = if clear_position.is_some() || placement_rect.start_corner.block > ceiling { let has_clearance = clear_position.is_some() || placement_rect.start_corner.block > ceiling;
Some( let clearance = has_clearance.then(|| {
placement_rect.start_corner.block - placement_rect.start_corner.block -
sequential_layout_state sequential_layout_state
.position_with_zero_clearance(&collapsed_margin_block_start), .position_with_zero_clearance(&collapsed_margin_block_start)
) });
} else {
None
};
( let ((margin_inline_start, margin_inline_end), effective_margin_inline_start) =
(margin_inline_start, margin_inline_end), solve_inline_margins_avoiding_floats(
effective_margin_inline_start,
) = solve_inline_margins_avoiding_floats(
sequential_layout_state, sequential_layout_state,
containing_block, containing_block,
&pbm, &pbm,
content_size.inline + pbm.padding_border_sums.inline, content_size.inline + pbm.padding_border_sums.inline,
placement_rect, placement_rect,
); );
}
let margin = LogicalSides { let margin = LogicalSides {
inline_start: margin_inline_start, inline_start: margin_inline_start,
@ -1409,17 +1396,26 @@ impl ReplacedContents {
// 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 collapsed_margin_block_start = CollapsedMargin::new(margin_block_start); let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
let size = content_size + pbm.padding_border_sums; let size = content_size + pbm.padding_border_sums;
let placement_rect;
(clearance, placement_rect) = sequential_layout_state
.calculate_clearance_and_inline_adjustment(
Clear::from_style_and_container_writing_mode(
&base.style,
containing_block.style.writing_mode,
),
&collapsed_margin_block_start,
pbm,
size,
);
( (
clearance,
(margin_inline_start, margin_inline_end), (margin_inline_start, margin_inline_end),
effective_margin_inline_start, effective_margin_inline_start,
) = solve_clearance_and_inline_margins_avoiding_floats( ) = solve_inline_margins_avoiding_floats(
sequential_layout_state, sequential_layout_state,
&collapsed_margin_block_start,
containing_block, containing_block,
pbm, pbm,
size, size.inline,
&base.style, placement_rect,
); );
// Clearance prevents margin collapse between this block and previous ones, // Clearance prevents margin collapse between this block and previous ones,
@ -1738,39 +1734,6 @@ fn solve_inline_margins_avoiding_floats(
(inline_margins, effective_margin_inline_start) (inline_margins, effective_margin_inline_start)
} }
/// A block-level element that establishes an independent formatting context (or is replaced)
/// must not overlap floats.
/// This can be achieved by adding clearance (to adjust the position in the block axis)
/// and/or modifying the margins in the inline axis.
/// This function takes care of calculating them.
fn solve_clearance_and_inline_margins_avoiding_floats(
sequential_layout_state: &SequentialLayoutState,
block_start_margin: &CollapsedMargin,
containing_block: &ContainingBlock,
pbm: &PaddingBorderMargin,
size: LogicalVec2<Au>,
style: &Arc<ComputedValues>,
) -> (Option<Au>, (Au, Au), Au) {
let (clearance, placement_rect) = sequential_layout_state
.calculate_clearance_and_inline_adjustment(
Clear::from_style_and_container_writing_mode(
style,
containing_block.style.writing_mode,
),
block_start_margin,
pbm,
size,
);
let (inline_margins, effective_margin_inline_start) = solve_inline_margins_avoiding_floats(
sequential_layout_state,
containing_block,
pbm,
size.inline,
placement_rect,
);
(clearance, inline_margins, effective_margin_inline_start)
}
/// 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