mirror of
https://github.com/servo/servo.git
synced 2025-08-01 19:50:30 +01:00
Fix interaction of clearance with margin collapse
In #29897 I did the simple naive thing, but it wasn't entirely correct. This patch tries to address the problems. In particular: - Clearance should prevent margins from collapsing through if it happens between them, as opposed to on the element that owns them. - The margins of an element with clearance can still collapse through, and collapse with other siblings as normal, but the resulting margin can't collapse with the bottom margin of the parent.
This commit is contained in:
parent
fa7107ac12
commit
0dd6abe023
7 changed files with 41 additions and 24 deletions
|
@ -306,10 +306,11 @@ fn layout_block_level_children_in_parallel(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let (content_block_size, collapsible_margins_in_children) = placement_state.finish();
|
||||
FlowLayout {
|
||||
fragments,
|
||||
content_block_size: placement_state.current_block_direction_position,
|
||||
collapsible_margins_in_children: placement_state.collapsible_margins_in_children(),
|
||||
content_block_size,
|
||||
collapsible_margins_in_children,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,10 +350,11 @@ fn layout_block_level_children_sequentially(
|
|||
})
|
||||
.collect();
|
||||
|
||||
let (content_block_size, collapsible_margins_in_children) = placement_state.finish();
|
||||
FlowLayout {
|
||||
fragments,
|
||||
content_block_size: placement_state.current_block_direction_position,
|
||||
collapsible_margins_in_children: placement_state.collapsible_margins_in_children(),
|
||||
content_block_size,
|
||||
collapsible_margins_in_children,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -641,7 +643,6 @@ fn layout_in_flow_non_replaced_block_level(
|
|||
collapsible_margins_in_children.collapsed_through &&
|
||||
block_is_same_formatting_context &&
|
||||
pbm.padding_border_sums.block == Length::zero() &&
|
||||
clearance == Length::zero() &&
|
||||
block_size.auto_is(|| Length::zero()) == Length::zero() &&
|
||||
min_box_size.block == Length::zero();
|
||||
},
|
||||
|
@ -775,6 +776,7 @@ fn solve_inline_margins_for_in_flow_block_level(
|
|||
// mode, this is done right after each block is laid out.
|
||||
pub(crate) struct PlacementState {
|
||||
next_in_flow_margin_collapses_with_parent_start_margin: bool,
|
||||
last_in_flow_margin_collapses_with_parent_end_margin: bool,
|
||||
start_margin: CollapsedMargin,
|
||||
current_margin: CollapsedMargin,
|
||||
current_block_direction_position: Length,
|
||||
|
@ -787,6 +789,7 @@ impl PlacementState {
|
|||
PlacementState {
|
||||
next_in_flow_margin_collapses_with_parent_start_margin:
|
||||
collapsible_with_parent_start_margin.0,
|
||||
last_in_flow_margin_collapses_with_parent_end_margin: true,
|
||||
start_margin: CollapsedMargin::zero(),
|
||||
current_margin: CollapsedMargin::zero(),
|
||||
current_block_direction_position: Length::zero(),
|
||||
|
@ -801,7 +804,23 @@ impl PlacementState {
|
|||
fragment.padding.block_sum() +
|
||||
fragment.border.block_sum() +
|
||||
fragment.content_rect.size.block;
|
||||
|
||||
// We use `last_in_flow_margin_collapses_with_parent_end_margin` to implement
|
||||
// this quote from https://drafts.csswg.org/css2/#collapsing-margins
|
||||
// > If the top and bottom margins of an element with clearance are adjoining,
|
||||
// > its margins collapse with the adjoining margins of following siblings but that
|
||||
// > resulting margin does not collapse with the bottom margin of the parent block.
|
||||
if fragment.clearance != Length::zero() {
|
||||
// Margins can't be adjoining if they are separated by clearance.
|
||||
// Setting `next_in_flow_margin_collapses_with_parent_start_margin` to false
|
||||
// prevents collapsing with the start margin of the parent, and will set
|
||||
// `collapsed_through` to false, preventing the parent from collapsing through.
|
||||
self.next_in_flow_margin_collapses_with_parent_start_margin = false;
|
||||
if fragment_block_margins.collapsed_through {
|
||||
self.last_in_flow_margin_collapses_with_parent_end_margin = false;
|
||||
}
|
||||
} else if !fragment_block_margins.collapsed_through {
|
||||
self.last_in_flow_margin_collapses_with_parent_end_margin = true;
|
||||
}
|
||||
if self.next_in_flow_margin_collapses_with_parent_start_margin {
|
||||
debug_assert_eq!(self.current_margin.solve(), Length::zero());
|
||||
self.start_margin
|
||||
|
@ -818,6 +837,9 @@ impl PlacementState {
|
|||
fragment.content_rect.start_corner.block +=
|
||||
self.current_margin.solve() + self.current_block_direction_position;
|
||||
if fragment_block_margins.collapsed_through {
|
||||
// `fragment_block_size` is typically zero when collapsing through,
|
||||
// but we still need to consider it in case there is clearance.
|
||||
self.current_block_direction_position += fragment_block_size;
|
||||
self.current_margin
|
||||
.adjoin_assign(&fragment_block_margins.end);
|
||||
return;
|
||||
|
@ -838,12 +860,19 @@ impl PlacementState {
|
|||
}
|
||||
}
|
||||
|
||||
fn collapsible_margins_in_children(&self) -> CollapsedBlockMargins {
|
||||
CollapsedBlockMargins {
|
||||
collapsed_through: self.next_in_flow_margin_collapses_with_parent_start_margin,
|
||||
start: self.start_margin,
|
||||
end: self.current_margin,
|
||||
fn finish(mut self) -> (Length, CollapsedBlockMargins) {
|
||||
if !self.last_in_flow_margin_collapses_with_parent_end_margin {
|
||||
self.current_block_direction_position += self.current_margin.solve();
|
||||
self.current_margin = CollapsedMargin::zero();
|
||||
}
|
||||
(
|
||||
self.current_block_direction_position,
|
||||
CollapsedBlockMargins {
|
||||
collapsed_through: self.next_in_flow_margin_collapses_with_parent_start_margin,
|
||||
start: self.start_margin,
|
||||
end: self.current_margin,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// When Float fragments are created in block flows, they are positioned
|
||||
|
@ -865,7 +894,7 @@ impl PlacementState {
|
|||
// non-zero sized float inside? The float won't be positioned correctly
|
||||
// anyway (see the comment in `floats.rs` about margin collapse), but
|
||||
// this might make the result even worse.
|
||||
let collapsed_margins = self.collapsible_margins_in_children().start.adjoin(
|
||||
let collapsed_margins = self.start_margin.adjoin(
|
||||
&sequential_layout_state
|
||||
.floats
|
||||
.containing_block_info
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[adjoining-float-nested-forced-clearance-002.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[margin-collapse-033.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[margin-collapse-034.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[margin-collapse-035.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[margin-collapse-clear-012.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[margin-collapse-clear-013.xht]
|
||||
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue