LibWeb: Combine Element's pseudo-element data together

Rather than maintain two dynamically-allocated arrays of data for
pseudo-elements, put them in a single array, which is easier to manage.
This commit is contained in:
Sam Atkins 2024-07-29 14:38:29 +01:00 committed by Andreas Kling
commit f23f0721bd
Notes: github-actions[bot] 2024-07-30 07:46:37 +00:00
2 changed files with 43 additions and 28 deletions

View file

@ -101,8 +101,10 @@ void Element::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_class_list); visitor.visit(m_class_list);
visitor.visit(m_shadow_root); visitor.visit(m_shadow_root);
visitor.visit(m_custom_element_definition); visitor.visit(m_custom_element_definition);
if (m_pseudo_element_nodes) { if (m_pseudo_element_data) {
visitor.visit(m_pseudo_element_nodes->span()); for (auto& pseudo_element : *m_pseudo_element_data) {
visitor.visit(pseudo_element.layout_node);
}
} }
if (m_registered_intersection_observers) { if (m_registered_intersection_observers) {
for (auto& registered_intersection_observers : *m_registered_intersection_observers) for (auto& registered_intersection_observers : *m_registered_intersection_observers)
@ -1087,34 +1089,36 @@ void Element::children_changed()
void Element::set_pseudo_element_node(Badge<Layout::TreeBuilder>, CSS::Selector::PseudoElement::Type pseudo_element, JS::GCPtr<Layout::Node> pseudo_element_node) void Element::set_pseudo_element_node(Badge<Layout::TreeBuilder>, CSS::Selector::PseudoElement::Type pseudo_element, JS::GCPtr<Layout::Node> pseudo_element_node)
{ {
if (!m_pseudo_element_nodes) { auto existing_pseudo_element = get_pseudo_element(pseudo_element);
if (!pseudo_element_node) if (!existing_pseudo_element.has_value() && !pseudo_element_node)
return; return;
m_pseudo_element_nodes = make<PseudoElementLayoutNodes>();
}
(*m_pseudo_element_nodes)[to_underlying(pseudo_element)] = pseudo_element_node; ensure_pseudo_element(pseudo_element).layout_node = move(pseudo_element_node);
} }
JS::GCPtr<Layout::Node> Element::get_pseudo_element_node(CSS::Selector::PseudoElement::Type pseudo_element) const JS::GCPtr<Layout::Node> Element::get_pseudo_element_node(CSS::Selector::PseudoElement::Type pseudo_element) const
{ {
if (!m_pseudo_element_nodes) if (auto element_data = get_pseudo_element(pseudo_element); element_data.has_value())
return element_data->layout_node;
return nullptr; return nullptr;
return (*m_pseudo_element_nodes)[to_underlying(pseudo_element)];
} }
void Element::clear_pseudo_element_nodes(Badge<Layout::TreeBuilder>) void Element::clear_pseudo_element_nodes(Badge<Layout::TreeBuilder>)
{ {
m_pseudo_element_nodes = nullptr; if (m_pseudo_element_data) {
for (auto& pseudo_element : *m_pseudo_element_data) {
pseudo_element.layout_node = nullptr;
}
}
} }
void Element::serialize_pseudo_elements_as_json(JsonArraySerializer<StringBuilder>& children_array) const void Element::serialize_pseudo_elements_as_json(JsonArraySerializer<StringBuilder>& children_array) const
{ {
if (!m_pseudo_element_nodes) if (!m_pseudo_element_data)
return; return;
for (size_t i = 0; i < m_pseudo_element_nodes->size(); ++i) { for (size_t i = 0; i < m_pseudo_element_data->size(); ++i) {
auto& pseudo_element_node = (*m_pseudo_element_nodes)[i]; auto& pseudo_element = (*m_pseudo_element_data)[i].layout_node;
if (!pseudo_element_node) if (!pseudo_element)
continue; continue;
auto object = MUST(children_array.add_object()); auto object = MUST(children_array.add_object());
MUST(object.add("name"sv, MUST(String::formatted("::{}", CSS::Selector::PseudoElement::name(static_cast<CSS::Selector::PseudoElement::Type>(i)))))); MUST(object.add("name"sv, MUST(String::formatted("::{}", CSS::Selector::PseudoElement::name(static_cast<CSS::Selector::PseudoElement::Type>(i))))));
@ -2219,11 +2223,18 @@ void Element::set_computed_css_values(RefPtr<CSS::StyleProperties> style)
computed_css_values_changed(); computed_css_values_changed();
} }
auto Element::pseudo_element_custom_properties() const -> PseudoElementCustomProperties& Optional<Element::PseudoElement&> Element::get_pseudo_element(CSS::Selector::PseudoElement::Type type) const
{ {
if (!m_pseudo_element_custom_properties) if (!m_pseudo_element_data)
m_pseudo_element_custom_properties = make<PseudoElementCustomProperties>(); return {};
return *m_pseudo_element_custom_properties; return m_pseudo_element_data->at(to_underlying(type));
}
Element::PseudoElement& Element::ensure_pseudo_element(CSS::Selector::PseudoElement::Type type) const
{
if (!m_pseudo_element_data)
m_pseudo_element_data = make<PseudoElementData>();
return m_pseudo_element_data->at(to_underlying(type));
} }
void Element::set_custom_properties(Optional<CSS::Selector::PseudoElement::Type> pseudo_element, HashMap<FlyString, CSS::StyleProperty> custom_properties) void Element::set_custom_properties(Optional<CSS::Selector::PseudoElement::Type> pseudo_element, HashMap<FlyString, CSS::StyleProperty> custom_properties)
@ -2232,14 +2243,14 @@ void Element::set_custom_properties(Optional<CSS::Selector::PseudoElement::Type>
m_custom_properties = move(custom_properties); m_custom_properties = move(custom_properties);
return; return;
} }
pseudo_element_custom_properties()[to_underlying(pseudo_element.value())] = move(custom_properties); ensure_pseudo_element(pseudo_element.value()).custom_properties = move(custom_properties);
} }
HashMap<FlyString, CSS::StyleProperty> const& Element::custom_properties(Optional<CSS::Selector::PseudoElement::Type> pseudo_element) const HashMap<FlyString, CSS::StyleProperty> const& Element::custom_properties(Optional<CSS::Selector::PseudoElement::Type> pseudo_element) const
{ {
if (!pseudo_element.has_value()) if (!pseudo_element.has_value())
return m_custom_properties; return m_custom_properties;
return pseudo_element_custom_properties()[to_underlying(pseudo_element.value())]; return ensure_pseudo_element(pseudo_element.value()).custom_properties;
} }
// https://drafts.csswg.org/cssom-view/#dom-element-scroll // https://drafts.csswg.org/cssom-view/#dom-element-scroll

View file

@ -449,9 +449,16 @@ private:
RefPtr<CSS::StyleProperties> m_computed_css_values; RefPtr<CSS::StyleProperties> m_computed_css_values;
HashMap<FlyString, CSS::StyleProperty> m_custom_properties; HashMap<FlyString, CSS::StyleProperty> m_custom_properties;
using PseudoElementCustomProperties = Array<HashMap<FlyString, CSS::StyleProperty>, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)>; struct PseudoElement {
mutable OwnPtr<PseudoElementCustomProperties> m_pseudo_element_custom_properties; JS::GCPtr<Layout::Node> layout_node;
PseudoElementCustomProperties& pseudo_element_custom_properties() const; HashMap<FlyString, CSS::StyleProperty> custom_properties;
};
// TODO: CSS::Selector::PseudoElement::Type includes a lot of pseudo-elements that exist in shadow trees,
// and so we don't want to include data for them here.
using PseudoElementData = Array<PseudoElement, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)>;
mutable OwnPtr<PseudoElementData> m_pseudo_element_data;
Optional<PseudoElement&> get_pseudo_element(CSS::Selector::PseudoElement::Type) const;
PseudoElement& ensure_pseudo_element(CSS::Selector::PseudoElement::Type) const;
Optional<CSS::Selector::PseudoElement::Type> m_use_pseudo_element; Optional<CSS::Selector::PseudoElement::Type> m_use_pseudo_element;
@ -461,9 +468,6 @@ private:
Optional<FlyString> m_id; Optional<FlyString> m_id;
Optional<FlyString> m_name; Optional<FlyString> m_name;
using PseudoElementLayoutNodes = Array<JS::GCPtr<Layout::Node>, to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount)>;
OwnPtr<PseudoElementLayoutNodes> m_pseudo_element_nodes;
// https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reaction-queue // https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reaction-queue
// All elements have an associated custom element reaction queue, initially empty. Each item in the custom element reaction queue is of one of two types: // All elements have an associated custom element reaction queue, initially empty. Each item in the custom element reaction queue is of one of two types:
// NOTE: See the structs at the top of this header. // NOTE: See the structs at the top of this header.