diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/box-with-clearance-and-margin-top.txt b/Tests/LibWeb/Layout/expected/block-and-inline/box-with-clearance-and-margin-top.txt new file mode 100644 index 00000000000..9792ca841d5 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/box-with-clearance-and-margin-top.txt @@ -0,0 +1,7 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x600 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x110 children: not-inline + BlockContainer
at (8,8) content-size 784x110 children: not-inline + BlockContainer at (8,8) content-size 100x100 floating [BFC] children: not-inline + BlockContainer at (8,108) content-size 10x10 children: not-inline + BlockContainer at (8,218) content-size 49x49 floating [BFC] children: not-inline diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/clear-both-without-introducing-clearance.txt b/Tests/LibWeb/Layout/expected/block-and-inline/clear-both-without-introducing-clearance.txt new file mode 100644 index 00000000000..f48d4f2c779 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/clear-both-without-introducing-clearance.txt @@ -0,0 +1,14 @@ +Viewport <#document> at (0,0) content-size 800x600 children: not-inline + BlockContainer at (0,0) content-size 800x125.9375 [BFC] children: not-inline + BlockContainer at (8,8) content-size 784x109.9375 children: not-inline + BlockContainer at (8,8) content-size 784x17.46875 children: inline + line 0 width: 46.15625, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 5, rect: [8,8 46.15625x17.46875] + "upper" + TextNode <#text> + BlockContainer at (8,100.46875) content-size 784x0 children: not-inline + BlockContainer at (8,100.46875) content-size 784x17.46875 children: inline + line 0 width: 43.359375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 + frag 0 from TextNode start: 0, length: 5, rect: [8,100.46875 43.359375x17.46875] + "lower" + TextNode <#text> diff --git a/Tests/LibWeb/Layout/input/block-and-inline/box-with-clearance-and-margin-top.html b/Tests/LibWeb/Layout/input/block-and-inline/box-with-clearance-and-margin-top.html new file mode 100644 index 00000000000..eb55f92bd49 --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/box-with-clearance-and-margin-top.html @@ -0,0 +1,24 @@ + +
\ No newline at end of file diff --git a/Tests/LibWeb/Layout/input/block-and-inline/clear-both-without-introducing-clearance.html b/Tests/LibWeb/Layout/input/block-and-inline/clear-both-without-introducing-clearance.html new file mode 100644 index 00000000000..582a1cacb57 --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/clear-both-without-introducing-clearance.html @@ -0,0 +1,8 @@ +
upper
lower \ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index b5ac2bfaffc..51941ab76ca 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -536,26 +536,27 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain resolve_vertical_box_model_metrics(box, m_state); - auto const y = m_y_offset_of_current_block_container.value(); - if (box.is_floating()) { + auto const y = m_y_offset_of_current_block_container.value(); auto margin_top = !m_margin_state.has_block_container_waiting_for_final_y_position() ? m_margin_state.current_collapsed_margin() : 0; layout_floating_box(box, block_container, layout_mode, available_space, margin_top + y); bottom_of_lowest_margin_box = max(bottom_of_lowest_margin_box, box_state.offset.y() + box_state.content_height() + box_state.margin_box_bottom()); return; } + m_margin_state.add_margin(box_state.margin_top); + auto introduce_clearance = clear_floating_boxes(box); + if (introduce_clearance == DidIntroduceClearance::Yes) + m_margin_state.reset(); + + auto const y = m_y_offset_of_current_block_container.value(); + if (box_state.has_definite_height()) { compute_height(box, available_space); } - if (box.computed_values().clear() != CSS::Clear::None) { - m_margin_state.reset(); - } - auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, box); - m_margin_state.add_margin(box_state.margin_top); m_margin_state.update_block_waiting_for_final_y_position(); CSSPixels margin_top = m_margin_state.current_collapsed_margin(); @@ -592,7 +593,9 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain } else if (!m_margin_state.has_block_container_waiting_for_final_y_position()) { // 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()); + if (introduce_clearance == DidIntroduceClearance::No) { + place_block_level_element_in_normal_flow_vertically(box, margin_top + y); + } }); } @@ -689,10 +692,10 @@ CSSPixels BlockFormattingContext::BlockMarginState::current_collapsed_margin() c return collapsed_margin; } -void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically(Box const& child_box, CSSPixels y) +BlockFormattingContext::DidIntroduceClearance BlockFormattingContext::clear_floating_boxes(Box const& child_box) { - auto& box_state = m_state.get_mutable(child_box); auto const& computed_values = child_box.computed_values(); + auto result = DidIntroduceClearance::No; auto clear_floating_boxes = [&](FloatSideData& float_side) { if (!float_side.current_boxes.is_empty()) { @@ -714,9 +717,11 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically for (auto* containing_block = child_box.containing_block(); containing_block && containing_block != &root(); containing_block = containing_block->containing_block()) clearance_y_in_containing_block -= m_state.get(*containing_block).offset.y(); - if (clearance_y_in_containing_block > y) + if (clearance_y_in_containing_block > m_y_offset_of_current_block_container.value()) { + result = DidIntroduceClearance::Yes; m_y_offset_of_current_block_container = clearance_y_in_containing_block; - y = max(y, clearance_y_in_containing_block); + } + float_side.clear(); } }; @@ -727,8 +732,13 @@ void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically if ((computed_values.clear() == CSS::Clear::Right || computed_values.clear() == CSS::Clear::Both) && !child_box.is_flex_item()) clear_floating_boxes(m_right_floats); - y += box_state.border_box_top(); + return result; +} +void BlockFormattingContext::place_block_level_element_in_normal_flow_vertically(Box const& child_box, CSSPixels y) +{ + auto& box_state = m_state.get_mutable(child_box); + y += box_state.border_box_top(); box_state.set_content_offset(CSSPixelPoint { box_state.offset.x(), y.value() }); } diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index 8b8c04426ae..63ce6d6e0ee 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -72,6 +72,13 @@ private: void layout_list_item_marker(ListItemBox const&); + enum class DidIntroduceClearance { + Yes, + No, + }; + + [[nodiscard]] DidIntroduceClearance clear_floating_boxes(Box const& child_box); + enum class FloatSide { Left, Right,