script: Make link elements set ElementState::UNVISITED (#41478)

In Servo, the `:link` and `:any-link` pseudo-classes correctly match
link elements when they are part of a compound selector whose last
simple selector does not start with them (e.g. `a:link` or `:link b`),
but they do not match when the last simple selector starts with `:link`.

The reason for this seems to be that Stylo uses two methods to determine
whether an element is an (unvisited) link: to call the `is_link()`
method on the `selectors::Element` trait, and to check if the element's
state has `ElementState::UNVISITED` set.

In a browser like Servo which does not support visited styles, these two
checks should be equivalent. However, they turn out not to be, because
Servo never actually sets `ElementState::UNVISITED`.

Since per the HTML spec the `:link` selector applies to all `<a>` and
`<area>` elements that have an `href` attribute, this patch fixes this
by setting `ElementState::UNVISITED` on such elements when the `href`
attribute is set, and by unsetting it when it is removed.

Testing: There are two invalidation-related WPT tests about the
`:any-link` selector that now pass with this patch.

Fixes: servo/stylo#282

---------

Signed-off-by: Andreu Botella <andreu@andreubotella.com>
This commit is contained in:
Andreu Botella
2025-12-24 09:00:40 +01:00
committed by GitHub
parent c8ed7a7269
commit f4307334dc
5 changed files with 8 additions and 23 deletions

View File

@@ -2,12 +2,6 @@
[:link as scoped selector]
expected: FAIL
[:visited as scoped selector]
expected: FAIL
[:not(:link) as scoped selector]
expected: FAIL
[:not(:visited) as scoped selector]
expected: FAIL
@@ -20,23 +14,11 @@
[:link as scoping root, :scope]
expected: FAIL
[:visited as scoping root, :scope]
expected: FAIL
[:not(:visited) as scoping root, :scope]
expected: FAIL
[:not(:link) as scoping root, :scope]
expected: FAIL
[:link as scoping limit]
expected: FAIL
[:visited as scoping limit]
expected: FAIL
[:not(:link) as scoping limit]
expected: FAIL
[:not(:visited) as scoping limit]
expected: FAIL