mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
LibWeb: Match attribute selectors case insensitively in XML documents
The values of attribute selectors are now compared case insensitively by default if the attribute's document is not a HTML document, or the element is not in the HTML namespace.
This commit is contained in:
parent
c422518792
commit
00f03f3e90
Notes:
github-actions[bot]
2024-08-19 07:04:16 +00:00
Author: https://github.com/tcl3 Commit: https://github.com/LadybirdBrowser/ladybird/commit/00f03f3e900 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1116
5 changed files with 54 additions and 62 deletions
|
@ -0,0 +1,4 @@
|
|||
The accept attribute is matched case insensitively in HTML documents true
|
||||
The accept attribute is matched case insensitively in XML documents false
|
||||
The accesskey attribute is matched case insensitively in HTML documents false
|
||||
The accesskey attribute is matched case insensitively in XML documents false
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
const elementName = "a";
|
||||
const attributeNames = ["accept", "accesskey"];
|
||||
for (const attributeName of attributeNames) {
|
||||
const htmlElement = document.createElement(elementName);
|
||||
htmlElement.setAttribute(attributeName, "TeSt");
|
||||
println(`The ${attributeName} attribute is matched case insensitively in HTML documents ${htmlElement.matches(`[${attributeName}^=test]`)}`);
|
||||
|
||||
const xmlDocument = new Document();
|
||||
const xmlElement = xmlDocument.createElementNS("http://www.w3.org/1999/xhtml", elementName);
|
||||
xmlElement.setAttribute(attributeName, "TeSt");
|
||||
println(`The ${attributeName} attribute is matched case insensitively in XML documents ${xmlElement.matches(`[${attributeName}^=test]`)}`);
|
||||
}
|
||||
});
|
||||
</script>
|
|
@ -77,56 +77,6 @@ public:
|
|||
|
||||
[[nodiscard]] LengthOrCalculated parse_as_sizes_attribute();
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors
|
||||
static constexpr Array case_insensitive_html_attributes = {
|
||||
"accept"sv,
|
||||
"accept-charset"sv,
|
||||
"align"sv,
|
||||
"alink"sv,
|
||||
"axis"sv,
|
||||
"bgcolor"sv,
|
||||
"charset"sv,
|
||||
"checked"sv,
|
||||
"clear"sv,
|
||||
"codetype"sv,
|
||||
"color"sv,
|
||||
"compact"sv,
|
||||
"declare"sv,
|
||||
"defer"sv,
|
||||
"dir"sv,
|
||||
"direction"sv,
|
||||
"disabled"sv,
|
||||
"enctype"sv,
|
||||
"face"sv,
|
||||
"frame"sv,
|
||||
"hreflang"sv,
|
||||
"http-equiv"sv,
|
||||
"lang"sv,
|
||||
"language"sv,
|
||||
"link"sv,
|
||||
"media"sv,
|
||||
"method"sv,
|
||||
"multiple"sv,
|
||||
"nohref"sv,
|
||||
"noresize"sv,
|
||||
"noshade"sv,
|
||||
"nowrap"sv,
|
||||
"readonly"sv,
|
||||
"rel"sv,
|
||||
"rev"sv,
|
||||
"rules"sv,
|
||||
"scope"sv,
|
||||
"scrolling"sv,
|
||||
"selected"sv,
|
||||
"shape"sv,
|
||||
"target"sv,
|
||||
"text"sv,
|
||||
"type"sv,
|
||||
"valign"sv,
|
||||
"valuetype"sv,
|
||||
"vlink"sv,
|
||||
};
|
||||
|
||||
private:
|
||||
Parser(ParsingContext const&, Vector<Token>);
|
||||
|
||||
|
|
|
@ -260,15 +260,8 @@ Parser::ParseErrorOr<Selector::SimpleSelector> Parser::parse_attribute_simple_se
|
|||
.type = Selector::SimpleSelector::Type::Attribute,
|
||||
.value = Selector::SimpleSelector::Attribute {
|
||||
.match_type = Selector::SimpleSelector::Attribute::MatchType::HasAttribute,
|
||||
// FIXME: Case-sensitivity is defined by the document language.
|
||||
// HTML is insensitive with attribute names, and our code generally assumes
|
||||
// they are converted to lowercase, so we do that here too. If we want to be
|
||||
// correct with XML later, we'll need to keep the original case and then do
|
||||
// a case-insensitive compare later.
|
||||
.qualified_name = qualified_name,
|
||||
.case_type = case_insensitive_html_attributes.contains_slow(qualified_name.name.lowercase_name)
|
||||
? Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch
|
||||
: Selector::SimpleSelector::Attribute::CaseType::DefaultMatch,
|
||||
.case_type = Selector::SimpleSelector::Attribute::CaseType::DefaultMatch,
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -213,10 +213,37 @@ static inline bool matches_attribute(CSS::Selector::SimpleSelector::Attribute co
|
|||
if (!attr)
|
||||
return false;
|
||||
|
||||
auto const case_insensitive_match = (attribute.case_type == CSS::Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch);
|
||||
auto const case_sensitivity = case_insensitive_match
|
||||
? CaseSensitivity::CaseInsensitive
|
||||
: CaseSensitivity::CaseSensitive;
|
||||
auto case_sensitivity = [&](CSS::Selector::SimpleSelector::Attribute::CaseType case_type) {
|
||||
switch (case_type) {
|
||||
case CSS::Selector::SimpleSelector::Attribute::CaseType::CaseInsensitiveMatch:
|
||||
return CaseSensitivity::CaseInsensitive;
|
||||
case CSS::Selector::SimpleSelector::Attribute::CaseType::CaseSensitiveMatch:
|
||||
return CaseSensitivity::CaseSensitive;
|
||||
case CSS::Selector::SimpleSelector::Attribute::CaseType::DefaultMatch:
|
||||
// See: https://html.spec.whatwg.org/multipage/semantics-other.html#case-sensitivity-of-selectors
|
||||
if (element.document().is_html_document()
|
||||
&& element.namespace_uri() == Namespace::HTML
|
||||
&& attribute_name.is_one_of(
|
||||
HTML::AttributeNames::accept, HTML::AttributeNames::accept_charset, HTML::AttributeNames::align,
|
||||
HTML::AttributeNames::alink, HTML::AttributeNames::axis, HTML::AttributeNames::bgcolor, HTML::AttributeNames::charset,
|
||||
HTML::AttributeNames::checked, HTML::AttributeNames::clear, HTML::AttributeNames::codetype, HTML::AttributeNames::color,
|
||||
HTML::AttributeNames::compact, HTML::AttributeNames::declare, HTML::AttributeNames::defer, HTML::AttributeNames::dir,
|
||||
HTML::AttributeNames::direction, HTML::AttributeNames::disabled, HTML::AttributeNames::enctype, HTML::AttributeNames::face,
|
||||
HTML::AttributeNames::frame, HTML::AttributeNames::hreflang, HTML::AttributeNames::http_equiv, HTML::AttributeNames::lang,
|
||||
HTML::AttributeNames::language, HTML::AttributeNames::link, HTML::AttributeNames::media, HTML::AttributeNames::method,
|
||||
HTML::AttributeNames::multiple, HTML::AttributeNames::nohref, HTML::AttributeNames::noresize, HTML::AttributeNames::noshade,
|
||||
HTML::AttributeNames::nowrap, HTML::AttributeNames::readonly, HTML::AttributeNames::rel, HTML::AttributeNames::rev,
|
||||
HTML::AttributeNames::rules, HTML::AttributeNames::scope, HTML::AttributeNames::scrolling, HTML::AttributeNames::selected,
|
||||
HTML::AttributeNames::shape, HTML::AttributeNames::target, HTML::AttributeNames::text, HTML::AttributeNames::type,
|
||||
HTML::AttributeNames::valign, HTML::AttributeNames::valuetype, HTML::AttributeNames::vlink)) {
|
||||
return CaseSensitivity::CaseInsensitive;
|
||||
}
|
||||
|
||||
return CaseSensitivity::CaseSensitive;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}(attribute.case_type);
|
||||
auto case_insensitive_match = case_sensitivity == CaseSensitivity::CaseInsensitive;
|
||||
|
||||
switch (attribute.match_type) {
|
||||
case CSS::Selector::SimpleSelector::Attribute::MatchType::ExactValueMatch:
|
||||
|
|
Loading…
Reference in a new issue