Skip to content

stylo: the servo engine has no `:dir()` pseudo-class

Generated from repros/stylo-dir-pseudo-class-gecko-only/README.md when the site was built at 7aa23e2.

No workaround yet. :dir(ltr) / :dir(rtl) selectors fail to parse under servo-engine stylo (the engine blitz uses), so in niso querySelector, querySelectorAll, matches and closest with :dir() throw SyntaxError. This blocks about 73 WPT subtests in html/dom/elements/global-attributes (dir-assorted.window.js, dir-auto-form-associated.window.js, dir-auto-dynamic-changes.window.js). Chromium supports :dir().

style/gecko/selector_parser.rs:87 has NonTSPseudoClass::Dir(Direction) and its parser handles dir. The servo NonTSPseudoClass (style/servo/selector_parser.rs) has no Dir variant, and parse_non_ts_functional_pseudo_class there (line 686) only knows lang and state, so dir falls through to UnexpectedIdent. The Direction type itself lives in the shared style/selector_parser.rs. Parsing with SelectorParser::parse_author_origin_no_namespace:

expected: div:lang(en) parses
actual: div:lang(en) parses
expected: div:dir(ltr) parses
actual: div:dir(ltr) Custom(SelectorError(UnexpectedIdent))
expected: div:dir(rtl) parses
actual: div:dir(rtl) Custom(SelectorError(UnexpectedIdent))
Terminal window
CARGO_TARGET_DIR=~/.capy/work/repro-target cargo run

Exit status 1 while the bug reproduces.

Reproduces on servo/stylo main at 7f0189de128e6dbd2b504acd3aebee3befa78358 (same output, run through a path dependency on the checkout). The servo NonTSPseudoClass still has no Dir variant; the Gecko one still does.

None found for re-adding it to stylo. Searched servo/stylo issues and PRs for dir, dir pseudo-class, NonTSPseudoClass Dir and similar: no relevant hit. In servo/servo only old, closed history from when the style system lived there: https://github.com/servo/servo/pull/19195 (merged 2017, “style: :dir() pseudo class now represented by enum”), https://github.com/servo/servo/pull/16875 (merged, “Don’t require style sharing cache invalidation for :dir”), https://github.com/servo/servo/issues/16840 (closed), and https://github.com/servo/servo/issues/19231 (open, :dir() argument needs serialize_identifier on serialization). None adds :dir() to the current servo engine.

Title: Support the :dir() pseudo-class in the servo engine

Body:

NonTSPseudoClass::Dir(Direction) exists in style/gecko/selector_parser.rs but not in style/servo/selector_parser.rs, so servo-engine stylo (Servo, Blitz) rejects :dir(ltr) and :dir(rtl) selectors, and querySelector/matches with them throw SyntaxError in embedders. WPT’s html/dom/elements/global-attributes/dir-*.window.js tests depend on it. Direction is already shared.

// Cargo.toml: style = { package = "stylo", git = "https://github.com/servo/stylo", rev = "..." }, url = "2.5"
use style::selector_parser::SelectorParser;
use style::stylesheets::UrlExtraData;
fn main() {
let url = UrlExtraData::from(url::Url::parse("about:blank").unwrap());
assert!(SelectorParser::parse_author_origin_no_namespace("div:lang(en)", &url).is_ok());
// actual: Err(Custom(SelectorError(UnexpectedIdent)))
assert!(SelectorParser::parse_author_origin_no_namespace("div:dir(rtl)", &url).is_ok());
}

Tested at 2dca34592ced37c6aa01733e94206a767194cf9d and main 7f0189de128e6dbd2b504acd3aebee3befa78358. Suggested fix: add a Dir(Direction) variant and parse it in parse_non_ts_functional_pseudo_class, then let the embedder’s match_non_ts_pseudo_class decide matching from the element’s directionality.