LibWeb: Avoid full DOM tree traversal in Window::named_objects()

Instead, take advantage of `ElementByIdMap` and
`m_potentially_named_elements` to gather elements with specified name
more efficiently.
This commit is contained in:
Aliaksandr Kalenik 2025-11-24 20:37:42 +01:00 committed by Jelle Raaijmakers
parent e80d1bcee7
commit 4c22c372a4
Notes: github-actions[bot] 2025-11-25 08:17:35 +00:00
2 changed files with 22 additions and 7 deletions

View file

@ -24,6 +24,18 @@ public:
callback(id);
}
template<typename Callback>
void for_each_element_with_id(StringView id, Callback callback)
{
auto maybe_elements_with_id = m_map.get(id);
if (!maybe_elements_with_id.has_value())
return;
for (auto const& element : *maybe_elements_with_id) {
if (element)
callback(GC::Ref { *element });
}
}
private:
HashMap<FlyString, Vector<GC::Weak<Element>>> m_map;
};

View file

@ -1901,13 +1901,16 @@ Window::NamedObjects Window::named_objects(StringView name)
// embed, form, img, or object elements that have a name content attribute whose value is name
// and are in a document tree with window's associated Document as their root; and
// HTML elements that have an id content attribute whose value is name and are in a document tree with window's associated Document as their root.
associated_document().for_each_in_subtree_of_type<DOM::Element>([&objects, &name](auto& element) -> TraversalDecision {
if ((is<HTMLEmbedElement>(element) || is<HTMLFormElement>(element) || is<HTMLImageElement>(element) || is<HTMLObjectElement>(element))
&& (element.name() == name))
objects.elements.append(element);
else if (element.id() == name)
objects.elements.append(element);
return TraversalDecision::Continue;
for (auto element : associated_document().potentially_named_elements()) {
if (element->id().has_value()) {
// NOTE: The element will be added when we iterate over the element_by_id() map below.
continue;
}
if (auto element_name = element->name(); element_name.has_value() && *element_name == name)
objects.elements.append(*element);
}
associated_document().element_by_id().for_each_element_with_id(name, [&](auto element) {
objects.elements.append(*element);
});
return objects;