From e7c2f0dd52167e8b80ab97cc82770409f8324a7b Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 23 May 2025 17:22:48 +0100 Subject: [PATCH] LibWeb: Make PseudoElement a class in its own right It's getting a bit large and complicated to be a struct hidden in DOM::Element. --- Libraries/LibWeb/CMakeLists.txt | 1 + Libraries/LibWeb/DOM/Element.cpp | 44 +++++++++-------------- Libraries/LibWeb/DOM/Element.h | 22 ++---------- Libraries/LibWeb/DOM/PseudoElement.cpp | 26 ++++++++++++++ Libraries/LibWeb/DOM/PseudoElement.h | 50 ++++++++++++++++++++++++++ Libraries/LibWeb/Forward.h | 1 + 6 files changed, 96 insertions(+), 48 deletions(-) create mode 100644 Libraries/LibWeb/DOM/PseudoElement.cpp create mode 100644 Libraries/LibWeb/DOM/PseudoElement.h diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 94cb388934c..28cfa5721ac 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -250,6 +250,7 @@ set(SOURCES DOM/ParentNode.cpp DOM/Position.cpp DOM/ProcessingInstruction.cpp + DOM/PseudoElement.cpp DOM/QualifiedName.cpp DOM/Range.cpp DOM/ShadowRoot.cpp diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index eb875d4f243..d725ca80e1a 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -91,9 +91,6 @@ namespace Web::DOM { -GC_DEFINE_ALLOCATOR(Element::PseudoElement); -GC_DEFINE_ALLOCATOR(Element::PseudoElementTreeNode); - Element::Element(Document& document, DOM::QualifiedName qualified_name) : ParentNode(document, NodeType::ELEMENT_NODE) , m_qualified_name(move(qualified_name)) @@ -133,15 +130,6 @@ void Element::visit_edges(Cell::Visitor& visitor) } } -void Element::PseudoElement::visit_edges(Cell::Visitor& visitor) -{ - Base::visit_edges(visitor); - - visitor.visit(cascaded_properties); - visitor.visit(computed_properties); - visitor.visit(layout_node); -} - // https://dom.spec.whatwg.org/#dom-element-getattribute Optional Element::get_attribute(FlyString const& name) const { @@ -780,14 +768,14 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style() for (auto i = 0; i < to_underlying(CSS::PseudoElement::KnownPseudoElementCount); i++) { auto pseudo_element_type = static_cast(i); auto pseudo_element = get_pseudo_element(pseudo_element_type); - if (!pseudo_element.has_value() || !pseudo_element->layout_node) + if (!pseudo_element.has_value() || !pseudo_element->layout_node()) continue; auto pseudo_element_style = pseudo_element_computed_properties(pseudo_element_type); if (!pseudo_element_style) continue; - if (auto* node_with_style = dynamic_cast(pseudo_element->layout_node.ptr())) { + if (auto node_with_style = pseudo_element->layout_node()) { node_with_style->apply_style(*pseudo_element_style); if (invalidation.repaint && node_with_style->first_paintable()) node_with_style->first_paintable()->set_needs_display(); @@ -1392,13 +1380,13 @@ void Element::set_pseudo_element_node(Badge, CSS::PseudoEle return; } - ensure_pseudo_element(pseudo_element).layout_node = move(pseudo_element_node); + ensure_pseudo_element(pseudo_element).set_layout_node(move(pseudo_element_node)); } GC::Ptr Element::get_pseudo_element_node(CSS::PseudoElement pseudo_element) const { if (auto element_data = get_pseudo_element(pseudo_element); element_data.has_value()) - return element_data->layout_node; + return element_data->layout_node(); return nullptr; } @@ -1409,9 +1397,9 @@ bool Element::affected_by_pseudo_class(CSS::PseudoClass pseudo_class) const } if (m_pseudo_element_data) { for (auto& pseudo_element : *m_pseudo_element_data) { - if (!pseudo_element.value->computed_properties) + if (!pseudo_element.value->computed_properties()) continue; - if (pseudo_element.value->computed_properties->has_attempted_match_against_pseudo_class(pseudo_class)) + if (pseudo_element.value->computed_properties()->has_attempted_match_against_pseudo_class(pseudo_class)) return true; } } @@ -1578,7 +1566,7 @@ bool Element::has_pseudo_elements() const { if (m_pseudo_element_data) { for (auto& pseudo_element : *m_pseudo_element_data) { - if (pseudo_element.value->layout_node) + if (pseudo_element.value->layout_node()) return true; } } @@ -1589,7 +1577,7 @@ void Element::clear_pseudo_element_nodes(Badge) { if (m_pseudo_element_data) { for (auto& pseudo_element : *m_pseudo_element_data) { - pseudo_element.value->layout_node = nullptr; + pseudo_element.value->set_layout_node(nullptr); } } } @@ -2903,7 +2891,7 @@ GC::Ptr Element::cascaded_properties(Optionalcascaded_properties; + return pseudo_element_data->cascaded_properties(); return nullptr; } return m_cascaded_properties; @@ -2914,7 +2902,7 @@ void Element::set_cascaded_properties(Optional pseudo_elemen if (pseudo_element.has_value()) { if (pseudo_element.value() >= CSS::PseudoElement::KnownPseudoElementCount) return; - ensure_pseudo_element(pseudo_element.value()).cascaded_properties = cascaded_properties; + ensure_pseudo_element(pseudo_element.value()).set_cascaded_properties(cascaded_properties); } else { m_cascaded_properties = cascaded_properties; } @@ -2934,18 +2922,18 @@ void Element::set_pseudo_element_computed_properties(CSS::PseudoElement pseudo_e if (!CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element)) return; - ensure_pseudo_element(pseudo_element).computed_properties = style; + ensure_pseudo_element(pseudo_element).set_computed_properties(style); } GC::Ptr Element::pseudo_element_computed_properties(CSS::PseudoElement type) { auto pseudo_element = get_pseudo_element(type); if (pseudo_element.has_value()) - return pseudo_element->computed_properties; + return pseudo_element->computed_properties(); return {}; } -Optional Element::get_pseudo_element(CSS::PseudoElement type) const +Optional Element::get_pseudo_element(CSS::PseudoElement type) const { if (!m_pseudo_element_data) return {}; @@ -2961,7 +2949,7 @@ Optional Element::get_pseudo_element(CSS::PseudoElement return *(pseudo_element.value()); } -Element::PseudoElement& Element::ensure_pseudo_element(CSS::PseudoElement type) const +PseudoElement& Element::ensure_pseudo_element(CSS::PseudoElement type) const { if (!m_pseudo_element_data) m_pseudo_element_data = make(); @@ -2990,7 +2978,7 @@ void Element::set_custom_properties(Optional pseudo_element, return; } - ensure_pseudo_element(pseudo_element.value()).custom_properties = move(custom_properties); + ensure_pseudo_element(pseudo_element.value()).set_custom_properties(move(custom_properties)); } HashMap const& Element::custom_properties(Optional pseudo_element) const @@ -3000,7 +2988,7 @@ HashMap const& Element::custom_properties(Optiona VERIFY(CSS::Selector::PseudoElementSelector::is_known_pseudo_element_type(pseudo_element.value())); - return ensure_pseudo_element(pseudo_element.value()).custom_properties; + return ensure_pseudo_element(pseudo_element.value()).custom_properties(); } // https://drafts.csswg.org/cssom-view/#dom-element-scroll diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index ad86a24274c..6647d657bf6 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -564,25 +565,6 @@ private: GC::Ptr m_computed_properties; HashMap m_custom_properties; - struct PseudoElement : public JS::Cell { - GC_CELL(PseudoElement, JS::Cell); - GC_DECLARE_ALLOCATOR(PseudoElement); - - GC::Ptr layout_node; - GC::Ptr cascaded_properties; - GC::Ptr computed_properties; - HashMap custom_properties; - - private: - virtual void visit_edges(JS::Cell::Visitor&) override; - }; - // https://drafts.csswg.org/css-view-transitions/#pseudo-element-tree - struct PseudoElementTreeNode - : public PseudoElement - , TreeNode { - GC_CELL(PseudoElementTreeNode, PseudoElement); - GC_DECLARE_ALLOCATOR(PseudoElementTreeNode); - }; using PseudoElementData = HashMap>; mutable OwnPtr m_pseudo_element_data; Optional get_pseudo_element(CSS::PseudoElement) const; @@ -673,7 +655,7 @@ inline bool Element::has_pseudo_element(CSS::PseudoElement type) const auto pseudo_element = m_pseudo_element_data->get(type); if (!pseudo_element.has_value()) return false; - return pseudo_element.value()->layout_node; + return pseudo_element.value()->layout_node(); } bool is_valid_namespace_prefix(FlyString const&); diff --git a/Libraries/LibWeb/DOM/PseudoElement.cpp b/Libraries/LibWeb/DOM/PseudoElement.cpp new file mode 100644 index 00000000000..b2da434ea21 --- /dev/null +++ b/Libraries/LibWeb/DOM/PseudoElement.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Web::DOM { + +GC_DEFINE_ALLOCATOR(PseudoElement); +GC_DEFINE_ALLOCATOR(PseudoElementTreeNode); + +void PseudoElement::visit_edges(JS::Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + + visitor.visit(m_cascaded_properties); + visitor.visit(m_computed_properties); + visitor.visit(m_layout_node); +} + +} diff --git a/Libraries/LibWeb/DOM/PseudoElement.h b/Libraries/LibWeb/DOM/PseudoElement.h new file mode 100644 index 00000000000..5c51523fec5 --- /dev/null +++ b/Libraries/LibWeb/DOM/PseudoElement.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Web::DOM { + +class PseudoElement : public JS::Cell { + GC_CELL(PseudoElement, JS::Cell); + GC_DECLARE_ALLOCATOR(PseudoElement); + + GC::Ptr layout_node() const { return m_layout_node; } + void set_layout_node(GC::Ptr value) { m_layout_node = value; } + + GC::Ptr cascaded_properties() const { return m_cascaded_properties; } + void set_cascaded_properties(GC::Ptr value) { m_cascaded_properties = value; } + + GC::Ptr computed_properties() const { return m_computed_properties; } + void set_computed_properties(GC::Ptr value) { m_computed_properties = value; } + + HashMap const& custom_properties() const { return m_custom_properties; } + void set_custom_properties(HashMap value) { m_custom_properties = move(value); } + + virtual void visit_edges(JS::Cell::Visitor&) override; + +private: + GC::Ptr m_layout_node; + GC::Ptr m_cascaded_properties; + GC::Ptr m_computed_properties; + HashMap m_custom_properties; +}; + +// https://drafts.csswg.org/css-view-transitions/#pseudo-element-tree +class PseudoElementTreeNode final + : public PseudoElement + , TreeNode { + GC_CELL(PseudoElementTreeNode, PseudoElement); + GC_DECLARE_ALLOCATOR(PseudoElementTreeNode); +}; + +} diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 1eeed6c6340..e41f2b7a9de 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -373,6 +373,7 @@ class NodeList; class ParentNode; class Position; class ProcessingInstruction; +class PseudoElement; class Range; class RegisteredObserver; class ShadowRoot;