Closed Bug 1712547 Opened 4 years ago Closed 4 years ago

[wpt-sync] Sync PR 29090 - Supports :has() pseudo class matching

Categories

(Core :: CSS Parsing and Computation, task, P4)

task

Tracking

()

RESOLVED FIXED
91 Branch
Tracking Status
firefox91 --- fixed

People

(Reporter: wpt-sync, Unassigned)

References

()

Details

(Whiteboard: [wptsync downstream])

Sync web-platform-tests PR 29090 into mozilla-central (this bug is closed when the sync is complete).

PR: https://github.com/web-platform-tests/wpt/pull/29090
Details from upstream follow.

b'Byungwoo Lee <blee@igalia.com>' wrote:

Supports :has() pseudo class matching

Add :has() pseudo class syntax support and matching logic behind a runtime
experimental feature (CSSPseudoHas)

\<Syntax support>
Add syntax support for :has() pseudo class specified in Selectors Level 4.

:has() pseudo class takes a relatvie selector list as an argument.

  • :has(\<relative-selector-list>)
  • \<relative-selector-list> = \<relative-selector>#
  • \<relative-selector> = \<combinator>? \<complex-selector>

\<relative-selector> is also specified in Selectors Level 4,
and it is not supported yet.

So this CL only supports argument selectors starting with descendant combinator.

  • .a:has(.b)

Argument selectors starting with other combinators are not supported yet.

  • .a:has(> .b)
  • .a:has(~ .b)
  • .a:has(+ .b)

\<Selector matching>
Add :has() pseudo class selector matching logic.

This CL suggests stack-allocated :has() matching status cache
to prevent repetitive tree traversal and argument selector matching
operation.

The cache stores each element status as below.

  • Matched : Checked :has() and matched
  • Checked : Checked :has() but not matched
  • NotChecked : Not checked :has() (default)

Below is the pseudo code for :has matching with descendant relative selectors.
(e.g. ':has(.a)' or ':has(:scope .a)')
┬ Allocate cache on stack memory
├ Enter the style recalculation sequence (or Node selector js API sequence)
│ ├ ...
│ ├ Enter the selector matching sequence
│ │ ├ If matching :has pseudo class on an element
│ │ │ └ Enter :has selector matching sequence
│ │ │ ├ Get argument selector
│ │ │ ├ Get element status from cache
│ │ │ ├ If the element status is checked
│ │ │ │ └ If the element status is matched
│ │ │ │ └ Finish has pseudo class matching as matched
│ │ │ ├ Else
│ │ │ │ ├ Set the element status as checked
│ │ │ │ └ Traverse all descendants of the element
│ │ │ │ ├ Get the descendant status from cache
│ │ │ │ ├ If the descendant status is checked
│ │ │ │ │ └ If the descendant status is matched
│ │ │ │ │ ├ Set the element status as matched
│ │ │ │ │ └ Finish has pseudo class matching as matched
│ │ │ │ └ Else
│ │ │ │ ├ Set the descendant status as checked
│ │ │ │ └ If the descendant matches the argument selector
│ │ │ │ ├ Get start element of the shortest match
│ │ │ │ ├ Traverse it's ancestors until met the element
│ │ │ │ │ └ Set the ancestor status as matched
│ │ │ │ ├ Set the element status as matched
│ │ │ │ └ Finish has pseudo class matching as matched
│ │ │ └ Finish has pseudo class matching as not matched
│ │ └ Otherwise
│ │ └ Do other selector matching sequence
│ └ ...
└ Release cache from stack memory

Other cases will be handled later in separated CLs.

  • :has(> .a) , :has(:scope > .a)
  • :has(~ .a) , :has(:scope ~ .a)
  • :has(+ .a) , :has(:scope + .a)

This CL supports :has with following javascript APIs.

  • querySelector
  • querySelectorAll
  • matches
  • closest

This CL merged 2 CLs to prevent a web_test failure (jquery/traversing.html)

Change-Id: I1992b70d86f47fc5f98437e1e6abea2da021ef6b
Bug: 669058
Reviewed-on: https://chromium-review.googlesource.com/2914717
WPT-Export-Revision: 9ad542085667cf694c7046e3d3f65a30f668a139

Component: web-platform-tests → CSS Parsing and Computation
Product: Testing → Core

CI Results

Ran 15 Firefox configurations based on mozilla-central, and Firefox, Chrome, and Safari on GitHub CI

Total 2 tests and 30 subtests

Status Summary

Firefox

OK : 2
PASS: 1
FAIL: 52

Chrome

OK : 2
PASS: 1
FAIL: 52

Safari

OK : 2
PASS: 1
FAIL: 52

Links

Gecko CI (Treeherder)
GitHub PR Head
GitHub PR Base

Details

New Tests That Don't Pass

/css/selectors/has-basic.html
:has(#a) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.ancestor) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.descendant) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.parent:has(.target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.sibling ~ .target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.parent:has(.sibling ~ .target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(:is(.target ~ .sibling .descendant)) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.parent:has(:is(.target ~ .sibling .descendant)) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.sibling:has(.descendant) ~ .target matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.sibling:has(.descendant) ~ .target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.sibling:has(.descendant) ~ .target) ~ .parent > .descendant matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(:scope .target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(:scope > .parent) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(> .target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
:has(:scope > .target) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.target:has(+ .sibling) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.target:has(:scope + .sibling) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.parent:has(~ #h) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.parent:has(:scope ~ #h) matches expected elements: FAIL (Chrome: FAIL, Safari: FAIL)
.sibling:has(.descendant) matches expected element: FAIL (Chrome: FAIL, Safari: FAIL)
closest(.ancestor:has(.descendant)) returns expected element: FAIL (Chrome: FAIL, Safari: FAIL)
:has(.target ~ .sibling .descendant) matches expectedly: FAIL (Chrome: FAIL, Safari: FAIL)
/css/selectors/parsing/parse-has.html
":has(a)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has(#a)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has(.a)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has([a])" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has([a="b"])" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has([a|="b"])" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has(:hover)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has(.a)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(.b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(:scope .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(> .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(:scope > .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(~ .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(:scope ~ .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(+ .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(:scope + .b)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(.b) .c" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a .b:has(.c)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a .b:has(.c .d)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a .b:has(.c .d) .e" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(.b:has(.c))" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(.b:is(.c .d))" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(.b:is(.c:has(.d) .e))" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:is(.b:has(.c) .d)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:not(:has(.b))" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(:not(.b))" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
".a:has(.b):has(.c)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
"
|:has()" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)
":has(|)" should be a valid selector: FAIL (Chrome: FAIL, Safari: FAIL)

Pushed by wptsync@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/18429dd46cdf [wpt PR 29090] - Supports :has() pseudo class matching, a=testonly https://hg.mozilla.org/integration/autoland/rev/515dfcad6c24 [wpt PR 29090] - Update wpt metadata, a=testonly
Status: NEW → RESOLVED
Closed: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → 91 Branch
You need to log in before you can comment on or make changes to this bug.