LibWeb: Take namespace into account when matching attribute

This commit is contained in:
Netanel Haber 2024-11-27 20:24:29 +02:00 committed by Sam Atkins
commit d743fcb376
Notes: github-actions[bot] 2024-11-30 16:48:12 +00:00
5 changed files with 77 additions and 3 deletions

View file

@ -213,13 +213,43 @@ static inline bool matches_indeterminate_pseudo_class(DOM::Element const& elemen
return false;
}
static inline Web::DOM::Attr const* get_optionally_namespaced_attribute(CSS::Selector::SimpleSelector::Attribute const& attribute, Optional<CSS::CSSStyleSheet const&> style_sheet_for_rule, DOM::Element const& element)
{
auto const& qualified_name = attribute.qualified_name;
auto const& attribute_name = qualified_name.name.name;
auto const& namespace_type = qualified_name.namespace_type;
if (element.namespace_uri() == Namespace::HTML) {
if (namespace_type == CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Named) {
return nullptr;
}
return element.attributes()->get_attribute(attribute_name);
}
switch (namespace_type) {
// "In keeping with the Namespaces in the XML recommendation, default namespaces do not apply to attributes,
// therefore attribute selectors without a namespace component apply only to attributes that have no namespace (equivalent to "|attr")"
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Default:
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::None:
return element.attributes()->get_attribute(attribute_name);
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Any:
return element.attributes()->get_attribute_namespace_agnostic(attribute_name);
case CSS::Selector::SimpleSelector::QualifiedName::NamespaceType::Named:
if (!style_sheet_for_rule.has_value())
return nullptr;
auto const& selector_namespace = style_sheet_for_rule->namespace_uri(qualified_name.namespace_);
if (!selector_namespace.has_value())
return nullptr;
return element.attributes()->get_attribute_ns(selector_namespace, attribute_name);
}
VERIFY_NOT_REACHED();
}
static inline bool matches_attribute(CSS::Selector::SimpleSelector::Attribute const& attribute, [[maybe_unused]] Optional<CSS::CSSStyleSheet const&> style_sheet_for_rule, DOM::Element const& element)
{
// FIXME: Check the attribute's namespace, once we support that in DOM::Element!
auto const& attribute_name = attribute.qualified_name.name.name;
auto const* attr = element.attributes()->get_attribute(attribute_name);
auto const* attr = get_optionally_namespaced_attribute(attribute, style_sheet_for_rule, element);
if (attribute.match_type == CSS::Selector::SimpleSelector::Attribute::MatchType::HasAttribute) {
// Early way out in case of an attribute existence selector.

View file

@ -194,6 +194,16 @@ Attr const* NamedNodeMap::get_attribute_ns(Optional<FlyString> const& namespace_
return nullptr;
}
Attr const* NamedNodeMap::get_attribute_namespace_agnostic(FlyString const& local_name) const
{
for (auto const& attribute : m_attributes) {
if (attribute->local_name() == local_name)
return attribute.ptr();
}
return nullptr;
}
// https://dom.spec.whatwg.org/#concept-element-attributes-set
WebIDL::ExceptionOr<GC::Ptr<Attr>> NamedNodeMap::set_attribute(Attr& attribute)
{

View file

@ -53,6 +53,8 @@ public:
Attr const* remove_attribute(FlyString const& qualified_name);
Attr const* remove_attribute_ns(Optional<FlyString> const& namespace_, FlyString const& local_name);
Attr const* get_attribute_namespace_agnostic(FlyString const& local_name) const;
WebIDL::ExceptionOr<GC::Ref<Attr>> remove_attribute_node(GC::Ref<Attr>);
private:

View file

@ -0,0 +1,11 @@
Summary
Harness status: OK
Rerun
Found 1 tests
1 Pass
Details
Result Test Name MessagePass querySelectorAll must work with namespace attribute selectors on SVG

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>querySelectorAll must work with namespace attribute selectors on SVG</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<!-- Regression test for https://github.com/jsdom/jsdom/issues/2028 -->
<svg id="thesvg" xlink:href="foo"></svg>
<script>
"use strict";
setup({ single_test: true });
const el = document.getElementById("thesvg");
assert_equals(document.querySelector("[*|href]"), el);
assert_array_equals(document.querySelectorAll("[*|href]"), [el]);
done();
</script>