From 268b9c5d904e41ba901c9fce556a5be1d5fea228 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 17 Oct 2022 14:41:50 +0200 Subject: LibWeb: Make the layout tree GC-allocated This removes a set of complex reference cycles between DOM, layout tree and browsing context. It also makes lifetimes much easier to reason about, as the DOM and layout trees are now free to keep each other alive. --- Userland/Libraries/LibWeb/DOM/Document.cpp | 8 +- Userland/Libraries/LibWeb/DOM/Document.h | 2 +- Userland/Libraries/LibWeb/DOM/Element.cpp | 36 +++---- Userland/Libraries/LibWeb/DOM/Element.h | 10 +- Userland/Libraries/LibWeb/DOM/Node.cpp | 9 +- Userland/Libraries/LibWeb/DOM/Node.h | 5 +- Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp | 14 ++- Userland/Libraries/LibWeb/HTML/HTMLBRElement.cpp | 4 +- Userland/Libraries/LibWeb/HTML/HTMLBRElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLCanvasElement.cpp | 4 +- Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLIFrameElement.cpp | 4 +- Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLImageElement.cpp | 4 +- Userland/Libraries/LibWeb/HTML/HTMLImageElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLInputElement.cpp | 10 +- Userland/Libraries/LibWeb/HTML/HTMLInputElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLLabelElement.cpp | 4 +- Userland/Libraries/LibWeb/HTML/HTMLLabelElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLObjectElement.cpp | 4 +- Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h | 2 +- .../Libraries/LibWeb/HTML/HTMLProgressElement.cpp | 4 +- .../Libraries/LibWeb/HTML/HTMLProgressElement.h | 2 +- Userland/Libraries/LibWeb/Layout/BlockContainer.h | 2 + Userland/Libraries/LibWeb/Layout/Box.h | 2 + Userland/Libraries/LibWeb/Layout/BreakNode.h | 2 + Userland/Libraries/LibWeb/Layout/ButtonBox.h | 2 + Userland/Libraries/LibWeb/Layout/CanvasBox.h | 2 + Userland/Libraries/LibWeb/Layout/CheckBox.h | 2 + .../LibWeb/Layout/FormAssociatedLabelableNode.h | 2 + Userland/Libraries/LibWeb/Layout/FrameBox.h | 2 + Userland/Libraries/LibWeb/Layout/ImageBox.h | 2 + .../LibWeb/Layout/InitialContainingBlock.h | 2 + Userland/Libraries/LibWeb/Layout/InlineNode.h | 2 + Userland/Libraries/LibWeb/Layout/Label.cpp | 3 - Userland/Libraries/LibWeb/Layout/Label.h | 2 + Userland/Libraries/LibWeb/Layout/LabelableNode.h | 2 + .../Libraries/LibWeb/Layout/LayoutPosition.cpp | 2 +- Userland/Libraries/LibWeb/Layout/LayoutPosition.h | 2 +- Userland/Libraries/LibWeb/Layout/ListItemBox.cpp | 8 +- Userland/Libraries/LibWeb/Layout/ListItemBox.h | 8 +- .../Libraries/LibWeb/Layout/ListItemMarkerBox.h | 2 + Userland/Libraries/LibWeb/Layout/Node.cpp | 28 +++--- Userland/Libraries/LibWeb/Layout/Node.h | 18 +++- Userland/Libraries/LibWeb/Layout/Progress.h | 2 + Userland/Libraries/LibWeb/Layout/RadioButton.h | 2 + Userland/Libraries/LibWeb/Layout/ReplacedBox.h | 2 + Userland/Libraries/LibWeb/Layout/SVGBox.h | 2 + Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h | 2 + Userland/Libraries/LibWeb/Layout/SVGGraphicsBox.h | 2 + Userland/Libraries/LibWeb/Layout/SVGSVGBox.h | 2 + Userland/Libraries/LibWeb/Layout/TableBox.h | 2 + Userland/Libraries/LibWeb/Layout/TableCellBox.h | 2 + Userland/Libraries/LibWeb/Layout/TableRowBox.h | 2 + .../Libraries/LibWeb/Layout/TableRowGroupBox.h | 2 + Userland/Libraries/LibWeb/Layout/TextNode.h | 2 + Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp | 54 +++++----- Userland/Libraries/LibWeb/Layout/TreeBuilder.h | 4 +- Userland/Libraries/LibWeb/Page/EventHandler.cpp | 2 +- .../Libraries/LibWeb/Painting/PaintableBox.cpp | 6 ++ .../Libraries/LibWeb/SVG/SVGClipPathElement.cpp | 2 +- Userland/Libraries/LibWeb/SVG/SVGClipPathElement.h | 2 +- Userland/Libraries/LibWeb/SVG/SVGDefsElement.cpp | 2 +- Userland/Libraries/LibWeb/SVG/SVGDefsElement.h | 2 +- Userland/Libraries/LibWeb/SVG/SVGGElement.cpp | 4 +- Userland/Libraries/LibWeb/SVG/SVGGElement.h | 2 +- .../Libraries/LibWeb/SVG/SVGGeometryElement.cpp | 4 +- Userland/Libraries/LibWeb/SVG/SVGGeometryElement.h | 2 +- Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp | 4 +- Userland/Libraries/LibWeb/SVG/SVGSVGElement.h | 2 +- Userland/Libraries/LibWeb/TreeNode.h | 112 +++++++-------------- 71 files changed, 257 insertions(+), 206 deletions(-) (limited to 'Userland/Libraries/LibWeb') diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index fc9afb9496..7f64a17337 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -683,7 +683,7 @@ void Document::tear_down_layout_tree() // Gather up all the layout nodes in a vector and detach them from parents // while the vector keeps them alive. - NonnullRefPtrVector layout_nodes; + Vector> layout_nodes; m_layout_root->for_each_in_inclusive_subtree([&](auto& layout_node) { layout_nodes.append(layout_node); @@ -691,8 +691,8 @@ void Document::tear_down_layout_tree() }); for (auto& layout_node : layout_nodes) { - if (layout_node.parent()) - layout_node.parent()->remove_child(layout_node); + if (layout_node->parent()) + layout_node->parent()->remove_child(*layout_node); } m_layout_root = nullptr; @@ -816,7 +816,7 @@ void Document::update_layout() if (!m_layout_root) { m_next_layout_node_serial_id = 0; Layout::TreeBuilder tree_builder; - m_layout_root = static_ptr_cast(tree_builder.build(*this)); + m_layout_root = verify_cast(*tree_builder.build(*this)); } Layout::LayoutState layout_state; diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 8762b61ae5..1ba0988cb6 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -469,7 +469,7 @@ private: JS::GCPtr m_window; - RefPtr m_layout_root; + JS::GCPtr m_layout_root; Optional m_link_color; Optional m_active_link_color; diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 319ec1c721..ac4e6c7f71 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -75,6 +75,8 @@ void Element::visit_edges(Cell::Visitor& visitor) visitor.visit(m_inline_style.ptr()); visitor.visit(m_class_list.ptr()); visitor.visit(m_shadow_root.ptr()); + for (auto& pseudo_element_layout_node : m_pseudo_element_nodes) + visitor.visit(pseudo_element_layout_node); } // https://dom.spec.whatwg.org/#dom-element-getattribute @@ -272,7 +274,7 @@ bool Element::has_class(FlyString const& class_name, CaseSensitivity case_sensit } } -RefPtr Element::create_layout_node(NonnullRefPtr style) +JS::GCPtr Element::create_layout_node(NonnullRefPtr style) { if (local_name() == "noscript" && document().is_scripting_enabled()) return nullptr; @@ -281,41 +283,41 @@ RefPtr Element::create_layout_node(NonnullRefPtr Element::create_layout_node_for_display_type(DOM::Document& document, CSS::Display const& display, NonnullRefPtr style, Element* element) +JS::GCPtr Element::create_layout_node_for_display_type(DOM::Document& document, CSS::Display const& display, NonnullRefPtr style, Element* element) { if (display.is_table_inside()) - return adopt_ref(*new Layout::TableBox(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_list_item()) - return adopt_ref(*new Layout::ListItemBox(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_table_row()) - return adopt_ref(*new Layout::TableRowBox(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_table_cell()) - return adopt_ref(*new Layout::TableCellBox(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_table_row_group() || display.is_table_header_group() || display.is_table_footer_group()) - return adopt_ref(*new Layout::TableRowGroupBox(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_table_column() || display.is_table_column_group() || display.is_table_caption()) { // FIXME: This is just an incorrect placeholder until we improve table layout support. - return adopt_ref(*new Layout::BlockContainer(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); } if (display.is_inline_outside()) { if (display.is_flow_root_inside()) - return adopt_ref(*new Layout::BlockContainer(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_flow_inside()) - return adopt_ref(*new Layout::InlineNode(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); if (display.is_flex_inside()) - return adopt_ref(*new Layout::BlockContainer(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); dbgln_if(LIBWEB_CSS_DEBUG, "FIXME: Support display: {}", display.to_string()); - return adopt_ref(*new Layout::InlineNode(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); } if (display.is_flow_inside() || display.is_flow_root_inside() || display.is_flex_inside() || display.is_grid_inside()) - return adopt_ref(*new Layout::BlockContainer(document, element, move(style))); + return document.heap().allocate_without_realm(document, element, move(style)); TODO(); } @@ -709,14 +711,14 @@ void Element::children_changed() set_needs_style_update(true); } -void Element::set_pseudo_element_node(Badge, CSS::Selector::PseudoElement pseudo_element, RefPtr pseudo_element_node) +void Element::set_pseudo_element_node(Badge, CSS::Selector::PseudoElement pseudo_element, JS::GCPtr pseudo_element_node) { - m_pseudo_element_nodes[to_underlying(pseudo_element)] = pseudo_element_node->make_weak_ptr(); + m_pseudo_element_nodes[to_underlying(pseudo_element)] = pseudo_element_node; } -RefPtr Element::get_pseudo_element_node(CSS::Selector::PseudoElement pseudo_element) const +JS::GCPtr Element::get_pseudo_element_node(CSS::Selector::PseudoElement pseudo_element) const { - return m_pseudo_element_nodes[to_underlying(pseudo_element)].strong_ref(); + return m_pseudo_element_nodes[to_underlying(pseudo_element)]; } void Element::clear_pseudo_element_nodes(Badge) diff --git a/Userland/Libraries/LibWeb/DOM/Element.h b/Userland/Libraries/LibWeb/DOM/Element.h index 95cb80dbfa..6265b1b80c 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.h +++ b/Userland/Libraries/LibWeb/DOM/Element.h @@ -142,15 +142,15 @@ public: JS::NonnullGCPtr get_bounding_client_rect() const; JS::NonnullGCPtr get_client_rects() const; - virtual RefPtr create_layout_node(NonnullRefPtr); + virtual JS::GCPtr create_layout_node(NonnullRefPtr); virtual void did_receive_focus() { } virtual void did_lose_focus() { } - static RefPtr create_layout_node_for_display_type(DOM::Document&, CSS::Display const&, NonnullRefPtr, Element*); + static JS::GCPtr create_layout_node_for_display_type(DOM::Document&, CSS::Display const&, NonnullRefPtr, Element*); - void set_pseudo_element_node(Badge, CSS::Selector::PseudoElement, RefPtr); - RefPtr get_pseudo_element_node(CSS::Selector::PseudoElement) const; + void set_pseudo_element_node(Badge, CSS::Selector::PseudoElement, JS::GCPtr); + JS::GCPtr get_pseudo_element_node(CSS::Selector::PseudoElement) const; void clear_pseudo_element_nodes(Badge); void serialize_pseudo_elements_as_json(JsonArraySerializer& children_array) const; @@ -188,7 +188,7 @@ private: Vector m_classes; - Array, CSS::Selector::PseudoElementCount> m_pseudo_element_nodes; + Array, CSS::Selector::PseudoElementCount> m_pseudo_element_nodes; }; template<> diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 7e4e83c23f..d073346ed2 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -92,6 +92,8 @@ void Node::visit_edges(Cell::Visitor& visitor) visitor.visit(m_previous_sibling.ptr()); visitor.visit(m_child_nodes); + visitor.visit(m_layout_node); + for (auto& registered_observer : m_registered_observer_list) visitor.visit(registered_observer); } @@ -823,11 +825,16 @@ bool Node::is_editable() const return parent() && parent()->is_editable(); } -void Node::set_layout_node(Badge, Layout::Node* layout_node) const +void Node::set_layout_node(Badge, JS::NonnullGCPtr layout_node) { m_layout_node = layout_node; } +void Node::detach_layout_node(Badge) +{ + m_layout_node = nullptr; +} + EventTarget* Node::get_parent(Event const&) { // FIXME: returns the node’s assigned slot, if node is assigned, and node’s parent otherwise. diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index cf2ad07a03..9e048a6892 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -156,7 +156,8 @@ public: Painting::PaintableBox const* paint_box() const; Painting::Paintable const* paintable() const; - void set_layout_node(Badge, Layout::Node*) const; + void set_layout_node(Badge, JS::NonnullGCPtr); + void detach_layout_node(Badge); virtual bool is_child_allowed(Node const&) const { return true; } @@ -623,7 +624,7 @@ protected: virtual void visit_edges(Cell::Visitor&) override; JS::GCPtr m_document; - mutable WeakPtr m_layout_node; + JS::GCPtr m_layout_node; NodeType m_type { NodeType::INVALID }; bool m_needs_style_update { false }; bool m_child_needs_style_update { false }; diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index 4f8cd120d5..c713467031 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -503,7 +503,7 @@ String BrowsingContext::selected_text() const auto selection = layout_root->selection().normalized(); - if (selection.start().layout_node == selection.end().layout_node) { + if (selection.start().layout_node.ptr() == selection.end().layout_node) { if (!is(*selection.start().layout_node)) return ""; return verify_cast(*selection.start().layout_node).text_for_rendering().substring(selection.start().index_in_node, selection.end().index_in_node - selection.start().index_in_node); @@ -518,7 +518,7 @@ String BrowsingContext::selected_text() const // Middle nodes layout_node = layout_node->next_in_pre_order(); - while (layout_node && layout_node != selection.end().layout_node) { + while (layout_node && layout_node.ptr() != selection.end().layout_node) { if (is(*layout_node)) builder.append(verify_cast(*layout_node).text_for_rendering()); else if (is(*layout_node) || is(*layout_node)) @@ -528,7 +528,7 @@ String BrowsingContext::selected_text() const } // End node - VERIFY(layout_node == selection.end().layout_node); + VERIFY(layout_node.ptr() == selection.end().layout_node); if (is(*layout_node)) { auto& text = verify_cast(*layout_node).text_for_rendering(); builder.append(text.substring(0, selection.end().index_in_node)); @@ -573,7 +573,13 @@ void BrowsingContext::select_all() last_layout_node_index_in_node = text_for_rendering.length() - 1; } - layout_root->set_selection({ { first_layout_node, 0 }, { last_layout_node, last_layout_node_index_in_node } }); + auto start = Layout::LayoutPosition { + JS::make_handle(const_cast(first_layout_node)), 0 + }; + auto end = Layout::LayoutPosition { + JS::make_handle(const_cast(last_layout_node)), last_layout_node_index_in_node + }; + layout_root->set_selection({ move(start), move(end) }); } void BrowsingContext::register_viewport_client(ViewportClient& client) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBRElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLBRElement.cpp index cd9f46b889..3dc799c88b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLBRElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLBRElement.cpp @@ -18,9 +18,9 @@ HTMLBRElement::HTMLBRElement(DOM::Document& document, DOM::QualifiedName qualifi HTMLBRElement::~HTMLBRElement() = default; -RefPtr HTMLBRElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLBRElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::BreakNode(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLBRElement.h b/Userland/Libraries/LibWeb/HTML/HTMLBRElement.h index 9b02c1d0e7..d3c8af7440 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLBRElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLBRElement.h @@ -16,7 +16,7 @@ class HTMLBRElement final : public HTMLElement { public: virtual ~HTMLBRElement() override; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; private: HTMLBRElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp index 54217cf542..9ec5a469a2 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp @@ -78,9 +78,9 @@ void HTMLCanvasElement::set_height(unsigned value) reset_context_to_default_state(); } -RefPtr HTMLCanvasElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLCanvasElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::CanvasBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } HTMLCanvasElement::HasOrCreatedContext HTMLCanvasElement::create_2d_context() diff --git a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h index 084e6e3487..c9eba32067 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLCanvasElement.h @@ -42,7 +42,7 @@ private: virtual void visit_edges(Cell::Visitor&) override; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; enum class HasOrCreatedContext { No, diff --git a/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp index 006640eabc..c3d171b55d 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp @@ -22,9 +22,9 @@ HTMLIFrameElement::HTMLIFrameElement(DOM::Document& document, DOM::QualifiedName HTMLIFrameElement::~HTMLIFrameElement() = default; -RefPtr HTMLIFrameElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLIFrameElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::FrameBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } void HTMLIFrameElement::parse_attribute(FlyString const& name, String const& value) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.h b/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.h index d7aba28e14..dd2aff3736 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLIFrameElement.h @@ -16,7 +16,7 @@ class HTMLIFrameElement final : public BrowsingContextContainer { public: virtual ~HTMLIFrameElement() override; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#will-lazy-load-element-steps bool will_lazy_load_element() const; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp index 1c14c29ee0..0d4ff16141 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -85,9 +85,9 @@ void HTMLImageElement::parse_attribute(FlyString const& name, String const& valu } } -RefPtr HTMLImageElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLImageElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::ImageBox(document(), *this, move(style), m_image_loader)); + return heap().allocate_without_realm(document(), *this, move(style), m_image_loader); } Gfx::Bitmap const* HTMLImageElement::bitmap() const diff --git a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h index 803ee9f339..3353a259b9 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLImageElement.h @@ -50,7 +50,7 @@ private: void animate(); - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; ImageLoader m_image_loader; }; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 3a613bb1af..e287da7387 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -51,21 +51,21 @@ void HTMLInputElement::visit_edges(Cell::Visitor& visitor) visitor.visit(m_selected_files); } -RefPtr HTMLInputElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLInputElement::create_layout_node(NonnullRefPtr style) { if (type_state() == TypeAttributeState::Hidden) return nullptr; if (type_state() == TypeAttributeState::SubmitButton || type_state() == TypeAttributeState::Button || type_state() == TypeAttributeState::ResetButton || type_state() == TypeAttributeState::FileUpload) - return adopt_ref(*new Layout::ButtonBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); if (type_state() == TypeAttributeState::Checkbox) - return adopt_ref(*new Layout::CheckBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); if (type_state() == TypeAttributeState::RadioButton) - return adopt_ref(*new Layout::RadioButton(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); - return adopt_ref(*new Layout::BlockContainer(document(), this, move(style))); + return heap().allocate_without_realm(document(), this, move(style)); } void HTMLInputElement::set_checked(bool checked, ChangeSource change_source) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index b04c6ef58c..b77c6cbc9e 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -48,7 +48,7 @@ class HTMLInputElement final public: virtual ~HTMLInputElement() override; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; enum class TypeAttributeState { #define __ENUMERATE_HTML_INPUT_TYPE_ATTRIBUTE(_, state) state, diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.cpp index db4a4a86ff..940d880007 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.cpp @@ -18,9 +18,9 @@ HTMLLabelElement::HTMLLabelElement(DOM::Document& document, DOM::QualifiedName q HTMLLabelElement::~HTMLLabelElement() = default; -RefPtr HTMLLabelElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLLabelElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::Label(document(), this, move(style))); + return heap().allocate_without_realm(document(), this, move(style)); } } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.h b/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.h index e322245cb5..9fd742fbb5 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLLabelElement.h @@ -16,7 +16,7 @@ class HTMLLabelElement final : public HTMLElement { public: virtual ~HTMLLabelElement() override; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; String for_() const { return attribute(HTML::AttributeNames::for_); } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp index b90a79ff08..7eecba0673 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.cpp @@ -39,7 +39,7 @@ String HTMLObjectElement::data() const return document().parse_url(data).to_string(); } -RefPtr HTMLObjectElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLObjectElement::create_layout_node(NonnullRefPtr style) { switch (m_representation) { case Representation::Children: @@ -49,7 +49,7 @@ RefPtr HTMLObjectElement::create_layout_node(NonnullRefPtrhas_image()) - return adopt_ref(*new Layout::ImageBox(document(), *this, move(style), *m_image_loader)); + return heap().allocate_without_realm(document(), *this, move(style), *m_image_loader); break; default: break; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h index 5788f85a07..a2b02b2f63 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLObjectElement.h @@ -46,7 +46,7 @@ public: private: HTMLObjectElement(DOM::Document&, DOM::QualifiedName); - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; bool has_ancestor_media_element_or_object_element_not_showing_fallback_content() const; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp index d52a7aa1fa..69a42f9d11 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.cpp @@ -23,11 +23,11 @@ HTMLProgressElement::HTMLProgressElement(DOM::Document& document, DOM::Qualified HTMLProgressElement::~HTMLProgressElement() = default; -RefPtr HTMLProgressElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr HTMLProgressElement::create_layout_node(NonnullRefPtr style) { if (style->appearance().value_or(CSS::Appearance::Auto) == CSS::Appearance::None) return HTMLElement::create_layout_node(style); - return adopt_ref(*new Layout::Progress(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } bool HTMLProgressElement::using_system_appearance() const diff --git a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h index e806f685af..414769514b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLProgressElement.h @@ -16,7 +16,7 @@ class HTMLProgressElement final : public HTMLElement { public: virtual ~HTMLProgressElement() override; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; double value() const; void set_value(double); diff --git a/Userland/Libraries/LibWeb/Layout/BlockContainer.h b/Userland/Libraries/LibWeb/Layout/BlockContainer.h index 0735a45553..4f89a7659b 100644 --- a/Userland/Libraries/LibWeb/Layout/BlockContainer.h +++ b/Userland/Libraries/LibWeb/Layout/BlockContainer.h @@ -13,6 +13,8 @@ namespace Web::Layout { // https://www.w3.org/TR/css-display/#block-container class BlockContainer : public Box { + JS_CELL(BlockContainer, Box); + public: BlockContainer(DOM::Document&, DOM::Node*, NonnullRefPtr); BlockContainer(DOM::Document&, DOM::Node*, CSS::ComputedValues); diff --git a/Userland/Libraries/LibWeb/Layout/Box.h b/Userland/Libraries/LibWeb/Layout/Box.h index a064d909c8..67cbe50573 100644 --- a/Userland/Libraries/LibWeb/Layout/Box.h +++ b/Userland/Libraries/LibWeb/Layout/Box.h @@ -18,6 +18,8 @@ struct LineBoxFragmentCoordinate { }; class Box : public NodeWithStyleAndBoxModelMetrics { + JS_CELL(Box, NodeWithStyleAndBoxModelMetrics); + public: Painting::PaintableBox const* paint_box() const; diff --git a/Userland/Libraries/LibWeb/Layout/BreakNode.h b/Userland/Libraries/LibWeb/Layout/BreakNode.h index 320f442722..f3c814b3ae 100644 --- a/Userland/Libraries/LibWeb/Layout/BreakNode.h +++ b/Userland/Libraries/LibWeb/Layout/BreakNode.h @@ -12,6 +12,8 @@ namespace Web::Layout { class BreakNode final : public NodeWithStyleAndBoxModelMetrics { + JS_CELL(BreakNode, NodeWithStyleAndBoxModelMetrics); + public: BreakNode(DOM::Document&, HTML::HTMLBRElement&, NonnullRefPtr); virtual ~BreakNode() override; diff --git a/Userland/Libraries/LibWeb/Layout/ButtonBox.h b/Userland/Libraries/LibWeb/Layout/ButtonBox.h index d80278e202..c1b0c1f106 100644 --- a/Userland/Libraries/LibWeb/Layout/ButtonBox.h +++ b/Userland/Libraries/LibWeb/Layout/ButtonBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class ButtonBox : public FormAssociatedLabelableNode { + JS_CELL(ButtonBox, FormAssociatedLabelableNode); + public: ButtonBox(DOM::Document&, HTML::HTMLInputElement&, NonnullRefPtr); virtual ~ButtonBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/CanvasBox.h b/Userland/Libraries/LibWeb/Layout/CanvasBox.h index 29da272193..89ec2c3da1 100644 --- a/Userland/Libraries/LibWeb/Layout/CanvasBox.h +++ b/Userland/Libraries/LibWeb/Layout/CanvasBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class CanvasBox : public ReplacedBox { + JS_CELL(CanvasBox, ReplacedBox); + public: CanvasBox(DOM::Document&, HTML::HTMLCanvasElement&, NonnullRefPtr); virtual ~CanvasBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/CheckBox.h b/Userland/Libraries/LibWeb/Layout/CheckBox.h index b6046f9de0..a43911cad3 100644 --- a/Userland/Libraries/LibWeb/Layout/CheckBox.h +++ b/Userland/Libraries/LibWeb/Layout/CheckBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class CheckBox : public FormAssociatedLabelableNode { + JS_CELL(CheckBox, FormAssociatedLabelableNode); + public: CheckBox(DOM::Document&, HTML::HTMLInputElement&, NonnullRefPtr); virtual ~CheckBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/FormAssociatedLabelableNode.h b/Userland/Libraries/LibWeb/Layout/FormAssociatedLabelableNode.h index 8aacbaf93a..44ee62981f 100644 --- a/Userland/Libraries/LibWeb/Layout/FormAssociatedLabelableNode.h +++ b/Userland/Libraries/LibWeb/Layout/FormAssociatedLabelableNode.h @@ -14,6 +14,8 @@ namespace Web::Layout { class FormAssociatedLabelableNode : public LabelableNode { + JS_CELL(FormAssociatedLabelableNode, LabelableNode); + public: const HTML::FormAssociatedElement& dom_node() const { return dynamic_cast(LabelableNode::dom_node()); } HTML::FormAssociatedElement& dom_node() { return dynamic_cast(LabelableNode::dom_node()); } diff --git a/Userland/Libraries/LibWeb/Layout/FrameBox.h b/Userland/Libraries/LibWeb/Layout/FrameBox.h index 96c6efdae3..2fd465213b 100644 --- a/Userland/Libraries/LibWeb/Layout/FrameBox.h +++ b/Userland/Libraries/LibWeb/Layout/FrameBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class FrameBox final : public ReplacedBox { + JS_CELL(FrameBox, ReplacedBox); + public: FrameBox(DOM::Document&, DOM::Element&, NonnullRefPtr); virtual ~FrameBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/ImageBox.h b/Userland/Libraries/LibWeb/Layout/ImageBox.h index 138cb507b8..9887312702 100644 --- a/Userland/Libraries/LibWeb/Layout/ImageBox.h +++ b/Userland/Libraries/LibWeb/Layout/ImageBox.h @@ -15,6 +15,8 @@ namespace Web::Layout { class ImageBox : public ReplacedBox , public HTML::BrowsingContext::ViewportClient { + JS_CELL(ImageBox, ReplacedBox); + public: ImageBox(DOM::Document&, DOM::Element&, NonnullRefPtr, ImageLoader const&); virtual ~ImageBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.h b/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.h index 200fe63dae..10c5f75074 100644 --- a/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.h +++ b/Userland/Libraries/LibWeb/Layout/InitialContainingBlock.h @@ -13,6 +13,8 @@ namespace Web::Layout { class InitialContainingBlock final : public BlockContainer { + JS_CELL(InitialContainingBlock, BlockContainer); + public: explicit InitialContainingBlock(DOM::Document&, NonnullRefPtr); virtual ~InitialContainingBlock() override; diff --git a/Userland/Libraries/LibWeb/Layout/InlineNode.h b/Userland/Libraries/LibWeb/Layout/InlineNode.h index bf5f35552b..e670180e93 100644 --- a/Userland/Libraries/LibWeb/Layout/InlineNode.h +++ b/Userland/Libraries/LibWeb/Layout/InlineNode.h @@ -11,6 +11,8 @@ namespace Web::Layout { class InlineNode : public NodeWithStyleAndBoxModelMetrics { + JS_CELL(InlineNode, NodeWithStyleAndBoxModelMetrics); + public: InlineNode(DOM::Document&, DOM::Element*, NonnullRefPtr); virtual ~InlineNode() override; diff --git a/Userland/Libraries/LibWeb/Layout/Label.cpp b/Userland/Libraries/LibWeb/Layout/Label.cpp index fc8ef56649..7cffc25ae4 100644 --- a/Userland/Libraries/LibWeb/Layout/Label.cpp +++ b/Userland/Libraries/LibWeb/Layout/Label.cpp @@ -38,9 +38,6 @@ void Label::handle_mouseup_on_label(Badge, Gfx::IntPoin if (!m_tracking_mouse || button != GUI::MouseButton::Primary) return; - // NOTE: Changing the checked state of the DOM node may run arbitrary JS, which could disappear this node. - NonnullRefPtr protect = *this; - if (auto* control = labeled_control(); control) { bool is_inside_control = enclosing_int_rect(control->paint_box()->absolute_rect()).contains(position); bool is_inside_label = enclosing_int_rect(paint_box()->absolute_rect()).contains(position); diff --git a/Userland/Libraries/LibWeb/Layout/Label.h b/Userland/Libraries/LibWeb/Layout/Label.h index 5cee1a986c..3723719046 100644 --- a/Userland/Libraries/LibWeb/Layout/Label.h +++ b/Userland/Libraries/LibWeb/Layout/Label.h @@ -12,6 +12,8 @@ namespace Web::Layout { class Label final : public BlockContainer { + JS_CELL(Label, BlockContainer); + public: Label(DOM::Document&, HTML::HTMLLabelElement*, NonnullRefPtr); virtual ~Label() override; diff --git a/Userland/Libraries/LibWeb/Layout/LabelableNode.h b/Userland/Libraries/LibWeb/Layout/LabelableNode.h index 6c579783c9..28f566b8dd 100644 --- a/Userland/Libraries/LibWeb/Layout/LabelableNode.h +++ b/Userland/Libraries/LibWeb/Layout/LabelableNode.h @@ -12,6 +12,8 @@ namespace Web::Layout { class LabelableNode : public ReplacedBox { + JS_CELL(LabelableNode, ReplacedBox); + public: Painting::LabelablePaintable* paintable(); Painting::LabelablePaintable const* paintable() const; diff --git a/Userland/Libraries/LibWeb/Layout/LayoutPosition.cpp b/Userland/Libraries/LibWeb/Layout/LayoutPosition.cpp index aeb4163f8d..a44cc343e7 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutPosition.cpp +++ b/Userland/Libraries/LibWeb/Layout/LayoutPosition.cpp @@ -23,7 +23,7 @@ LayoutRange LayoutRange::normalized() const { if (!is_valid()) return {}; - if (m_start.layout_node == m_end.layout_node) { + if (m_start.layout_node.ptr() == m_end.layout_node.ptr()) { if (m_start.index_in_node < m_end.index_in_node) return *this; return { m_end, m_start }; diff --git a/Userland/Libraries/LibWeb/Layout/LayoutPosition.h b/Userland/Libraries/LibWeb/Layout/LayoutPosition.h index 7ab85c4a07..755e6dd01a 100644 --- a/Userland/Libraries/LibWeb/Layout/LayoutPosition.h +++ b/Userland/Libraries/LibWeb/Layout/LayoutPosition.h @@ -16,7 +16,7 @@ namespace Web::Layout { class Node; struct LayoutPosition { - RefPtr layout_node; + JS::Handle layout_node; int index_in_node { 0 }; DOM::Position to_dom_position() const; diff --git a/Userland/Libraries/LibWeb/Layout/ListItemBox.cpp b/Userland/Libraries/LibWeb/Layout/ListItemBox.cpp index 4ac9ccb430..29f7035039 100644 --- a/Userland/Libraries/LibWeb/Layout/ListItemBox.cpp +++ b/Userland/Libraries/LibWeb/Layout/ListItemBox.cpp @@ -17,7 +17,13 @@ ListItemBox::ListItemBox(DOM::Document& document, DOM::Element* element, Nonnull ListItemBox::~ListItemBox() = default; -void ListItemBox::set_marker(RefPtr marker) +void ListItemBox::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_marker); +} + +void ListItemBox::set_marker(JS::GCPtr marker) { m_marker = move(marker); } diff --git a/Userland/Libraries/LibWeb/Layout/ListItemBox.h b/Userland/Libraries/LibWeb/Layout/ListItemBox.h index b285e2b0df..d3b79f3e3d 100644 --- a/Userland/Libraries/LibWeb/Layout/ListItemBox.h +++ b/Userland/Libraries/LibWeb/Layout/ListItemBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class ListItemBox final : public BlockContainer { + JS_CELL(ListItemBox, BlockContainer); + public: ListItemBox(DOM::Document&, DOM::Element*, NonnullRefPtr); virtual ~ListItemBox() override; @@ -20,10 +22,12 @@ public: DOM::Element const& dom_node() const { return static_cast(*BlockContainer::dom_node()); } ListItemMarkerBox const* marker() const { return m_marker; } - void set_marker(RefPtr); + void set_marker(JS::GCPtr); private: - RefPtr m_marker; + virtual void visit_edges(Cell::Visitor&) override; + + JS::GCPtr m_marker; }; } diff --git a/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h b/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h index 647f4a7f20..170a620d89 100644 --- a/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h +++ b/Userland/Libraries/LibWeb/Layout/ListItemMarkerBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class ListItemMarkerBox final : public Box { + JS_CELL(ListItemMarkerBox, Box); + public: explicit ListItemMarkerBox(DOM::Document&, CSS::ListStyleType, size_t index, NonnullRefPtr); virtual ~ListItemMarkerBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index 4a0838af27..778e3cf4a9 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -15,24 +15,26 @@ #include #include #include -#include namespace Web::Layout { Node::Node(DOM::Document& document, DOM::Node* node) - : m_dom_node(node ? node : &document) + : m_dom_node(node ? *node : document) , m_anonymous(node == nullptr) { m_serial_id = document.next_layout_node_serial_id({}); if (node) - node->set_layout_node({}, this); + node->set_layout_node({}, *this); } -Node::~Node() +Node::~Node() = default; + +void Node::visit_edges(Cell::Visitor& visitor) { - if (!is_anonymous() && m_dom_node->layout_node() == this) - m_dom_node->set_layout_node({}, nullptr); + Base::visit_edges(visitor); + visitor.visit(m_dom_node); + TreeNode::visit_edges(visitor); } // https://www.w3.org/TR/css-display-3/#out-of-flow @@ -558,16 +560,10 @@ bool Node::is_root_element() const return is(*dom_node()); } -String Node::class_name() const -{ - auto const* mangled_name = typeid(*this).name(); - return demangle({ mangled_name, strlen(mangled_name) }); -} - String Node::debug_description() const { StringBuilder builder; - builder.append(class_name().substring_view(13)); + builder.append(class_name()); if (dom_node()) { builder.appendff("<{}>", dom_node()->node_name()); if (dom_node()->is_element()) { @@ -604,13 +600,13 @@ bool Node::is_inline_block() const return display.is_inline_outside() && display.is_flow_root_inside(); } -NonnullRefPtr NodeWithStyle::create_anonymous_wrapper() const +JS::NonnullGCPtr NodeWithStyle::create_anonymous_wrapper() const { - auto wrapper = adopt_ref(*new BlockContainer(const_cast(document()), nullptr, m_computed_values.clone_inherited_values())); + auto wrapper = heap().allocate_without_realm(const_cast(document()), nullptr, m_computed_values.clone_inherited_values()); static_cast(wrapper->m_computed_values).set_display(CSS::Display(CSS::Display::Outside::Block, CSS::Display::Inside::Flow)); wrapper->m_font = m_font; wrapper->m_line_height = m_line_height; - return wrapper; + return *wrapper; } void Node::set_paintable(RefPtr paintable) diff --git a/Userland/Libraries/LibWeb/Layout/Node.h b/Userland/Libraries/LibWeb/Layout/Node.h index e8ca0bfe1b..b3a044d3f8 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.h +++ b/Userland/Libraries/LibWeb/Layout/Node.h @@ -31,7 +31,12 @@ enum class LayoutMode { IntrinsicSizing, }; -class Node : public TreeNode { +class Node + : public JS::Cell + , public TreeNode + , public Weakable { + JS_CELL(Node, JS::Cell); + public: virtual ~Node(); @@ -61,7 +66,6 @@ public: bool is_root_element() const; - String class_name() const; String debug_description() const; bool has_style() const { return m_has_style; } @@ -140,10 +144,12 @@ public: protected: Node(DOM::Document&, DOM::Node*); + virtual void visit_edges(Cell::Visitor&) override; + private: friend class NodeWithStyle; - JS::Handle m_dom_node; + JS::NonnullGCPtr m_dom_node; RefPtr m_paintable; size_t m_serial_id { 0 }; @@ -159,6 +165,8 @@ private: }; class NodeWithStyle : public Node { + JS_CELL(NodeWithStyle, Node); + public: virtual ~NodeWithStyle() override = default; @@ -171,7 +179,7 @@ public: Vector const& background_layers() const { return computed_values().background_layers(); } const CSS::AbstractImageStyleValue* list_style_image() const { return m_list_style_image; } - NonnullRefPtr create_anonymous_wrapper() const; + JS::NonnullGCPtr create_anonymous_wrapper() const; protected: NodeWithStyle(DOM::Document&, DOM::Node*, NonnullRefPtr); @@ -185,6 +193,8 @@ private: }; class NodeWithStyleAndBoxModelMetrics : public NodeWithStyle { + JS_CELL(NodeWithStyleAndBoxModelMetrics, NodeWithStyle); + public: BoxModelMetrics& box_model() { return m_box_model; } BoxModelMetrics const& box_model() const { return m_box_model; } diff --git a/Userland/Libraries/LibWeb/Layout/Progress.h b/Userland/Libraries/LibWeb/Layout/Progress.h index 0f26ae6142..a55ed6860b 100644 --- a/Userland/Libraries/LibWeb/Layout/Progress.h +++ b/Userland/Libraries/LibWeb/Layout/Progress.h @@ -12,6 +12,8 @@ namespace Web::Layout { class Progress : public LabelableNode { + JS_CELL(Progress, LabelableNode); + public: Progress(DOM::Document&, HTML::HTMLProgressElement&, NonnullRefPtr); virtual ~Progress() override; diff --git a/Userland/Libraries/LibWeb/Layout/RadioButton.h b/Userland/Libraries/LibWeb/Layout/RadioButton.h index 9be341f00a..bf30e2dde3 100644 --- a/Userland/Libraries/LibWeb/Layout/RadioButton.h +++ b/Userland/Libraries/LibWeb/Layout/RadioButton.h @@ -12,6 +12,8 @@ namespace Web::Layout { class RadioButton final : public FormAssociatedLabelableNode { + JS_CELL(RadioButton, FormAssociatedLabelableNode); + public: RadioButton(DOM::Document&, HTML::HTMLInputElement&, NonnullRefPtr); virtual ~RadioButton() override; diff --git a/Userland/Libraries/LibWeb/Layout/ReplacedBox.h b/Userland/Libraries/LibWeb/Layout/ReplacedBox.h index 28032d5aa8..f2bfa4a3cd 100644 --- a/Userland/Libraries/LibWeb/Layout/ReplacedBox.h +++ b/Userland/Libraries/LibWeb/Layout/ReplacedBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class ReplacedBox : public Box { + JS_CELL(ReplacedBox, Box); + public: ReplacedBox(DOM::Document&, DOM::Element&, NonnullRefPtr); virtual ~ReplacedBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/SVGBox.h b/Userland/Libraries/LibWeb/Layout/SVGBox.h index 30caf476d3..69bd821279 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGBox.h +++ b/Userland/Libraries/LibWeb/Layout/SVGBox.h @@ -13,6 +13,8 @@ namespace Web::Layout { class SVGBox : public Box { + JS_CELL(SVGBox, Box); + public: SVGBox(DOM::Document&, SVG::SVGElement&, NonnullRefPtr); virtual ~SVGBox() override = default; diff --git a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h index 0da419179b..d5a009c891 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h +++ b/Userland/Libraries/LibWeb/Layout/SVGGeometryBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class SVGGeometryBox final : public SVGGraphicsBox { + JS_CELL(SVGGeometryBox, SVGGraphicsBox); + public: SVGGeometryBox(DOM::Document&, SVG::SVGGeometryElement&, NonnullRefPtr); virtual ~SVGGeometryBox() override = default; diff --git a/Userland/Libraries/LibWeb/Layout/SVGGraphicsBox.h b/Userland/Libraries/LibWeb/Layout/SVGGraphicsBox.h index efa4333239..1411ef93dd 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGGraphicsBox.h +++ b/Userland/Libraries/LibWeb/Layout/SVGGraphicsBox.h @@ -13,6 +13,8 @@ namespace Web::Layout { class SVGGraphicsBox : public SVGBox { + JS_CELL(SVGGraphicsBox, SVGBox); + public: SVGGraphicsBox(DOM::Document&, SVG::SVGGraphicsElement&, NonnullRefPtr); virtual ~SVGGraphicsBox() override = default; diff --git a/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h b/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h index 55d4967c41..ee681c23c1 100644 --- a/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h +++ b/Userland/Libraries/LibWeb/Layout/SVGSVGBox.h @@ -12,6 +12,8 @@ namespace Web::Layout { class SVGSVGBox final : public ReplacedBox { + JS_CELL(SVGSVGBox, ReplacedBox); + public: SVGSVGBox(DOM::Document&, SVG::SVGSVGElement&, NonnullRefPtr); virtual ~SVGSVGBox() override = default; diff --git a/Userland/Libraries/LibWeb/Layout/TableBox.h b/Userland/Libraries/LibWeb/Layout/TableBox.h index 8fd3b9aba8..fbe3371d0c 100644 --- a/Userland/Libraries/LibWeb/Layout/TableBox.h +++ b/Userland/Libraries/LibWeb/Layout/TableBox.h @@ -11,6 +11,8 @@ namespace Web::Layout { class TableBox final : public Layout::BlockContainer { + JS_CELL(TableBox, BlockContainer); + public: TableBox(DOM::Document&, DOM::Element*, NonnullRefPtr); TableBox(DOM::Document&, DOM::Element*, CSS::ComputedValues); diff --git a/Userland/Libraries/LibWeb/Layout/TableCellBox.h b/Userland/Libraries/LibWeb/Layout/TableCellBox.h index 3662c62fa0..b63d8c5b1e 100644 --- a/Userland/Libraries/LibWeb/Layout/TableCellBox.h +++ b/Userland/Libraries/LibWeb/Layout/TableCellBox.h @@ -11,6 +11,8 @@ namespace Web::Layout { class TableCellBox final : public BlockContainer { + JS_CELL(TableCellBox, BlockContainer); + public: TableCellBox(DOM::Document&, DOM::Element*, NonnullRefPtr); TableCellBox(DOM::Document&, DOM::Element*, CSS::ComputedValues); diff --git a/Userland/Libraries/LibWeb/Layout/TableRowBox.h b/Userland/Libraries/LibWeb/Layout/TableRowBox.h index e7f6b1f783..26c7f6de7d 100644 --- a/Userland/Libraries/LibWeb/Layout/TableRowBox.h +++ b/Userland/Libraries/LibWeb/Layout/TableRowBox.h @@ -11,6 +11,8 @@ namespace Web::Layout { class TableRowBox final : public Box { + JS_CELL(TableRowBox, Box); + public: TableRowBox(DOM::Document&, DOM::Element*, NonnullRefPtr); TableRowBox(DOM::Document&, DOM::Element*, CSS::ComputedValues); diff --git a/Userland/Libraries/LibWeb/Layout/TableRowGroupBox.h b/Userland/Libraries/LibWeb/Layout/TableRowGroupBox.h index 46ac7f4997..923c662f47 100644 --- a/Userland/Libraries/LibWeb/Layout/TableRowGroupBox.h +++ b/Userland/Libraries/LibWeb/Layout/TableRowGroupBox.h @@ -11,6 +11,8 @@ namespace Web::Layout { class TableRowGroupBox final : public BlockContainer { + JS_CELL(TableRowGroupBox, BlockContainer); + public: TableRowGroupBox(DOM::Document&, DOM::Element*, NonnullRefPtr); virtual ~TableRowGroupBox() override; diff --git a/Userland/Libraries/LibWeb/Layout/TextNode.h b/Userland/Libraries/LibWeb/Layout/TextNode.h index 128f80b893..e13ca54272 100644 --- a/Userland/Libraries/LibWeb/Layout/TextNode.h +++ b/Userland/Libraries/LibWeb/Layout/TextNode.h @@ -15,6 +15,8 @@ namespace Web::Layout { class LineBoxFragment; class TextNode : public Node { + JS_CELL(TextNode, Node); + public: TextNode(DOM::Document&, DOM::Text&); virtual ~TextNode() override; diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp index ac86d9ddc6..e4c7ceb04b 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -31,7 +31,7 @@ TreeBuilder::TreeBuilder() = default; static bool has_inline_or_in_flow_block_children(Layout::Node const& layout_node) { - for (auto const* child = layout_node.first_child(); child; child = child->next_sibling()) { + for (auto child = layout_node.first_child(); child; child = child->next_sibling()) { if (child->is_inline()) return true; if (!child->is_floating() && !child->is_absolutely_positioned()) @@ -44,7 +44,7 @@ static bool has_in_flow_block_children(Layout::Node const& layout_node) { if (layout_node.children_are_inline()) return false; - for (auto const* child = layout_node.first_child(); child; child = child->next_sibling()) { + for (auto child = layout_node.first_child(); child; child = child->next_sibling()) { if (child->is_inline()) continue; if (!child->is_floating() && !child->is_absolutely_positioned()) @@ -95,15 +95,15 @@ static Layout::Node& insertion_parent_for_block_node(Layout::NodeWithStyle& layo // Parent block has inline-level children (our siblings). // First move these siblings into an anonymous wrapper block. - NonnullRefPtrVector children; - while (RefPtr child = layout_parent.first_child()) { + Vector> children; + while (JS::GCPtr child = layout_parent.first_child()) { layout_parent.remove_child(*child); - children.append(child.release_nonnull()); + children.append(*child); } layout_parent.append_child(layout_parent.create_anonymous_wrapper()); layout_parent.set_children_are_inline(false); for (auto& child : children) { - layout_parent.last_child()->append_child(child); + layout_parent.last_child()->append_child(*child); } layout_parent.last_child()->set_children_are_inline(true); // Then it's safe to insert this block into parent. @@ -166,10 +166,10 @@ void TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Se // FIXME: Handle images, and multiple values if (pseudo_element_content.type == CSS::ContentData::Type::String) { auto* text = document.heap().allocate(document.realm(), document, pseudo_element_content.data); - auto text_node = adopt_ref(*new TextNode(document, *text)); + auto text_node = document.heap().allocate_without_realm(document, *text); text_node->set_generated(true); push_parent(verify_cast(*pseudo_element_node)); - insert_node_into_inline_or_block_ancestor(text_node, text_node->display(), AppendOrPrepend::Append); + insert_node_into_inline_or_block_ancestor(*text_node, text_node->display(), AppendOrPrepend::Append); pop_parent(); } else { TODO(); @@ -195,7 +195,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& auto& document = dom_node.document(); auto& style_computer = document.style_computer(); - RefPtr layout_node; + JS::GCPtr layout_node; RefPtr style; CSS::Display display; @@ -211,12 +211,12 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& } else if (is(dom_node)) { style = style_computer.create_document_style(); display = style->display(); - layout_node = adopt_ref(*new Layout::InitialContainingBlock(static_cast(dom_node), *style)); + layout_node = document.heap().allocate_without_realm(static_cast(dom_node), *style); } else if (is(dom_node)) { - layout_node = adopt_ref(*new Layout::TextNode(document, static_cast(dom_node))); + layout_node = document.heap().allocate_without_realm(document, static_cast(dom_node)); display = CSS::Display(CSS::Display::Outside::Inline, CSS::Display::Inside::Flow); } else if (is(dom_node)) { - layout_node = adopt_ref(*new Layout::BlockContainer(document, &static_cast(dom_node), CSS::ComputedValues {})); + layout_node = document.heap().allocate_without_realm(document, &static_cast(dom_node), CSS::ComputedValues {}); display = CSS::Display(CSS::Display::Outside::Block, CSS::Display::Inside::FlowRoot); } @@ -256,10 +256,10 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& auto& element = static_cast(dom_node); int child_index = layout_node->parent()->index_of_child(*layout_node).value(); auto marker_style = style_computer.compute_style(element, CSS::Selector::PseudoElement::Marker); - auto list_item_marker = adopt_ref(*new ListItemMarkerBox(document, layout_node->computed_values().list_style_type(), child_index + 1, *marker_style)); + auto list_item_marker = document.heap().allocate_without_realm(document, layout_node->computed_values().list_style_type(), child_index + 1, *marker_style); static_cast(*layout_node).set_marker(list_item_marker); element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::Marker, list_item_marker); - layout_node->append_child(move(list_item_marker)); + layout_node->append_child(*list_item_marker); } if (is(dom_node)) { @@ -287,7 +287,7 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& } } -RefPtr TreeBuilder::build(DOM::Node& dom_node) +JS::GCPtr TreeBuilder::build(DOM::Node& dom_node) { VERIFY(dom_node.is_document()); @@ -333,7 +333,7 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root) { // The following boxes are discarded as if they were display:none: - NonnullRefPtrVector to_remove; + Vector> to_remove; // Children of a table-column. for_each_in_tree_with_internal_display(root, [&](Box& table_column) { @@ -358,7 +358,7 @@ void TreeBuilder::remove_irrelevant_boxes(NodeWithStyle& root) // - whose immediate sibling, if any, is a table-non-root box for (auto& box : to_remove) - box.parent()->remove_child(box); + box->parent()->remove_child(*box); } static bool is_table_track(CSS::Display display) @@ -424,18 +424,18 @@ static bool is_ignorable_whitespace(Layout::Node const& node) template static void for_each_sequence_of_consecutive_children_matching(NodeWithStyle& parent, Matcher matcher, Callback callback) { - NonnullRefPtrVector sequence; + Vector> sequence; auto sequence_is_all_ignorable_whitespace = [&]() -> bool { for (auto& node : sequence) { - if (!is_ignorable_whitespace(node)) + if (!is_ignorable_whitespace(*node)) return false; } return true; }; Node* next_sibling = nullptr; - for (auto* child = parent.first_child(); child; child = next_sibling) { + for (auto child = parent.first_child(); child; child = next_sibling) { next_sibling = child->next_sibling(); if (matcher(*child)) { sequence.append(*child); @@ -452,21 +452,21 @@ static void for_each_sequence_of_consecutive_children_matching(NodeWithStyle& pa } template -static void wrap_in_anonymous(NonnullRefPtrVector& sequence, Node* nearest_sibling) +static void wrap_in_anonymous(Vector>& sequence, Node* nearest_sibling) { VERIFY(!sequence.is_empty()); - auto& parent = *sequence.first().parent(); + auto& parent = *sequence.first()->parent(); auto computed_values = parent.computed_values().clone_inherited_values(); static_cast(computed_values).set_display(WrapperBoxType::static_display()); - auto wrapper = adopt_ref(*new WrapperBoxType(parent.document(), nullptr, move(computed_values))); + auto wrapper = parent.heap().template allocate_without_realm(parent.document(), nullptr, move(computed_values)); for (auto& child : sequence) { - parent.remove_child(child); - wrapper->append_child(child); + parent.remove_child(*child); + wrapper->append_child(*child); } if (nearest_sibling) - parent.insert_before(move(wrapper), *nearest_sibling); + parent.insert_before(*wrapper, *nearest_sibling); else - parent.append_child(move(wrapper)); + parent.append_child(*wrapper); } void TreeBuilder::generate_missing_child_wrappers(NodeWithStyle& root) diff --git a/Userland/Libraries/LibWeb/Layout/TreeBuilder.h b/Userland/Libraries/LibWeb/Layout/TreeBuilder.h index f3b844b240..0c0c238ad4 100644 --- a/Userland/Libraries/LibWeb/Layout/TreeBuilder.h +++ b/Userland/Libraries/LibWeb/Layout/TreeBuilder.h @@ -17,7 +17,7 @@ class TreeBuilder { public: TreeBuilder(); - RefPtr build(DOM::Node&); + JS::GCPtr build(DOM::Node&); private: struct Context { @@ -47,7 +47,7 @@ private: void insert_node_into_inline_or_block_ancestor(Layout::Node&, CSS::Display, AppendOrPrepend); void create_pseudo_element_if_needed(DOM::Element&, CSS::Selector::PseudoElement, AppendOrPrepend); - RefPtr m_layout_root; + JS::GCPtr m_layout_root; Vector m_ancestor_stack; }; diff --git a/Userland/Libraries/LibWeb/Page/EventHandler.cpp b/Userland/Libraries/LibWeb/Page/EventHandler.cpp index f60d7c624b..a5ed478ced 100644 --- a/Userland/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Userland/Libraries/LibWeb/Page/EventHandler.cpp @@ -637,7 +637,7 @@ bool EventHandler::handle_keydown(KeyCode key, unsigned modifiers, u32 code_poin if (!document->layout_node()) return false; - NonnullRefPtr layout_root = *document->layout_node(); + JS::NonnullGCPtr layout_root = *document->layout_node(); if (key == KeyCode::Key_Tab) { if (modifiers & KeyModifier::Mod_Shift) diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index 34d56620a0..c9326e047e 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -71,6 +71,12 @@ Gfx::FloatPoint PaintableBox::effective_offset() const { Gfx::FloatPoint offset; if (m_containing_line_box_fragment.has_value()) { + + // FIXME: This is a hack to deal with situations where the layout tree has been garbage collected. + // We could avoid this by making the paintable tree garbage collected as well. + if (!containing_block() || !containing_block()->paint_box()) + return offset; + auto const& fragment = containing_block()->paint_box()->line_boxes()[m_containing_line_box_fragment->line_box_index].fragments()[m_containing_line_box_fragment->fragment_index]; offset = fragment.offset(); } else { diff --git a/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.cpp index 34642e5eec..c7127dff91 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.cpp @@ -19,7 +19,7 @@ SVGClipPathElement::~SVGClipPathElement() { } -RefPtr SVGClipPathElement::create_layout_node(NonnullRefPtr) +JS::GCPtr SVGClipPathElement::create_layout_node(NonnullRefPtr) { return nullptr; } diff --git a/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.h b/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.h index 8a76da5aae..36712c18b4 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGClipPathElement.h @@ -16,7 +16,7 @@ class SVGClipPathElement final : public SVGElement { public: virtual ~SVGClipPathElement(); - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; private: SVGClipPathElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/SVG/SVGDefsElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGDefsElement.cpp index 4d4a8dfaa6..86e7d87ff0 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGDefsElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGDefsElement.cpp @@ -19,7 +19,7 @@ SVGDefsElement::~SVGDefsElement() { } -RefPtr SVGDefsElement::create_layout_node(NonnullRefPtr) +JS::GCPtr SVGDefsElement::create_layout_node(NonnullRefPtr) { return nullptr; } diff --git a/Userland/Libraries/LibWeb/SVG/SVGDefsElement.h b/Userland/Libraries/LibWeb/SVG/SVGDefsElement.h index 68e521b5e9..ddb2eeb437 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGDefsElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGDefsElement.h @@ -16,7 +16,7 @@ class SVGDefsElement final : public SVGGraphicsElement { public: virtual ~SVGDefsElement(); - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; private: SVGDefsElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/SVG/SVGGElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGElement.cpp index 20601ea4a8..25fdd0beee 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGElement.cpp @@ -16,9 +16,9 @@ SVGGElement::SVGGElement(DOM::Document& document, DOM::QualifiedName qualified_n { } -RefPtr SVGGElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr SVGGElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::SVGGraphicsBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } } diff --git a/Userland/Libraries/LibWeb/SVG/SVGGElement.h b/Userland/Libraries/LibWeb/SVG/SVGGElement.h index a2609680ca..825983c2dc 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGGElement.h @@ -16,7 +16,7 @@ class SVGGElement final : public SVGGraphicsElement { public: virtual ~SVGGElement() override = default; - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; private: SVGGElement(DOM::Document&, DOM::QualifiedName); diff --git a/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.cpp index 2c56eadce2..974f966797 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.cpp @@ -16,9 +16,9 @@ SVGGeometryElement::SVGGeometryElement(DOM::Document& document, DOM::QualifiedNa set_prototype(&Bindings::cached_web_prototype(realm(), "SVGGeometryElement")); } -RefPtr SVGGeometryElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr SVGGeometryElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::SVGGeometryBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } float SVGGeometryElement::get_total_length() diff --git a/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.h b/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.h index 70d48b7669..bf01c92a93 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGGeometryElement.h @@ -16,7 +16,7 @@ class SVGGeometryElement : public SVGGraphicsElement { WEB_PLATFORM_OBJECT(SVGGeometryElement, SVGGraphicsElement); public: - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; virtual Gfx::Path& get_path() = 0; diff --git a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp index 640b4d7edc..24a34d343d 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.cpp @@ -23,9 +23,9 @@ SVGSVGElement::SVGSVGElement(DOM::Document& document, DOM::QualifiedName qualifi set_prototype(&Bindings::cached_web_prototype(realm(), "SVGSVGElement")); } -RefPtr SVGSVGElement::create_layout_node(NonnullRefPtr style) +JS::GCPtr SVGSVGElement::create_layout_node(NonnullRefPtr style) { - return adopt_ref(*new Layout::SVGSVGBox(document(), *this, move(style))); + return heap().allocate_without_realm(document(), *this, move(style)); } void SVGSVGElement::apply_presentational_hints(CSS::StyleProperties& style) const diff --git a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h index c3518e09b3..92835066e7 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGSVGElement.h @@ -16,7 +16,7 @@ class SVGSVGElement final : public SVGGraphicsElement { WEB_PLATFORM_OBJECT(SVGSVGElement, SVGGraphicsElement); public: - virtual RefPtr create_layout_node(NonnullRefPtr) override; + virtual JS::GCPtr create_layout_node(NonnullRefPtr) override; virtual void apply_presentational_hints(CSS::StyleProperties&) const override; diff --git a/Userland/Libraries/LibWeb/TreeNode.h b/Userland/Libraries/LibWeb/TreeNode.h index 1972c4fd05..74d7a94d40 100644 --- a/Userland/Libraries/LibWeb/TreeNode.h +++ b/Userland/Libraries/LibWeb/TreeNode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2018-2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -7,54 +7,27 @@ #pragma once #include -#include #include -#include +#include #include namespace Web { template -class TreeNode : public Weakable { +class TreeNode { public: - void ref() - { - VERIFY(!m_in_removed_last_ref); - if constexpr (!IsBaseOf) { - // NOTE: DOM::Document is allowed to survive with 0 ref count, if one of its descendant nodes are alive. - VERIFY(m_ref_count); - } - ++m_ref_count; - } - - void unref() - { - VERIFY(!m_in_removed_last_ref); - VERIFY(m_ref_count); - if (!--m_ref_count) { - if constexpr (IsBaseOf) { - m_in_removed_last_ref = true; - static_cast(this)->removed_last_ref(); - } else { - delete static_cast(this); - } - return; - } - } - int ref_count() const { return m_ref_count; } - T* parent() { return m_parent; } - const T* parent() const { return m_parent; } + T const* parent() const { return m_parent; } bool has_children() const { return m_first_child; } T* next_sibling() { return m_next_sibling; } T* previous_sibling() { return m_previous_sibling; } T* first_child() { return m_first_child; } T* last_child() { return m_last_child; } - const T* next_sibling() const { return m_next_sibling; } - const T* previous_sibling() const { return m_previous_sibling; } - const T* first_child() const { return m_first_child; } - const T* last_child() const { return m_last_child; } + T const* next_sibling() const { return m_next_sibling; } + T const* previous_sibling() const { return m_previous_sibling; } + T const* first_child() const { return m_first_child; } + T const* last_child() const { return m_last_child; } size_t child_count() const { @@ -75,7 +48,7 @@ public: return nullptr; } - const T* child_at_index(int index) const + T const* child_at_index(int index) const { return const_cast(this)->child_at_index(index); } @@ -90,7 +63,7 @@ public: return index; } - Optional index_of_child(const T& search_child) + Optional index_of_child(T const& search_child) { VERIFY(search_child.parent() == this); size_t index = 0; @@ -106,7 +79,7 @@ public: } template - Optional index_of_child(const T& search_child) + Optional index_of_child(T const& search_child) { VERIFY(search_child.parent() == this); size_t index = 0; @@ -130,12 +103,12 @@ public: bool is_following(TreeNode const&) const; - void append_child(NonnullRefPtr node); - void prepend_child(NonnullRefPtr node); - void insert_before(NonnullRefPtr node, RefPtr child); - void remove_child(NonnullRefPtr node); + void append_child(JS::NonnullGCPtr node); + void prepend_child(JS::NonnullGCPtr node); + void insert_before(JS::NonnullGCPtr node, JS::GCPtr child); + void remove_child(JS::NonnullGCPtr node); - bool is_child_allowed(const T&) const { return true; } + bool is_child_allowed(T const&) const { return true; } T* next_in_pre_order() { @@ -230,7 +203,7 @@ public: template IterationDecision for_each_in_inclusive_subtree(Callback callback) const { - if (callback(static_cast(*this)) == IterationDecision::Break) + if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; for (auto* child = first_child(); child; child = child->next_sibling()) { if (child->for_each_in_inclusive_subtree(callback) == IterationDecision::Break) @@ -254,7 +227,7 @@ public: template IterationDecision for_each_in_inclusive_subtree_of_type(Callback callback) { - if (is(static_cast(*this))) { + if (is(static_cast(*this))) { if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; } @@ -268,8 +241,8 @@ public: template IterationDecision for_each_in_inclusive_subtree_of_type(Callback callback) const { - if (is(static_cast(*this))) { - if (callback(static_cast(*this)) == IterationDecision::Break) + if (is(static_cast(*this))) { + if (callback(static_cast(*this)) == IterationDecision::Break) return IterationDecision::Break; } for (auto* child = first_child(); child; child = child->next_sibling()) { @@ -348,7 +321,7 @@ public: } template - const U* next_sibling_of_type() const + U const* next_sibling_of_type() const { return const_cast(this)->template next_sibling_of_type(); } @@ -364,7 +337,7 @@ public: } template - const U* previous_sibling_of_type() const + U const* previous_sibling_of_type() const { return const_cast(this)->template previous_sibling_of_type(); } @@ -380,13 +353,13 @@ public: } template - const U* first_child_of_type() const + U const* first_child_of_type() const { return const_cast(this)->template first_child_of_type(); } template - const U* last_child_of_type() const + U const* last_child_of_type() const { return const_cast(this)->template last_child_of_type(); } @@ -418,7 +391,7 @@ public: } template - const U* first_ancestor_of_type() const + U const* first_ancestor_of_type() const { return const_cast(this)->template first_ancestor_of_type(); } @@ -442,25 +415,21 @@ public: return false; } - ~TreeNode() - { - VERIFY(!m_parent); - T* next_child = nullptr; - for (auto* child = m_first_child; child; child = next_child) { - next_child = child->m_next_sibling; - child->m_parent = nullptr; - child->unref(); - } - } + ~TreeNode() = default; protected: TreeNode() = default; - bool m_deletion_has_begun { false }; - bool m_in_removed_last_ref { false }; + void visit_edges(JS::Cell::Visitor& visitor) + { + visitor.visit(m_parent); + visitor.visit(m_first_child); + visitor.visit(m_last_child); + visitor.visit(m_next_sibling); + visitor.visit(m_previous_sibling); + } private: - int m_ref_count { 1 }; T* m_parent { nullptr }; T* m_first_child { nullptr }; T* m_last_child { nullptr }; @@ -469,7 +438,7 @@ private: }; template -inline void TreeNode::remove_child(NonnullRefPtr node) +inline void TreeNode::remove_child(JS::NonnullGCPtr node) { VERIFY(node->m_parent == this); @@ -488,12 +457,10 @@ inline void TreeNode::remove_child(NonnullRefPtr node) node->m_next_sibling = nullptr; node->m_previous_sibling = nullptr; node->m_parent = nullptr; - - node->unref(); } template -inline void TreeNode::append_child(NonnullRefPtr node) +inline void TreeNode::append_child(JS::NonnullGCPtr node) { VERIFY(!node->m_parent); @@ -507,11 +474,10 @@ inline void TreeNode::append_child(NonnullRefPtr node) m_last_child = node.ptr(); if (!m_first_child) m_first_child = m_last_child; - [[maybe_unused]] auto& rc = node.leak_ref(); } template -inline void TreeNode::insert_before(NonnullRefPtr node, RefPtr child) +inline void TreeNode::insert_before(JS::NonnullGCPtr node, JS::GCPtr child) { if (!child) return append_child(move(node)); @@ -531,11 +497,10 @@ inline void TreeNode::insert_before(NonnullRefPtr node, RefPtr child) child->m_previous_sibling = node; node->m_parent = static_cast(this); - [[maybe_unused]] auto& rc = node.leak_ref(); } template -inline void TreeNode::prepend_child(NonnullRefPtr node) +inline void TreeNode::prepend_child(JS::NonnullGCPtr node) { VERIFY(!node->m_parent); @@ -550,7 +515,6 @@ inline void TreeNode::prepend_child(NonnullRefPtr node) if (!m_last_child) m_last_child = m_first_child; node->inserted_into(static_cast(*this)); - [[maybe_unused]] auto& rc = node.leak_ref(); static_cast(this)->children_changed(); } -- cgit v1.2.3