mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-25 19:56:30 +00:00
LibWeb/DOM: Serialize pseudo-elements in the correct order
Make Element responsible for serializing all its children, so it can put them in order.
This commit is contained in:
parent
4df472988c
commit
ffd5503dcb
Notes:
github-actions[bot]
2025-07-03 08:57:58 +00:00
Author: https://github.com/AtkinsSJ
Commit: ffd5503dcb
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5274
4 changed files with 63 additions and 26 deletions
|
@ -1585,21 +1585,60 @@ void Element::clear_pseudo_element_nodes(Badge<Layout::TreeBuilder>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Element::serialize_pseudo_elements_as_json(JsonArraySerializer<StringBuilder>& children_array) const
|
void Element::serialize_children_as_json(JsonObjectSerializer<StringBuilder>& element_object) const
|
||||||
{
|
{
|
||||||
if (!m_pseudo_element_data)
|
bool has_pseudo_elements = this->has_pseudo_elements();
|
||||||
|
if (!is_shadow_host() && !has_child_nodes() && !has_pseudo_elements)
|
||||||
return;
|
return;
|
||||||
for (auto const& [pseudo_element_type, pseudo_element] : (*m_pseudo_element_data)) {
|
|
||||||
|
auto children = MUST(element_object.add_array("children"sv));
|
||||||
|
|
||||||
|
auto serialize_pseudo_element = [&](CSS::PseudoElement pseudo_element_type, auto const& pseudo_element) {
|
||||||
// FIXME: Find a way to make these still inspectable? (eg, `::before { display: none }`)
|
// FIXME: Find a way to make these still inspectable? (eg, `::before { display: none }`)
|
||||||
if (!pseudo_element->layout_node())
|
if (!pseudo_element->layout_node())
|
||||||
continue;
|
return;
|
||||||
auto object = MUST(children_array.add_object());
|
auto object = MUST(children.add_object());
|
||||||
MUST(object.add("name"sv, MUST(String::formatted("::{}", CSS::pseudo_element_name(pseudo_element_type)))));
|
MUST(object.add("name"sv, MUST(String::formatted("::{}", CSS::pseudo_element_name(pseudo_element_type)))));
|
||||||
MUST(object.add("type"sv, "pseudo-element"));
|
MUST(object.add("type"sv, "pseudo-element"));
|
||||||
MUST(object.add("parent-id"sv, unique_id().value()));
|
MUST(object.add("parent-id"sv, unique_id().value()));
|
||||||
MUST(object.add("pseudo-element"sv, to_underlying(pseudo_element_type)));
|
MUST(object.add("pseudo-element"sv, to_underlying(pseudo_element_type)));
|
||||||
MUST(object.finish());
|
MUST(object.finish());
|
||||||
|
};
|
||||||
|
|
||||||
|
if (has_pseudo_elements) {
|
||||||
|
if (auto backdrop = m_pseudo_element_data->get(CSS::PseudoElement::Backdrop); backdrop.has_value()) {
|
||||||
|
serialize_pseudo_element(CSS::PseudoElement::Backdrop, backdrop.value());
|
||||||
|
}
|
||||||
|
if (auto marker = m_pseudo_element_data->get(CSS::PseudoElement::Marker); marker.has_value()) {
|
||||||
|
serialize_pseudo_element(CSS::PseudoElement::Marker, marker.value());
|
||||||
|
}
|
||||||
|
if (auto before = m_pseudo_element_data->get(CSS::PseudoElement::Before); before.has_value()) {
|
||||||
|
serialize_pseudo_element(CSS::PseudoElement::Before, before.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_shadow_host())
|
||||||
|
serialize_child_as_json(children, *shadow_root());
|
||||||
|
|
||||||
|
auto add_child = [this, &children](Node const& child) {
|
||||||
|
return serialize_child_as_json(children, child);
|
||||||
|
};
|
||||||
|
for_each_child(add_child);
|
||||||
|
|
||||||
|
if (has_pseudo_elements) {
|
||||||
|
if (auto after = m_pseudo_element_data->get(CSS::PseudoElement::After); after.has_value()) {
|
||||||
|
serialize_pseudo_element(CSS::PseudoElement::After, after.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any other pseudo-elements, as a catch-all.
|
||||||
|
for (auto const& [type, pseudo_element] : *m_pseudo_element_data) {
|
||||||
|
if (first_is_one_of(type, CSS::PseudoElement::After, CSS::PseudoElement::Backdrop, CSS::PseudoElement::Before, CSS::PseudoElement::Marker))
|
||||||
|
continue;
|
||||||
|
serialize_pseudo_element(type, pseudo_element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MUST(children.finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/interaction.html#dom-tabindex
|
// https://html.spec.whatwg.org/multipage/interaction.html#dom-tabindex
|
||||||
|
|
|
@ -288,7 +288,8 @@ public:
|
||||||
bool has_pseudo_element(CSS::PseudoElement) const;
|
bool has_pseudo_element(CSS::PseudoElement) const;
|
||||||
bool has_pseudo_elements() const;
|
bool has_pseudo_elements() const;
|
||||||
void clear_pseudo_element_nodes(Badge<Layout::TreeBuilder>);
|
void clear_pseudo_element_nodes(Badge<Layout::TreeBuilder>);
|
||||||
void serialize_pseudo_elements_as_json(JsonArraySerializer<StringBuilder>& children_array) const;
|
|
||||||
|
void serialize_children_as_json(JsonObjectSerializer<StringBuilder>&) const;
|
||||||
|
|
||||||
i32 tab_index() const;
|
i32 tab_index() const;
|
||||||
void set_tab_index(i32 tab_index);
|
void set_tab_index(i32 tab_index);
|
||||||
|
|
|
@ -1909,6 +1909,16 @@ bool Node::is_uninteresting_whitespace_node() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IterationDecision Node::serialize_child_as_json(JsonArraySerializer<StringBuilder>& children_array, Node const& child) const
|
||||||
|
{
|
||||||
|
if (child.is_uninteresting_whitespace_node())
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
JsonObjectSerializer<StringBuilder> child_object = MUST(children_array.add_object());
|
||||||
|
child.serialize_tree_as_json(child_object);
|
||||||
|
MUST(child_object.finish());
|
||||||
|
return IterationDecision::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& object) const
|
void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& object) const
|
||||||
{
|
{
|
||||||
MUST(object.add("name"sv, node_name()));
|
MUST(object.add("name"sv, node_name()));
|
||||||
|
@ -1967,29 +1977,15 @@ void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& object) c
|
||||||
|
|
||||||
MUST((object.add("visible"sv, !!layout_node())));
|
MUST((object.add("visible"sv, !!layout_node())));
|
||||||
|
|
||||||
auto const* element = is_element() ? static_cast<DOM::Element const*>(this) : nullptr;
|
if (auto const* element = as_if<Element>(this)) {
|
||||||
|
element->serialize_children_as_json(object);
|
||||||
if (has_child_nodes()
|
} else if (has_child_nodes()) {
|
||||||
|| (element && (element->is_shadow_host() || element->has_pseudo_elements()))) {
|
|
||||||
auto children = MUST(object.add_array("children"sv));
|
auto children = MUST(object.add_array("children"sv));
|
||||||
auto add_child = [&children](DOM::Node const& child) {
|
auto add_child = [this, &children](Node const& child) {
|
||||||
if (child.is_uninteresting_whitespace_node())
|
return serialize_child_as_json(children, child);
|
||||||
return IterationDecision::Continue;
|
|
||||||
JsonObjectSerializer<StringBuilder> child_object = MUST(children.add_object());
|
|
||||||
child.serialize_tree_as_json(child_object);
|
|
||||||
MUST(child_object.finish());
|
|
||||||
return IterationDecision::Continue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for_each_child(add_child);
|
for_each_child(add_child);
|
||||||
|
|
||||||
if (element) {
|
|
||||||
// Pseudo-elements don't have DOM nodes,so we have to add them separately.
|
|
||||||
element->serialize_pseudo_elements_as_json(children);
|
|
||||||
|
|
||||||
if (element->is_shadow_host())
|
|
||||||
add_child(*element->shadow_root());
|
|
||||||
}
|
|
||||||
|
|
||||||
MUST(children.finish());
|
MUST(children.finish());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,6 +382,7 @@ public:
|
||||||
|
|
||||||
// Used for dumping the DOM Tree
|
// Used for dumping the DOM Tree
|
||||||
void serialize_tree_as_json(JsonObjectSerializer<StringBuilder>&) const;
|
void serialize_tree_as_json(JsonObjectSerializer<StringBuilder>&) const;
|
||||||
|
IterationDecision serialize_child_as_json(JsonArraySerializer<StringBuilder>& children_array, Node const& child) const;
|
||||||
|
|
||||||
bool is_shadow_including_descendant_of(Node const&) const;
|
bool is_shadow_including_descendant_of(Node const&) const;
|
||||||
bool is_shadow_including_inclusive_descendant_of(Node const&) const;
|
bool is_shadow_including_inclusive_descendant_of(Node const&) const;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue