1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 11:38:11 +00:00

LibWeb: Weakly store NamedNodeMap's & Attribute's associated Element

This is similar to how Gecko avoids a reference cycle, where both the
NamedNodeMap and Attribute would otherwise store a strong reference to
their associated Element. Gecko manually clears stored raw references
when an Element is destroyed, whereas we use weak references to do so
automatically.

Attribute's ownerElement getter and setter are moved out of line to
avoid an #include cycle between Element and Attribute.
This commit is contained in:
Timothy Flynn 2021-10-17 15:09:47 -04:00 committed by Andreas Kling
parent 356d5821e7
commit b67f6daf05
4 changed files with 35 additions and 8 deletions

View file

@ -19,6 +19,8 @@ NonnullRefPtr<NamedNodeMap> NamedNodeMap::create(Element const& associated_eleme
NamedNodeMap::NamedNodeMap(Element const& associated_element)
: m_associated_element(associated_element)
{
// Note: To avoid a reference cycle between Element, NamedNodeMap, and Attribute, do not store a
// strong reference to the associated element.
}
// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-indices%E2%91%A3
@ -30,6 +32,10 @@ bool NamedNodeMap::is_supported_property_index(u32 index) const
// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-names%E2%91%A0
Vector<String> NamedNodeMap::supported_property_names() const
{
auto associated_element = m_associated_element.strong_ref();
if (!associated_element)
return {};
// 1. Let names be the qualified names of the attributes in this NamedNodeMap objects attribute list, with duplicates omitted, in order.
Vector<String> names;
names.ensure_capacity(m_attributes.size());
@ -41,7 +47,7 @@ Vector<String> NamedNodeMap::supported_property_names() const
// 2. If this NamedNodeMap objects element is in the HTML namespace and its node document is an HTML document, then for each name in names:
// FIXME: Handle the second condition, assume it is an HTML document for now.
if (m_associated_element.namespace_uri() == Namespace::HTML) {
if (associated_element->namespace_uri() == Namespace::HTML) {
// 1. Let lowercaseName be name, in ASCII lowercase.
// 2. If lowercaseName is not equal to name, remove name from names.
names.remove_all_matching([](auto const& name) { return name != name.to_lowercase(); });
@ -97,13 +103,17 @@ Attribute* NamedNodeMap::get_attribute(StringView qualified_name, size_t* item_i
// https://dom.spec.whatwg.org/#concept-element-attributes-get-by-name
Attribute const* NamedNodeMap::get_attribute(StringView qualified_name, size_t* item_index) const
{
auto associated_element = m_associated_element.strong_ref();
if (!associated_element)
return nullptr;
if (item_index)
*item_index = 0;
// 1. If element is in the HTML namespace and its node document is an HTML document, then set qualifiedName to qualifiedName in ASCII lowercase.
// FIXME: Handle the second condition, assume it is an HTML document for now.
Optional<String> qualified_name_lowercase;
if (m_associated_element.namespace_uri() == Namespace::HTML) {
if (associated_element->namespace_uri() == Namespace::HTML) {
qualified_name_lowercase = qualified_name.to_lowercase_string();
qualified_name = qualified_name_lowercase->view();
}
@ -122,8 +132,12 @@ Attribute const* NamedNodeMap::get_attribute(StringView qualified_name, size_t*
// https://dom.spec.whatwg.org/#concept-element-attributes-set
ExceptionOr<Attribute const*> NamedNodeMap::set_attribute(Attribute& attribute)
{
auto associated_element = m_associated_element.strong_ref();
if (!associated_element)
return nullptr;
// 1. If attrs element is neither null nor element, throw an "InUseAttributeError" DOMException.
if ((attribute.owner_element() != nullptr) && (attribute.owner_element() != &m_associated_element))
if ((attribute.owner_element() != nullptr) && (attribute.owner_element() != associated_element))
return InUseAttributeError::create("Attribute must not already be in use"sv);
// 2. Let oldAttr be the result of getting an attribute given attrs namespace, attrs local name, and element.
@ -177,7 +191,7 @@ void NamedNodeMap::append_attribute(Attribute& attribute)
m_attributes.append(attribute);
// 3. Set attributes element to element.
attribute.set_owner_element(&m_associated_element);
attribute.set_owner_element(m_associated_element);
}
// https://dom.spec.whatwg.org/#concept-element-attributes-remove-by-name