diff --git a/Tests/LibWeb/Layout/expected/block-and-inline/percentage-height-box-nested-into-percentage-height-box.txt b/Tests/LibWeb/Layout/expected/block-and-inline/percentage-height-box-nested-into-percentage-height-box.txt new file mode 100644 index 00000000000..3e7eca42455 --- /dev/null +++ b/Tests/LibWeb/Layout/expected/block-and-inline/percentage-height-box-nested-into-percentage-height-box.txt @@ -0,0 +1,9 @@ +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 784x300 children: not-inline + BlockContainer
at (8,8) content-size 784x300 children: not-inline + +ViewportPaintable (Viewport<#document>) [0,0 800x600] + PaintableWithLines (BlockContainer) [0,0 800x600] + PaintableWithLines (BlockContainer) [8,8 784x300] + PaintableWithLines (BlockContainer
) [8,8 784x300] diff --git a/Tests/LibWeb/Layout/input/block-and-inline/percentage-height-box-nested-into-percentage-height-box.html b/Tests/LibWeb/Layout/input/block-and-inline/percentage-height-box-nested-into-percentage-height-box.html new file mode 100644 index 00000000000..d2a6e604f7c --- /dev/null +++ b/Tests/LibWeb/Layout/input/block-and-inline/percentage-height-box-nested-into-percentage-height-box.html @@ -0,0 +1,9 @@ +
\ No newline at end of file diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index a9b8c0c65d1..85dafe1d8f4 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -407,24 +407,48 @@ void BlockFormattingContext::compute_width_for_block_level_replaced_element_in_n box_state.padding_right = padding_right; } -void BlockFormattingContext::compute_height(Box const& box, AvailableSpace const& available_space, FormattingContext const* box_formatting_context) +void BlockFormattingContext::resolve_used_height_if_not_treated_as_auto(Box const& box, AvailableSpace const& available_space) { - auto const& computed_values = box.computed_values(); - auto& box_used_values = m_state.get_mutable(box); + if (should_treat_height_as_auto(box, available_space)) { + return; + } + + auto const& computed_values = box.computed_values(); + auto& box_state = m_state.get_mutable(box); + + auto height = calculate_inner_height(box, available_space.height, box.computed_values().height()); + + if (!should_treat_max_height_as_none(box, available_space.height)) { + if (!computed_values.max_height().is_auto()) { + auto max_height = calculate_inner_height(box, available_space.height, computed_values.max_height()); + height = min(height, max_height); + } + } + if (!computed_values.min_height().is_auto()) { + height = max(height, calculate_inner_height(box, available_space.height, computed_values.min_height())); + } + + box_state.set_content_height(height); + box_state.set_has_definite_height(true); +} + +void BlockFormattingContext::resolve_used_height_if_treated_as_auto(Box const& box, AvailableSpace const& available_space, FormattingContext const* box_formatting_context) +{ + if (!should_treat_height_as_auto(box, available_space)) { + return; + } + + auto const& computed_values = box.computed_values(); + auto& box_state = m_state.get_mutable(box); - // Then work out what the height is, based on box type and CSS properties. CSSPixels height = 0; if (box_is_sized_as_replaced_element(box)) { height = compute_height_for_replaced_element(box, available_space); } else { - if (should_treat_height_as_auto(box, available_space)) { - if (box_formatting_context) { - height = box_formatting_context->automatic_content_height(); - } else { - height = compute_auto_height_for_block_level_element(box, m_state.get(box).available_inner_space_or_constraints_from(available_space)); - } + if (box_formatting_context) { + height = box_formatting_context->automatic_content_height(); } else { - height = calculate_inner_height(box, available_space.height, computed_values.height()); + height = compute_auto_height_for_block_level_element(box, m_state.get(box).available_inner_space_or_constraints_from(available_space)); } } @@ -446,8 +470,6 @@ void BlockFormattingContext::compute_height(Box const& box, AvailableSpace const // https://quirks.spec.whatwg.org/#the-html-element-fills-the-viewport-quirk // FIXME: Handle vertical writing mode. - auto& box_state = m_state.get_mutable(box); - // 1. Let margins be sum of the used values of the margin-left and margin-right properties of element // if element has a vertical writing mode, otherwise let margins be the sum of the used values of // the margin-top and margin-bottom properties of element. @@ -461,10 +483,10 @@ void BlockFormattingContext::compute_height(Box const& box, AvailableSpace const height = max(size, height); // NOTE: The height of the root element when affected by this quirk is considered to be definite. - box_used_values.set_has_definite_height(true); + box_state.set_has_definite_height(true); } - box_used_values.set_content_height(height); + box_state.set_content_height(height); } void BlockFormattingContext::layout_inline_children(BlockContainer const& block_container, AvailableSpace const& available_space) @@ -616,7 +638,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain // NOTE: In quirks mode, the html element's height matches the viewport so it can be treated as definite if (box_state.has_definite_height() || box_is_html_element_in_quirks_mode) { - compute_height(box, available_space); + resolve_used_height_if_treated_as_auto(box, available_space); } auto independent_formatting_context = create_independent_formatting_context_if_needed(m_state, m_layout_mode, box); @@ -650,9 +672,12 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain place_block_level_element_in_normal_flow_horizontally(box, available_space); + resolve_used_height_if_not_treated_as_auto(box, available_space); + // NOTE: Flex containers with `auto` height are treated as `max-content`, so we can compute their height early. - if (box.is_replaced_box() || box.display().is_flex_inside()) - compute_height(box, available_space); + if (box.is_replaced_box() || box.display().is_flex_inside()) { + resolve_used_height_if_treated_as_auto(box, available_space); + } // Before we insert the children of a list item we need to know the location of the marker. // If we do not do this then left-floating elements inside the list item will push the marker to the right, @@ -701,7 +726,7 @@ void BlockFormattingContext::layout_block_level_box(Box const& box, BlockContain // Tables already set their height during the independent formatting context run. When multi-line text cells are involved, using different // available space here than during the independent formatting context run can result in different line breaks and thus a different height. if (!box.display().is_table_inside()) { - compute_height(box, available_space, independent_formatting_context); + resolve_used_height_if_treated_as_auto(box, available_space, independent_formatting_context); } if (independent_formatting_context || !margins_collapse_through(box, m_state)) { @@ -939,12 +964,15 @@ void BlockFormattingContext::layout_floating_box(Box const& box, BlockContainer compute_width(box, available_space); + resolve_used_height_if_not_treated_as_auto(box, available_space); + // NOTE: Flex containers with `auto` height are treated as `max-content`, so we can compute their height early. - if (box.is_replaced_box() || box.display().is_flex_inside()) - compute_height(box, available_space); + if (box.is_replaced_box() || box.display().is_flex_inside()) { + resolve_used_height_if_treated_as_auto(box, available_space); + } auto independent_formatting_context = layout_inside(box, m_layout_mode, box_state.available_inner_space_or_constraints_from(available_space)); - compute_height(box, available_space, independent_formatting_context); + resolve_used_height_if_treated_as_auto(box, available_space, independent_formatting_context); // First we place the box normally (to get the right y coordinate.) // If we have a LineBuilder, we're in the middle of inline layout, otherwise this is block layout. diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index aae4039046f..06985760213 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -37,7 +37,8 @@ public: virtual void parent_context_did_dimension_child_root_box() override; - void compute_height(Box const&, AvailableSpace const&, FormattingContext const* box_formatting_context = nullptr); + void resolve_used_height_if_not_treated_as_auto(Box const&, AvailableSpace const&); + void resolve_used_height_if_treated_as_auto(Box const&, AvailableSpace const&, FormattingContext const* box_formatting_context = nullptr); SpaceUsedAndContainingMarginForFloats space_used_and_containing_margin_for_floats(CSSPixels y) const; [[nodiscard]] SpaceUsedByFloats intrusion_by_floats_into_box(Box const&, CSSPixels y_in_box) const; diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 374954ee5bc..2d3400d6733 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -177,16 +177,18 @@ void InlineFormattingContext::dimension_box_on_line(Box const& box, LayoutMode l box_state.set_content_width(width); + parent().resolve_used_height_if_not_treated_as_auto(box, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_indefinite())); + // NOTE: Flex containers with `auto` height are treated as `max-content`, so we can compute their height early. if (box_state.has_definite_height() || box.display().is_flex_inside()) - parent().compute_height(box, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_indefinite())); + parent().resolve_used_height_if_treated_as_auto(box, AvailableSpace(AvailableSize::make_definite(width), AvailableSize::make_indefinite())); auto independent_formatting_context = layout_inside(box, layout_mode, box_state.available_inner_space_or_constraints_from(*m_available_space)); auto const& height_value = box.computed_values().height(); if (should_treat_height_as_auto(box, *m_available_space)) { // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. - parent().compute_height(box, AvailableSpace(AvailableSize::make_indefinite(), AvailableSize::make_indefinite())); + parent().resolve_used_height_if_treated_as_auto(box, AvailableSpace(AvailableSize::make_indefinite(), AvailableSize::make_indefinite())); } else { auto inner_height = calculate_inner_height(box, AvailableSize::make_definite(m_containing_block_used_values.content_height()), height_value); box_state.set_content_height(inner_height);