diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index d218d55a1d..e7193a61cd 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -1003,7 +1003,7 @@ void Document::update_layout() Layout::AvailableSize::make_definite(viewport_rect.height()))); } - layout_state.commit(); + layout_state.commit(*m_layout_root); // Broadcast the current viewport rect to any new paintables, so they know whether they're visible or not. browsing_context()->inform_all_viewport_clients_about_the_current_viewport_rect(); diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp index 956a947633..c8c7a6ff4e 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.cpp @@ -196,7 +196,24 @@ void LayoutState::resolve_relative_positions(Vector(*node.paintable()); + if (parent_paintable) { + // In case this was a relayout of an existing tree, we need to remove the paintable from its old parent first. + if (auto* old_parent = paintable.parent()) { + old_parent->remove_child(paintable); + } + parent_paintable->append_child(paintable); + } + for (auto* child = node.first_child(); child; child = child->next_sibling()) { + build_paint_tree(*child, &paintable); + } +} + +void LayoutState::commit(Box& root) { // Only the top-level LayoutState should ever be committed. VERIFY(!m_parent); @@ -215,12 +232,14 @@ void LayoutState::commit() node.box_model().border = { used_values.border_top, used_values.border_right, used_values.border_bottom, used_values.border_left }; node.box_model().margin = { used_values.margin_top, used_values.margin_right, used_values.margin_bottom, used_values.margin_left }; - node.set_paintable(node.create_paintable()); + auto paintable = node.create_paintable(); + + node.set_paintable(paintable); // For boxes, transfer all the state needed for painting. if (is(node)) { auto& box = static_cast(node); - auto& paintable_box = const_cast(*box.paintable_box()); + auto& paintable_box = static_cast(*paintable); paintable_box.set_offset(used_values.offset); paintable_box.set_content_size(used_values.content_width(), used_values.content_height()); if (used_values.override_borders_data().has_value()) { @@ -255,6 +274,11 @@ void LayoutState::commit() } } + for (auto* text_node : text_nodes) + text_node->set_paintable(text_node->create_paintable()); + + build_paint_tree(root); + // Measure overflow in scroll containers. for (auto& it : used_values_per_layout_node) { auto& used_values = *it.value; @@ -263,9 +287,6 @@ void LayoutState::commit() auto const& box = static_cast(used_values.node()); measure_scrollable_overflow(box); } - - for (auto* text_node : text_nodes) - text_node->set_paintable(text_node->create_paintable()); } void LayoutState::UsedValues::set_node(NodeWithStyleAndBoxModelMetrics& node, UsedValues const* containing_block_used_values) diff --git a/Userland/Libraries/LibWeb/Layout/LayoutState.h b/Userland/Libraries/LibWeb/Layout/LayoutState.h index 0715490181..c580c220bc 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutState.h +++ b/Userland/Libraries/LibWeb/Layout/LayoutState.h @@ -148,7 +148,8 @@ struct LayoutState { Optional m_table_cell_coordinates; }; - void commit(); + // Commits the used values produced by layout and builds a paintable tree. + void commit(Box& root); // NOTE: get_mutable() will CoW the UsedValues if it's inherited from an ancestor state; UsedValues& get_mutable(NodeWithStyleAndBoxModelMetrics const&); diff --git a/Userland/Libraries/LibWeb/Painting/Paintable.cpp b/Userland/Libraries/LibWeb/Painting/Paintable.cpp index 1872ff39f1..c7a913e256 100644 --- a/Userland/Libraries/LibWeb/Painting/Paintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/Paintable.cpp @@ -44,38 +44,6 @@ Optional Paintable::hit_test(CSSPixelPoint, HitTestType) const return {}; } -Paintable const* Paintable::first_child() const -{ - auto const* layout_child = m_layout_node->first_child(); - for (; layout_child && !layout_child->paintable(); layout_child = layout_child->next_sibling()) - ; - return layout_child ? layout_child->paintable() : nullptr; -} - -Paintable const* Paintable::next_sibling() const -{ - auto const* layout_node = m_layout_node->next_sibling(); - for (; layout_node && !layout_node->paintable(); layout_node = layout_node->next_sibling()) - ; - return layout_node ? layout_node->paintable() : nullptr; -} - -Paintable const* Paintable::last_child() const -{ - auto const* layout_child = m_layout_node->last_child(); - for (; layout_child && !layout_child->paintable(); layout_child = layout_child->previous_sibling()) - ; - return layout_child ? layout_child->paintable() : nullptr; -} - -Paintable const* Paintable::previous_sibling() const -{ - auto const* layout_node = m_layout_node->previous_sibling(); - for (; layout_node && !layout_node->paintable(); layout_node = layout_node->previous_sibling()) - ; - return layout_node ? layout_node->paintable() : nullptr; -} - StackingContext const* Paintable::stacking_context_rooted_here() const { if (!layout_node().is_box()) diff --git a/Userland/Libraries/LibWeb/Painting/Paintable.h b/Userland/Libraries/LibWeb/Painting/Paintable.h index 0ccb448256..ab1ceaddbd 100644 --- a/Userland/Libraries/LibWeb/Painting/Paintable.h +++ b/Userland/Libraries/LibWeb/Painting/Paintable.h @@ -48,17 +48,14 @@ enum class HitTestType { TextCursor, // Clicking past the right/bottom edge of text will still hit the text }; -class Paintable : public JS::Cell { +class Paintable + : public JS::Cell + , public TreeNode { JS_CELL(Paintable, Cell); public: virtual ~Paintable() = default; - Paintable const* first_child() const; - Paintable const* last_child() const; - Paintable const* next_sibling() const; - Paintable const* previous_sibling() const; - template TraversalDecision for_each_in_inclusive_subtree_of_type(Callback callback) const {