diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index 195658fb77f..82b518edfa4 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -267,49 +267,6 @@ void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_n box.set_width(compute_width_for_replaced_element(box)); } -float BlockFormattingContext::compute_auto_height_for_block_level_element(const Box& box) -{ - Optional top; - Optional bottom; - - if (box.children_are_inline()) { - // If it only has inline-level children, the height is the distance between - // the top of the topmost line box and the bottom of the bottommost line box. - if (!box.line_boxes().is_empty()) { - for (auto& fragment : box.line_boxes().first().fragments()) { - if (!top.has_value() || fragment.offset().y() < top.value()) - top = fragment.offset().y(); - } - for (auto& fragment : box.line_boxes().last().fragments()) { - if (!bottom.has_value() || (fragment.offset().y() + fragment.height()) > bottom.value()) - bottom = fragment.offset().y() + fragment.height(); - } - } - } else { - // If it has block-level children, the height is the distance between - // the top margin-edge of the topmost block-level child box - // and the bottom margin-edge of the bottommost block-level child box. - box.for_each_child_of_type([&](Layout::Box& child_box) { - if (child_box.is_absolutely_positioned()) - return IterationDecision::Continue; - if ((box.computed_values().overflow_y() == CSS::Overflow::Visible) && child_box.is_floating()) - return IterationDecision::Continue; - - float child_box_top = child_box.effective_offset().y() - child_box.box_model().margin_box().top; - float child_box_bottom = child_box.effective_offset().y() + child_box.height() + child_box.box_model().margin_box().bottom; - - if (!top.has_value() || child_box_top < top.value()) - top = child_box_top; - - if (!bottom.has_value() || child_box_bottom > bottom.value()) - bottom = child_box_bottom; - - return IterationDecision::Continue; - }); - } - return bottom.value_or(0) - top.value_or(0); -} - void BlockFormattingContext::compute_height(Box& box) { auto& computed_values = box.computed_values(); diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index 7cc5d6fac53..13852f74deb 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -56,8 +56,6 @@ private: void compute_width_for_block_level_replaced_element_in_normal_flow(ReplacedBox&); - [[nodiscard]] static float compute_auto_height_for_block_level_element(const Box&); - void layout_initial_containing_block(LayoutMode); void layout_block_level_children(Box&, LayoutMode); diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index 5df5ba312f8..dfda823476c 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -180,6 +180,63 @@ static Gfx::FloatSize solve_replaced_size_constraint(float w, float h, const Rep return { w, h }; } +float FormattingContext::compute_auto_height_for_block_level_element(const Box& box) +{ + Optional top; + Optional bottom; + + if (box.children_are_inline()) { + // If it only has inline-level children, the height is the distance between + // the top of the topmost line box and the bottom of the bottommost line box. + if (!box.line_boxes().is_empty()) { + for (auto& fragment : box.line_boxes().first().fragments()) { + if (!top.has_value() || fragment.offset().y() < top.value()) + top = fragment.offset().y(); + } + for (auto& fragment : box.line_boxes().last().fragments()) { + if (!bottom.has_value() || (fragment.offset().y() + fragment.height()) > bottom.value()) + bottom = fragment.offset().y() + fragment.height(); + } + } + } else { + // If it has block-level children, the height is the distance between + // the top margin-edge of the topmost block-level child box + // and the bottom margin-edge of the bottommost block-level child box. + box.for_each_child_of_type([&](Layout::Box& child_box) { + if (child_box.is_absolutely_positioned()) + return IterationDecision::Continue; + if ((box.computed_values().overflow_y() == CSS::Overflow::Visible) && child_box.is_floating()) + return IterationDecision::Continue; + + float child_box_top = child_box.effective_offset().y() - child_box.box_model().margin_box().top; + float child_box_bottom = child_box.effective_offset().y() + child_box.height() + child_box.box_model().margin_box().bottom; + + if (!top.has_value() || child_box_top < top.value()) + top = child_box_top; + + if (!bottom.has_value() || child_box_bottom > bottom.value()) + bottom = child_box_bottom; + + return IterationDecision::Continue; + }); + // In addition, if the element has any floating descendants + // whose bottom margin edge is below the element's bottom content edge, + // then the height is increased to include those edges. + box.for_each_child_of_type([&](Layout::Box& child_box) { + if (!child_box.is_floating()) + return IterationDecision::Continue; + + float child_box_bottom = child_box.effective_offset().y() + child_box.height(); + + if (!bottom.has_value() || child_box_bottom > bottom.value()) + bottom = child_box_bottom; + + return IterationDecision::Continue; + }); + } + return bottom.value_or(0) - top.value_or(0); +} + float FormattingContext::tentative_width_for_replaced_element(const ReplacedBox& box, const CSS::Length& width) { auto& containing_block = *box.containing_block(); @@ -487,7 +544,16 @@ void FormattingContext::compute_height_for_absolutely_positioned_non_replaced_el box.box_model().padding.top = computed_values.padding().top.resolved_or_zero(box, containing_block.width()).to_px(box); box.box_model().padding.bottom = computed_values.padding().bottom.resolved_or_zero(box, containing_block.width()).to_px(box); - if (specified_height.is_auto() && !specified_top.is_auto() && !specified_bottom.is_auto()) { + if (specified_height.is_auto() && !specified_top.is_auto() && specified_bottom.is_auto()) { + const auto& margin = box.box_model().margin; + const auto& padding = box.box_model().padding; + const auto& border = box.box_model().border; + + specified_height = CSS::Length(compute_auto_height_for_block_level_element(box), CSS::Length::Type::Px); + box.box_model().offset.bottom = containing_block.height() - specified_height.to_px(box) - specified_top.to_px(box) - margin.top - padding.top - border.top - margin.bottom - padding.bottom - border.bottom; + } + + else if (specified_height.is_auto() && !specified_top.is_auto() && !specified_bottom.is_auto()) { const auto& margin = box.box_model().margin; const auto& padding = box.box_model().padding; const auto& border = box.box_model().border; diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index aad024a04e8..213be06a1b9 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -58,6 +58,7 @@ protected: float preferred_minimum_width { 0 }; }; + static float compute_auto_height_for_block_level_element(const Box& box); static float tentative_width_for_replaced_element(const ReplacedBox&, const CSS::Length& width); static float tentative_height_for_replaced_element(const ReplacedBox&, const CSS::Length& width);