diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index edf3427e88..b84e1ef4b8 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -32,38 +32,25 @@ bool BlockFormattingContext::is_initial() const return is(root()); } -void BlockFormattingContext::run(Box& box, LayoutMode layout_mode) +void BlockFormattingContext::run(Box&, LayoutMode layout_mode) { if (is_initial()) { layout_initial_containing_block(layout_mode); return; } - // FIXME: BFC currently computes the width+height of the target box. - // This is necessary to be able to place absolutely positioned descendants. - // The same work is also done by the parent BFC for each of its blocks.. + if (root().children_are_inline()) + layout_inline_children(root(), layout_mode); + else + layout_block_level_children(root(), layout_mode); +} - if (layout_mode == LayoutMode::Default) - compute_width(box); +void BlockFormattingContext::parent_context_did_dimension_child_root_box() +{ + for (auto& box : m_absolutely_positioned_boxes) + layout_absolutely_positioned_element(box); - if (box.children_are_inline()) { - layout_inline_children(verify_cast(box), layout_mode); - } else { - layout_block_level_children(verify_cast(box), layout_mode); - } - - if (layout_mode == LayoutMode::Default) { - compute_height(box); - - box.for_each_child_of_type([&](auto& child_box) { - if (child_box.is_absolutely_positioned()) { - layout_absolutely_positioned_element(child_box); - } - return IterationDecision::Continue; - }); - } - - apply_transformations_to_children(box); + apply_transformations_to_children(root()); } void BlockFormattingContext::apply_transformations_to_children(Box& box) @@ -384,18 +371,24 @@ void BlockFormattingContext::compute_position(Box& box) void BlockFormattingContext::layout_inline_children(BlockContainer& block_container, LayoutMode layout_mode) { + VERIFY(block_container.children_are_inline()); + InlineFormattingContext context(block_container, *this); context.run(block_container, layout_mode); } void BlockFormattingContext::layout_block_level_children(BlockContainer& block_container, LayoutMode layout_mode) { + VERIFY(!block_container.children_are_inline()); + float content_height = 0; float content_width = 0; block_container.for_each_child_of_type([&](Box& child_box) { - if (child_box.is_absolutely_positioned()) + if (child_box.is_absolutely_positioned()) { + m_absolutely_positioned_boxes.append(child_box); return IterationDecision::Continue; + } // NOTE: ListItemMarkerBoxes are placed by their corresponding ListItemBox. if (is(child_box)) @@ -410,7 +403,15 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer& block_c if (is(child_box) || is(child_box)) place_block_level_element_in_normal_flow_vertically(child_box, block_container); - (void)layout_inside(child_box, layout_mode); + OwnPtr independent_formatting_context; + if (child_box.can_have_children()) { + independent_formatting_context = create_independent_formatting_context_if_needed(child_box); + if (independent_formatting_context) + independent_formatting_context->run(child_box, layout_mode); + else + layout_block_level_children(verify_cast(child_box), layout_mode); + } + compute_height(child_box); if (child_box.computed_values().position() == CSS::Position::Relative) @@ -426,6 +427,10 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer& block_c content_height = max(content_height, child_box.effective_offset().y() + child_box.content_height() + child_box.box_model().margin_box().bottom); content_width = max(content_width, child_box.content_width()); + + if (independent_formatting_context) + independent_formatting_context->parent_context_did_dimension_child_root_box(); + return IterationDecision::Continue; }); diff --git a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h index 403bad5f1a..fffb595003 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h @@ -33,8 +33,11 @@ public: BlockContainer& root() { return static_cast(context_box()); } BlockContainer const& root() const { return static_cast(context_box()); } -protected: + virtual void parent_context_did_dimension_child_root_box() override; + static void compute_height(Box&); + +protected: void compute_position(Box&); private: @@ -69,6 +72,8 @@ private: FloatSideData m_left_floats; FloatSideData m_right_floats; + + Vector m_absolutely_positioned_boxes; }; } diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp index 3f9b6670b8..7077952ddc 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.cpp @@ -616,7 +616,7 @@ void FormattingContext::layout_absolutely_positioned_element(Box& box) auto specified_width = box.computed_values().width().resolved(box, width_of_containing_block).resolved_or_auto(box); compute_width_for_absolutely_positioned_element(box); - (void)layout_inside(box, LayoutMode::Default); + auto independent_formatting_context = layout_inside(box, LayoutMode::Default); compute_height_for_absolutely_positioned_element(box); box_model.margin.left = box.computed_values().margin().left.resolved(box, width_of_containing_block).resolved_or_auto(box).to_px(box); @@ -676,6 +676,9 @@ void FormattingContext::layout_absolutely_positioned_element(Box& box) } box.set_offset(used_offset); + + if (independent_formatting_context) + independent_formatting_context->parent_context_did_dimension_child_root_box(); } void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(ReplacedBox& box) diff --git a/Userland/Libraries/LibWeb/Layout/FormattingContext.h b/Userland/Libraries/LibWeb/Layout/FormattingContext.h index 2ff1e452ed..48f3216cba 100644 --- a/Userland/Libraries/LibWeb/Layout/FormattingContext.h +++ b/Userland/Libraries/LibWeb/Layout/FormattingContext.h @@ -43,6 +43,8 @@ public: OwnPtr create_independent_formatting_context_if_needed(Box& child_box); + virtual void parent_context_did_dimension_child_root_box() { } + protected: FormattingContext(Type, Box&, FormattingContext* parent = nullptr); diff --git a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp index 420e408318..43bc2abe11 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp +++ b/Userland/Libraries/LibWeb/Layout/InlineFormattingContext.cpp @@ -141,14 +141,17 @@ void InlineFormattingContext::dimension_box_on_line(Box& box, LayoutMode layout_ auto container_width = CSS::Length::make_px(containing_block().content_width()); inline_block.set_content_width(inline_block.computed_values().width().resolved(box, container_width).resolved_or_zero(inline_block).to_px(inline_block)); } - (void)layout_inside(inline_block, layout_mode); + auto independent_formatting_context = layout_inside(inline_block, layout_mode); if (inline_block.computed_values().height().is_length() && inline_block.computed_values().height().length().is_undefined_or_auto()) { // FIXME: (10.6.6) If 'height' is 'auto', the height depends on the element's descendants per 10.6.7. + BlockFormattingContext::compute_height(inline_block); } else { auto container_height = CSS::Length::make_px(containing_block().content_height()); inline_block.set_content_height(inline_block.computed_values().height().resolved(box, container_height).resolved_or_zero(inline_block).to_px(inline_block)); } + + independent_formatting_context->parent_context_did_dimension_child_root_box(); return; }