Skip to content

Commit 4c22c37

Browse files
kalenikaliaksandrgmta
authored andcommitted
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.
1 parent e80d1bc commit 4c22c37

File tree

2 files changed

+22
-7
lines changed

2 files changed

+22
-7
lines changed

Libraries/LibWeb/DOM/ElementByIdMap.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ class ElementByIdMap {
2424
callback(id);
2525
}
2626

27+
template<typename Callback>
28+
void for_each_element_with_id(StringView id, Callback callback)
29+
{
30+
auto maybe_elements_with_id = m_map.get(id);
31+
if (!maybe_elements_with_id.has_value())
32+
return;
33+
for (auto const& element : *maybe_elements_with_id) {
34+
if (element)
35+
callback(GC::Ref { *element });
36+
}
37+
}
38+
2739
private:
2840
HashMap<FlyString, Vector<GC::Weak<Element>>> m_map;
2941
};

Libraries/LibWeb/HTML/Window.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,13 +1901,16 @@ Window::NamedObjects Window::named_objects(StringView name)
19011901
// embed, form, img, or object elements that have a name content attribute whose value is name
19021902
// and are in a document tree with window's associated Document as their root; and
19031903
// 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.
1904-
associated_document().for_each_in_subtree_of_type<DOM::Element>([&objects, &name](auto& element) -> TraversalDecision {
1905-
if ((is<HTMLEmbedElement>(element) || is<HTMLFormElement>(element) || is<HTMLImageElement>(element) || is<HTMLObjectElement>(element))
1906-
&& (element.name() == name))
1907-
objects.elements.append(element);
1908-
else if (element.id() == name)
1909-
objects.elements.append(element);
1910-
return TraversalDecision::Continue;
1904+
for (auto element : associated_document().potentially_named_elements()) {
1905+
if (element->id().has_value()) {
1906+
// NOTE: The element will be added when we iterate over the element_by_id() map below.
1907+
continue;
1908+
}
1909+
if (auto element_name = element->name(); element_name.has_value() && *element_name == name)
1910+
objects.elements.append(*element);
1911+
}
1912+
associated_document().element_by_id().for_each_element_with_id(name, [&](auto element) {
1913+
objects.elements.append(*element);
19111914
});
19121915

19131916
return objects;

0 commit comments

Comments
 (0)