Explorar o código

LibWeb: Stop sizing the context root box in formatting contexts

Until now, some formatting contexts (BFC in particular) have been
assigning size to the root box. This is really the responsibility of the
parent formatting context, so let's stop doing it.

To keep position:absolute working, parent formatting contexts now notify
child contexts when the child's root box has been sized. (Note that the
important thing here is for the child root to have its final used height
before it's able to place bottom-relative boxes.)

This breaks flexbox layout in some ways, but we'll have to address those
by improving the spec compliance of FFC.)
Andreas Kling %!s(int64=3) %!d(string=hai) anos
pai
achega
0532d7d255

+ 31 - 26
Userland/Libraries/LibWeb/Layout/BlockFormattingContext.cpp

@@ -32,38 +32,25 @@ bool BlockFormattingContext::is_initial() const
     return is<InitialContainingBlock>(root());
     return is<InitialContainingBlock>(root());
 }
 }
 
 
-void BlockFormattingContext::run(Box& box, LayoutMode layout_mode)
+void BlockFormattingContext::run(Box&, LayoutMode layout_mode)
 {
 {
     if (is_initial()) {
     if (is_initial()) {
         layout_initial_containing_block(layout_mode);
         layout_initial_containing_block(layout_mode);
         return;
         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 (layout_mode == LayoutMode::Default)
-        compute_width(box);
-
-    if (box.children_are_inline()) {
-        layout_inline_children(verify_cast<BlockContainer>(box), layout_mode);
-    } else {
-        layout_block_level_children(verify_cast<BlockContainer>(box), layout_mode);
-    }
-
-    if (layout_mode == LayoutMode::Default) {
-        compute_height(box);
+    if (root().children_are_inline())
+        layout_inline_children(root(), layout_mode);
+    else
+        layout_block_level_children(root(), layout_mode);
+}
 
 
-        box.for_each_child_of_type<Box>([&](auto& child_box) {
-            if (child_box.is_absolutely_positioned()) {
-                layout_absolutely_positioned_element(child_box);
-            }
-            return IterationDecision::Continue;
-        });
-    }
+void BlockFormattingContext::parent_context_did_dimension_child_root_box()
+{
+    for (auto& box : m_absolutely_positioned_boxes)
+        layout_absolutely_positioned_element(box);
 
 
-    apply_transformations_to_children(box);
+    apply_transformations_to_children(root());
 }
 }
 
 
 void BlockFormattingContext::apply_transformations_to_children(Box& box)
 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)
 void BlockFormattingContext::layout_inline_children(BlockContainer& block_container, LayoutMode layout_mode)
 {
 {
+    VERIFY(block_container.children_are_inline());
+
     InlineFormattingContext context(block_container, *this);
     InlineFormattingContext context(block_container, *this);
     context.run(block_container, layout_mode);
     context.run(block_container, layout_mode);
 }
 }
 
 
 void BlockFormattingContext::layout_block_level_children(BlockContainer& block_container, LayoutMode 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_height = 0;
     float content_width = 0;
     float content_width = 0;
 
 
     block_container.for_each_child_of_type<Box>([&](Box& child_box) {
     block_container.for_each_child_of_type<Box>([&](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;
             return IterationDecision::Continue;
+        }
 
 
         // NOTE: ListItemMarkerBoxes are placed by their corresponding ListItemBox.
         // NOTE: ListItemMarkerBoxes are placed by their corresponding ListItemBox.
         if (is<ListItemMarkerBox>(child_box))
         if (is<ListItemMarkerBox>(child_box))
@@ -410,7 +403,15 @@ void BlockFormattingContext::layout_block_level_children(BlockContainer& block_c
         if (is<ReplacedBox>(child_box) || is<BlockContainer>(child_box))
         if (is<ReplacedBox>(child_box) || is<BlockContainer>(child_box))
             place_block_level_element_in_normal_flow_vertically(child_box, block_container);
             place_block_level_element_in_normal_flow_vertically(child_box, block_container);
 
 
-        (void)layout_inside(child_box, layout_mode);
+        OwnPtr<FormattingContext> 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<BlockContainer>(child_box), layout_mode);
+        }
+
         compute_height(child_box);
         compute_height(child_box);
 
 
         if (child_box.computed_values().position() == CSS::Position::Relative)
         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_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());
         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;
         return IterationDecision::Continue;
     });
     });
 
 

+ 6 - 1
Userland/Libraries/LibWeb/Layout/BlockFormattingContext.h

@@ -33,8 +33,11 @@ public:
     BlockContainer& root() { return static_cast<BlockContainer&>(context_box()); }
     BlockContainer& root() { return static_cast<BlockContainer&>(context_box()); }
     BlockContainer const& root() const { return static_cast<BlockContainer const&>(context_box()); }
     BlockContainer const& root() const { return static_cast<BlockContainer const&>(context_box()); }
 
 
-protected:
+    virtual void parent_context_did_dimension_child_root_box() override;
+
     static void compute_height(Box&);
     static void compute_height(Box&);
+
+protected:
     void compute_position(Box&);
     void compute_position(Box&);
 
 
 private:
 private:
@@ -69,6 +72,8 @@ private:
 
 
     FloatSideData m_left_floats;
     FloatSideData m_left_floats;
     FloatSideData m_right_floats;
     FloatSideData m_right_floats;
+
+    Vector<Box&> m_absolutely_positioned_boxes;
 };
 };
 
 
 }
 }

+ 4 - 1
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);
     auto specified_width = box.computed_values().width().resolved(box, width_of_containing_block).resolved_or_auto(box);
 
 
     compute_width_for_absolutely_positioned_element(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);
     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);
     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);
     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)
 void FormattingContext::compute_height_for_absolutely_positioned_replaced_element(ReplacedBox& box)

+ 2 - 0
Userland/Libraries/LibWeb/Layout/FormattingContext.h

@@ -43,6 +43,8 @@ public:
 
 
     OwnPtr<FormattingContext> create_independent_formatting_context_if_needed(Box& child_box);
     OwnPtr<FormattingContext> create_independent_formatting_context_if_needed(Box& child_box);
 
 
+    virtual void parent_context_did_dimension_child_root_box() { }
+
 protected:
 protected:
     FormattingContext(Type, Box&, FormattingContext* parent = nullptr);
     FormattingContext(Type, Box&, FormattingContext* parent = nullptr);
 
 

+ 4 - 1
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());
             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));
             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()) {
         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.
             // 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 {
         } else {
             auto container_height = CSS::Length::make_px(containing_block().content_height());
             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));
             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;
         return;
     }
     }