Attribute value matching should be case sensitive for SVG

#41089999 Filed 2014-02-17 P3 / S5

The problem

The HTML standard lists a set of legacy attribute names whose values are matched ASCII case-insensitively by CSS attribute selectors. Per the spec this only happens for an HTML element in an HTML document:

"Attribute selectors on an HTML element in an HTML document must treat the values of attributes with the following names as ASCII case-insensitive: accept, align, bgcolor, type, ... vlink."

html.spec.whatwg.org · Case-sensitivity of selectors

Blink only checked the "in an HTML document" half of that condition, so SVG elements (and empty-namespace elements) wrongly got case-insensitive value matching too. The fix adds the missing "is an HTML element" check.

Live test (your browser)

Each row sets a legacy attribute to a mixed-case value (FOO) and checks el.matches('[attr=foo]') -- the lowercase selector value. An HTML element should match (case-insensitive); SVG and empty-namespace elements should not (case-sensitive).

ElementAttributeSelectorResultExpectedStatus

Root cause & fix

In third_party/blink/renderer/core/css/selector_checker.cc:

const bool case_insensitive =
    selector.AttributeMatch() ==
        CSSSelector::AttributeMatchType::kCaseInsensitive ||
    (selector.LegacyCaseInsensitiveMatch() &&
+    element.IsHTMLElement() &&
     IsA<HTMLDocument>(element.GetDocument()));

The element identity is only known at match time, so the "is an HTML element" half of the spec condition has to live in the matchers (the parse-time LegacyCaseInsensitiveMatch bit only knows the attribute name). There are three such match-time decision points, all fixed with the same element.IsHTMLElement() gate:

selector_checker.ccmatches() and complex selectors

selector_checker-inl.h (EasySelectorChecker) — style application via rule collection (the path this issue is about)

selector_query.cc (MatchCompound) — querySelectorAll fast path

The attribute substring pre-filter (CanIgnoreEntireList) stays case-insensitive on purpose: it only ever rejects candidates, and the final decision is always made by the checkers above, so it cannot mask a case-sensitive result. This makes the pre-existing WPT values.window.js all-pass (46 failures removed) and a new style-application test pass for SVG.

Links

🔗 Issue 41089999 🔗 HTML spec 🔗 WPT test