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.
What niso does
Section titled “What niso does”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().
Expected vs actual
Section titled “Expected vs actual”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) parsesactual: div:lang(en) parsesexpected: div:dir(ltr) parsesactual: div:dir(ltr) Custom(SelectorError(UnexpectedIdent))expected: div:dir(rtl) parsesactual: div:dir(rtl) Custom(SelectorError(UnexpectedIdent))CARGO_TARGET_DIR=~/.capy/work/repro-target cargo runExit status 1 while the bug reproduces.
Upstream main
Section titled “Upstream main”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.
Existing issue or PR
Section titled “Existing issue or PR”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.
Issue text
Section titled “Issue text”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.