diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 5c038e1e346..80c46cd5e2f 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1322,6 +1322,11 @@ void Document::update_layout(UpdateLayoutReason reason) } } + m_layout_root->for_each_in_inclusive_subtree([&](auto& layout_node) { + layout_node.recompute_containing_block({}); + return TraversalDecision::Continue; + }); + m_layout_root->for_each_in_inclusive_subtree_of_type([&](auto& child) { if (auto dom_node = child.dom_node(); dom_node && dom_node->is_element()) { child.set_has_size_containment(as(*dom_node).has_size_containment()); @@ -1338,8 +1343,8 @@ void Document::update_layout(UpdateLayoutReason reason) m_layout_root->for_each_in_inclusive_subtree_of_type([&](auto& child) { if (!child.is_absolutely_positioned()) return TraversalDecision::Continue; - if (auto* containing_block = child.containing_block()) { - auto* closest_box_that_establishes_formatting_context = containing_block; + if (auto containing_block = child.containing_block()) { + auto closest_box_that_establishes_formatting_context = containing_block; while (closest_box_that_establishes_formatting_context) { if (closest_box_that_establishes_formatting_context == m_layout_root) break; diff --git a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp index c302731501f..aab03e11b7f 100644 --- a/Libraries/LibWeb/Layout/BlockFormattingContext.cpp +++ b/Libraries/LibWeb/Layout/BlockFormattingContext.cpp @@ -638,7 +638,7 @@ CSSPixels BlockFormattingContext::compute_auto_height_for_block_level_element(Bo static CSSPixels containing_block_height_to_resolve_percentage_in_quirks_mode(Box const& box, LayoutState const& state) { // https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk - auto const* containing_block = box.containing_block(); + auto containing_block = box.containing_block(); while (containing_block) { // 1. Let element be the nearest ancestor containing block of element, if there is one. // Otherwise, return the initial containing block. @@ -925,7 +925,7 @@ BlockFormattingContext::DidIntroduceClearance BlockFormattingContext::clear_floa // Then, convert the clearance Y to a coordinate relative to the containing block of `child_box`. CSSPixels clearance_y_in_containing_block = clearance_y_in_root; - for (auto* containing_block = child_box.containing_block(); containing_block && containing_block != &root(); containing_block = containing_block->containing_block()) + 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 (inline_formatting_context.has_value()) { diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 5a9664f8e1e..6e5822d433e 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -53,6 +53,7 @@ void Node::visit_edges(Cell::Visitor& visitor) for (auto const& paintable : m_paintable) { visitor.visit(GC::Ptr { &paintable }); } + visitor.visit(m_containing_block); visitor.visit(m_pseudo_element_generator); TreeNode::visit_edges(visitor); } @@ -106,9 +107,9 @@ bool Node::can_contain_boxes_with_position_absolute() const return false; } -static Box const* nearest_ancestor_capable_of_forming_a_containing_block(Node const& node) +static GC::Ptr nearest_ancestor_capable_of_forming_a_containing_block(Node& node) { - for (auto const* ancestor = node.parent(); ancestor; ancestor = ancestor->parent()) { + for (auto* ancestor = node.parent(); ancestor; ancestor = ancestor->parent()) { if (ancestor->is_block_container() || ancestor->display().is_flex_inside() || ancestor->display().is_grid_inside() @@ -119,31 +120,36 @@ static Box const* nearest_ancestor_capable_of_forming_a_containing_block(Node co return nullptr; } -Box const* Node::containing_block() const +void Node::recompute_containing_block(Badge) { - if (is(*this)) - return nearest_ancestor_capable_of_forming_a_containing_block(*this); + if (is(*this)) { + m_containing_block = nearest_ancestor_capable_of_forming_a_containing_block(*this); + return; + } auto position = computed_values().position(); // https://drafts.csswg.org/css-position-3/#absolute-cb if (position == CSS::Positioning::Absolute) { - auto const* ancestor = parent(); + auto* ancestor = parent(); while (ancestor && !ancestor->can_contain_boxes_with_position_absolute()) ancestor = ancestor->parent(); - return static_cast(ancestor); + m_containing_block = static_cast(ancestor); + return; } - if (position == CSS::Positioning::Fixed) - return &root(); + if (position == CSS::Positioning::Fixed) { + m_containing_block = &root(); + return; + } - return nearest_ancestor_capable_of_forming_a_containing_block(*this); + m_containing_block = nearest_ancestor_capable_of_forming_a_containing_block(*this); } // returns containing block this node would have had if its position was static Box const* Node::static_position_containing_block() const { - return nearest_ancestor_capable_of_forming_a_containing_block(*this); + return nearest_ancestor_capable_of_forming_a_containing_block(const_cast(*this)); } Box const* Node::non_anonymous_containing_block() const diff --git a/Libraries/LibWeb/Layout/Node.h b/Libraries/LibWeb/Layout/Node.h index 7eb08f25da3..0bb62aba966 100644 --- a/Libraries/LibWeb/Layout/Node.h +++ b/Libraries/LibWeb/Layout/Node.h @@ -127,8 +127,10 @@ public: bool is_grid_item() const { return m_is_grid_item; } void set_grid_item(bool b) { m_is_grid_item = b; } - Box const* containing_block() const; - Box* containing_block() { return const_cast(const_cast(this)->containing_block()); } + [[nodiscard]] GC::Ptr containing_block() const { return m_containing_block; } + [[nodiscard]] GC::Ptr containing_block() { return m_containing_block; } + + void recompute_containing_block(Badge); [[nodiscard]] Box const* static_position_containing_block() const; [[nodiscard]] Box* static_position_containing_block() { return const_cast(const_cast(this)->static_position_containing_block()); } @@ -200,6 +202,8 @@ private: GC::Ref m_dom_node; PaintableList m_paintable; + GC::Ptr m_containing_block; + GC::Ptr m_pseudo_element_generator; bool m_anonymous { false };