diff --git a/Userland/Libraries/LibWeb/Bindings/PlatformObject.cpp b/Userland/Libraries/LibWeb/Bindings/PlatformObject.cpp index 858daf6c14a..091c36632bd 100644 --- a/Userland/Libraries/LibWeb/Bindings/PlatformObject.cpp +++ b/Userland/Libraries/LibWeb/Bindings/PlatformObject.cpp @@ -47,9 +47,7 @@ JS::ThrowCompletionOr PlatformObject::is_named_property_exposed_on_object( // 1. If P is not a supported property name of O, then return false. // NOTE: This is in it's own variable to enforce the type. - auto supported_property_names = this->supported_property_names(); - auto property_key_string = MUST(String::from_byte_string(property_key.to_string())); - if (!supported_property_names.contains_slow(property_key_string)) + if (!is_supported_property_name(MUST(String::from_byte_string(property_key.to_string())))) return false; // 2. If O has an own property named P, then return false. @@ -500,6 +498,11 @@ Vector PlatformObject::supported_property_names() const return {}; } +bool PlatformObject::is_supported_property_name(FlyString const& name) const +{ + return supported_property_names().contains_slow(name); +} + bool PlatformObject::is_supported_property_index(u32) const { return false; diff --git a/Userland/Libraries/LibWeb/Bindings/PlatformObject.h b/Userland/Libraries/LibWeb/Bindings/PlatformObject.h index 30ad8afaace..66dae61875d 100644 --- a/Userland/Libraries/LibWeb/Bindings/PlatformObject.h +++ b/Userland/Libraries/LibWeb/Bindings/PlatformObject.h @@ -75,6 +75,7 @@ protected: virtual WebIDL::ExceptionOr item_value(size_t index) const; virtual WebIDL::ExceptionOr named_item_value(FlyString const& name) const; virtual Vector supported_property_names() const; + virtual bool is_supported_property_name(FlyString const&) const; virtual bool is_supported_property_index(u32) const; // NOTE: These will crash if you make has_named_property_setter return true but do not override these methods. diff --git a/Userland/Libraries/LibWeb/DOM/HTMLCollection.cpp b/Userland/Libraries/LibWeb/DOM/HTMLCollection.cpp index 07535ea1457..2531cd75e49 100644 --- a/Userland/Libraries/LibWeb/DOM/HTMLCollection.cpp +++ b/Userland/Libraries/LibWeb/DOM/HTMLCollection.cpp @@ -48,6 +48,30 @@ void HTMLCollection::visit_edges(Cell::Visitor& visitor) Base::visit_edges(visitor); visitor.visit(m_root); visitor.visit(m_cached_elements); + if (m_cached_name_to_element_mappings) + visitor.visit(*m_cached_name_to_element_mappings); +} + +void HTMLCollection::update_name_to_element_mappings_if_needed() const +{ + update_cache_if_needed(); + if (m_cached_name_to_element_mappings) + return; + m_cached_name_to_element_mappings = make>>(); + for (auto const& element : m_cached_elements) { + // 1. If element has an ID which is not in result, append element’s ID to result. + if (auto const& id = element->id(); id.has_value()) { + if (!id.value().is_empty() && !m_cached_name_to_element_mappings->contains(id.value())) + m_cached_name_to_element_mappings->set(id.value(), element); + } + + // 2. If element is in the HTML namespace and has a name attribute whose value is neither the empty string nor is in result, append element’s name attribute value to result. + if (element->namespace_uri() == Namespace::HTML && element->name().has_value()) { + auto element_name = element->name().value(); + if (!element_name.is_empty() && !m_cached_name_to_element_mappings->contains(element_name)) + m_cached_name_to_element_mappings->set(move(element_name), element); + } + } } void HTMLCollection::update_cache_if_needed() const @@ -57,6 +81,7 @@ void HTMLCollection::update_cache_if_needed() const return; m_cached_elements.clear(); + m_cached_name_to_element_mappings = nullptr; if (m_scope == Scope::Descendants) { m_root->for_each_in_subtree_of_type([&](auto& element) { if (m_filter(element)) @@ -107,23 +132,19 @@ Element* HTMLCollection::named_item(FlyString const& key) const if (key.is_empty()) return nullptr; - update_cache_if_needed(); - - // 2. Return the first element in the collection for which at least one of the following is true: - for (auto const& element : m_cached_elements) { - // - it has an ID which is key; - if (element->id() == key) - return element; - - // - it is in the HTML namespace and has a name attribute whose value is key; - if (element->namespace_uri() == Namespace::HTML && element->name() == key) - return element; - } - - // or null if there is no such element. + update_name_to_element_mappings_if_needed(); + if (auto it = m_cached_name_to_element_mappings->get(key); it.has_value()) + return it.value(); return nullptr; } +// https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-names +bool HTMLCollection::is_supported_property_name(FlyString const& name) const +{ + update_name_to_element_mappings_if_needed(); + return m_cached_name_to_element_mappings->contains(name); +} + // https://dom.spec.whatwg.org/#ref-for-dfn-supported-property-names Vector HTMLCollection::supported_property_names() const { @@ -131,20 +152,9 @@ Vector HTMLCollection::supported_property_names() const Vector result; // 2. For each element represented by the collection, in tree order: - update_cache_if_needed(); - for (auto const& element : m_cached_elements) { - // 1. If element has an ID which is not in result, append element’s ID to result. - if (auto const& id = element->id(); id.has_value()) { - if (!id.value().is_empty() && !result.contains_slow(id.value())) - result.append(id.value()); - } - - // 2. If element is in the HTML namespace and has a name attribute whose value is neither the empty string nor is in result, append element’s name attribute value to result. - if (element->namespace_uri() == Namespace::HTML && element->name().has_value()) { - auto name = element->name().value(); - if (!name.is_empty() && !result.contains_slow(name)) - result.append(move(name)); - } + update_name_to_element_mappings_if_needed(); + for (auto const& it : *m_cached_name_to_element_mappings) { + result.append(it.key); } // 3. Return result. diff --git a/Userland/Libraries/LibWeb/DOM/HTMLCollection.h b/Userland/Libraries/LibWeb/DOM/HTMLCollection.h index 844323a200e..1fba69a58c1 100644 --- a/Userland/Libraries/LibWeb/DOM/HTMLCollection.h +++ b/Userland/Libraries/LibWeb/DOM/HTMLCollection.h @@ -43,6 +43,7 @@ public: virtual WebIDL::ExceptionOr item_value(size_t index) const override; virtual WebIDL::ExceptionOr named_item_value(FlyString const& name) const override; virtual Vector supported_property_names() const override; + virtual bool is_supported_property_name(FlyString const&) const override; virtual bool is_supported_property_index(u32) const override; protected: @@ -57,9 +58,11 @@ private: virtual void visit_edges(Cell::Visitor&) override; void update_cache_if_needed() const; + void update_name_to_element_mappings_if_needed() const; mutable u64 m_cached_dom_tree_version { 0 }; mutable Vector> m_cached_elements; + mutable OwnPtr>> m_cached_name_to_element_mappings; JS::NonnullGCPtr m_root; Function m_filter;