mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 13:37:45 +00:00
LibWeb: Make sure that margins don't collapse across a nested BFC
In order to fix this, I also had to reorganize the code so that we create an independent formatting context even for block-level boxes that don't have any children. This accidentally improves a table layout test as well (for empty tables).
This commit is contained in:
parent
9ce7681ff2
commit
411b28fc59
4 changed files with 62 additions and 31 deletions
|
@ -0,0 +1,6 @@
|
||||||
|
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||||
|
BlockContainer <html> at (0,0) content-size 800x116 [BFC] children: not-inline
|
||||||
|
BlockContainer <body> at (8,30) content-size 784x100 children: not-inline
|
||||||
|
BlockContainer <div.not-bfc> at (8,30) content-size 784x20 children: not-inline
|
||||||
|
BlockContainer <div.bfc> at (8,80) content-size 784x0 [BFC] children: not-inline
|
||||||
|
BlockContainer <div.not-bfc> at (8,110) content-size 784x20 children: not-inline
|
|
@ -1,8 +1,8 @@
|
||||||
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||||
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
|
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
|
||||||
BlockContainer <body> at (8,8) content-size 784x58.40625 children: not-inline
|
BlockContainer <body> at (8,8) content-size 784x58.40625 children: not-inline
|
||||||
TableWrapper <(anonymous)> at (8,8) content-size 784x0 [BFC] children: not-inline
|
TableWrapper <(anonymous)> at (8,8) content-size 0x0 [BFC] children: not-inline
|
||||||
TableBox <table#empty-table> at (8,8) content-size 784x0 [TFC] children: not-inline
|
TableBox <table#empty-table> at (8,8) content-size 0x0 [TFC] children: not-inline
|
||||||
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
|
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
|
||||||
TextNode <#text>
|
TextNode <#text>
|
||||||
TextNode <#text>
|
TextNode <#text>
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<!doctype html><style>
|
||||||
|
* {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
html {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background: pink;
|
||||||
|
}
|
||||||
|
.not-bfc {
|
||||||
|
margin-top: 30px;
|
||||||
|
height: 20px;
|
||||||
|
background: orange;
|
||||||
|
}
|
||||||
|
.bfc {
|
||||||
|
margin-top: 30px;
|
||||||
|
display: flow-root;
|
||||||
|
}
|
||||||
|
</style><div class="not-bfc"></div><div class=bfc></div><div class="not-bfc"></div>
|
|
@ -552,13 +552,23 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
||||||
m_margin_state.reset();
|
m_margin_state.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_margin_state.add_margin(box_state.margin_top);
|
CSSPixels margin_top = 0;
|
||||||
m_margin_state.update_block_waiting_for_final_y_position();
|
auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box);
|
||||||
|
|
||||||
auto margin_top = m_margin_state.current_collapsed_margin();
|
if (independent_formatting_context) {
|
||||||
if (m_margin_state.has_block_container_waiting_for_final_y_position()) {
|
// Margins of elements that establish new formatting contexts do not collapse with their in-flow children
|
||||||
// If first child margin top will collapse with margin-top of containing block then margin-top of child is 0
|
m_margin_state.reset();
|
||||||
margin_top = 0;
|
|
||||||
|
margin_top = box_state.margin_top;
|
||||||
|
} else {
|
||||||
|
m_margin_state.add_margin(box_state.margin_top);
|
||||||
|
m_margin_state.update_block_waiting_for_final_y_position();
|
||||||
|
|
||||||
|
margin_top = m_margin_state.current_collapsed_margin();
|
||||||
|
if (m_margin_state.has_block_container_waiting_for_final_y_position()) {
|
||||||
|
// If first child margin top will collapse with margin-top of containing block then margin-top of child is 0
|
||||||
|
margin_top = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
place_block_level_element_in_normal_flow_vertically(box, y + margin_top);
|
place_block_level_element_in_normal_flow_vertically(box, y + margin_top);
|
||||||
|
@ -567,36 +577,31 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain
|
||||||
|
|
||||||
place_block_level_element_in_normal_flow_horizontally(box, available_space);
|
place_block_level_element_in_normal_flow_horizontally(box, available_space);
|
||||||
|
|
||||||
OwnPtr<FormattingContext> independent_formatting_context;
|
if (independent_formatting_context) {
|
||||||
if (!box.is_replaced_box() && box.has_children()) {
|
// This box establishes a new formatting context. Pass control to it.
|
||||||
independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box);
|
independent_formatting_context->run(box, layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
||||||
if (independent_formatting_context) {
|
} else {
|
||||||
// Margins of elements that establish new formatting contexts do not collapse with their in-flow children
|
// This box participates in the current block container's flow.
|
||||||
m_margin_state.reset();
|
if (box.children_are_inline()) {
|
||||||
|
layout_inline_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
||||||
independent_formatting_context->run(box, layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
|
||||||
} else {
|
} else {
|
||||||
if (box.children_are_inline()) {
|
if (box_state.border_top > 0 || box_state.padding_top > 0) {
|
||||||
layout_inline_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
// margin-top of block container can't collapse with it's children if it has non zero border or padding
|
||||||
} else {
|
m_margin_state.reset();
|
||||||
if (box_state.border_top > 0 || box_state.padding_top > 0) {
|
} else if (!m_margin_state.has_block_container_waiting_for_final_y_position()) {
|
||||||
// margin-top of block container can't collapse with it's children if it has non zero border or padding
|
// margin-top of block container can be updated during children layout hence it's final y position yet to be determined
|
||||||
m_margin_state.reset();
|
m_margin_state.register_block_container_y_position_update_callback([&](CSSPixels margin_top) {
|
||||||
} else if (!m_margin_state.has_block_container_waiting_for_final_y_position()) {
|
place_block_level_element_in_normal_flow_vertically(box, margin_top + y + box_state.border_box_top());
|
||||||
// margin-top of block container can be updated during children layout hence it's final y position yet to be determined
|
});
|
||||||
m_margin_state.register_block_container_y_position_update_callback([&](CSSPixels margin_top) {
|
|
||||||
place_block_level_element_in_normal_flow_vertically(box, margin_top + y + box_state.border_box_top());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode, box_state.available_inner_space_or_constraints_from(available_space));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_height(box, available_space);
|
compute_height(box, available_space);
|
||||||
|
|
||||||
if (!margins_collapse_through(box, m_state)) {
|
if (independent_formatting_context || !margins_collapse_through(box, m_state)) {
|
||||||
if (!m_margin_state.box_last_in_flow_child_margin_bottom_collapsed) {
|
if (!m_margin_state.box_last_in_flow_child_margin_bottom_collapsed) {
|
||||||
m_margin_state.reset();
|
m_margin_state.reset();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue