LayoutTests/ChangeLog

 12020-04-14 Antti Koivisto <antti@apple.com>
 2
 3 [CSS Selectors] Selectors Level 4 specificity calculation for pseudo classes
 4 https://bugs.webkit.org/show_bug.cgi?id=210419
 5
 6 Reviewed by Simon Fraser.
 7
 8 Update specificity tests for static behavior, trying to also keep them useful.
 9
 10 * fast/css/is-specificity-10-expected.html:
 11 * fast/css/is-specificity-10.html:
 12 * fast/css/is-specificity-2-expected.html:
 13 * fast/css/is-specificity-2.html:
 14 * fast/css/is-specificity-3-expected.html:
 15 * fast/css/is-specificity-3.html:
 16 * fast/css/is-specificity-4-expected.html:
 17 * fast/css/is-specificity-4.html:
 18 * fast/css/is-specificity-5.html:
 19 * fast/css/matches-specificity-10-expected.html:
 20 * fast/css/matches-specificity-10.html:
 21 * fast/css/matches-specificity-2-expected.html:
 22 * fast/css/matches-specificity-2.html:
 23 * fast/css/matches-specificity-3-expected.html:
 24 * fast/css/matches-specificity-3.html:
 25 * fast/css/matches-specificity-4-expected.html:
 26 * fast/css/matches-specificity-4.html:
 27 * fast/css/matches-specificity-5.html:
 28 * fast/css/nth-child-specificity-2-expected.html:
 29 * fast/css/nth-child-specificity-2.html:
 30 * fast/css/nth-child-specificity-3-expected.html:
 31 * fast/css/nth-child-specificity-3.html:
 32 * fast/css/nth-child-specificity-4-expected.html:
 33 * fast/css/nth-child-specificity-4.html:
 34 * fast/css/nth-last-child-specificity-2-expected.html:
 35 * fast/css/nth-last-child-specificity-2.html:
 36 * fast/css/nth-last-child-specificity-3-expected.html:
 37 * fast/css/nth-last-child-specificity-3.html:
 38 * fast/css/nth-last-child-specificity-4-expected.html:
 39 * fast/css/nth-last-child-specificity-4.html:
 40
1412020-04-14 Commit Queue <commit-queue@webkit.org>
242
343 Unreviewed, reverting r260024.

LayoutTests/fast/css/is-specificity-10-expected.html

11<!doctype html>
22<html>
33<body>
4  <p>This test the dynamic specificity of :is() with a simple descendant backtracking case. The test pass if each block has style matching its description. None of the result should have a border.</p>
5 
64 <foo id="b">
75 <foo id="c">
86 <e>

LayoutTests/fast/css/is-specificity-10.html

22<html>
33<head>
44<style>
5  /* Specificity (2, 0, 2). */
6  #f#f > padding > target {
 5 /* Specificity (3, 0, 2). */
 6 #f#f#f > padding > target {
77 background-color: purple;
88 }
99

2323 border: 5px blue solid;
2424 }
2525
 26 /* Specificity (3, 0, 1) */
2627 :is(aBlock, #b) > :is(#c, d) > :is(e, #f) target {
2728 background-color: green;
2829 color: white;
2930 border: none;
3031 }
 32
 33 /* Specificity (3, 0, 2) */
 34 #c#c#c padding target {
 35 background-color: green;
 36 }
 37
 38 /* Specificity (3, 0, 1) */
 39 #f#f#f target {
 40 background-color: green;
 41 }
 42
 43 /* Specificity (3, 0, 2) */
 44 a #f#f#f target {
 45 color: green;
 46 }
3147</style>
3248</head>
3349<body>
34  <p>This test the dynamic specificity of :is() with a simple descendant backtracking case. The test pass if each block has style matching its description. None of the result should have a border.</p>
35 
36  <!--
37  This case should match ":is(a, #b) > :is(#c, d) > :is(e, #f) target"
38  like "#a > #c > e target"
39  with the specificity (2, 0, 2).
40  -->
4150 <foo id="b">
4251 <foo id="c">
4352 <e> <!-- Success case from here. -->

6473 </foo>
6574 </foo>
6675
67  <!--
68  This case should match ":is(a, #b) > :is(#c, d) > :is(e, #f) target"
69  like "#a > d > e target"
70  with the specificity (1, 0, 3).
71  -->
7276 <foo id="b">
7377 <d>
7478 <e> <!-- Success case from here. -->

9599 </d>
96100 </foo>
97101
98  <!--
99  This case should match ":is(a, #b) > :is(#c, d) > :is(e, #f) target"
100  like "a > d > e target"
101  with the specificity (0, 0, 4).
102  -->
103102 <aBlock>
104103 <d>
105104 <e> <!-- Success case from here. -->

LayoutTests/fast/css/is-specificity-2-expected.html

88</style>
99</head>
1010<body>
11  <p>This test the specificity of :is() with a dynamic specificity of zero. The test passes if the text "target" is displayed white on green background.</p>
12  <target style="background-color: green; color: white;">Target</target>
 11 <target style="color: blue;">Target</target>
1312</body>
1413</html>

LayoutTests/fast/css/is-specificity-2.html

1515 background-color: green;
1616 }
1717
18  /* The only dynamic selector that matches is "*". Every rules except the first one (* selector) should override the style defined here.
19  Background-color is defined by the two tag selectors above.
20  Color is defined below by the star rule. It has the same specificity but a higher position.
21  Border overrides the black border defined in the first rule. */
2218 :is(#foo, .bar, target.notthere, *, foo>bar) {
23  background-color: red;
 19 background-color: white;
2420 color: blue;
2521 border: none;
2622 }

3026</style>
3127</head>
3228<body>
33  <p>This test the specificity of :is() with a dynamic specificity of zero. The test passes if the text "target" is displayed white on green background.</p>
3429 <target>Target</target>
3530</body>
3631</html>

LayoutTests/fast/css/is-specificity-3-expected.html

11<!doctype html>
22<html>
3 <head>
4 <style>
5  body > * {
6  display: block;
7  }
8  html, body, p {
9  background-color: white;
10  color: black;
11  }
12 </style>
13 </head>
143<body>
15  <p>This test checks the dynamic specificity of :is() changing the order in which rules are applied depending on the element. Each element should have the colors described in the text and no border.</p>
16  <nottarget style="color: purple; background-color: red;">Purple text on red background.</nottarget>
17  <target style="color: white; background-color: green;">White text on green background.</target>
18  <nottarget style="color: purple; background-color: red;">Purple text on red background.</nottarget>
19  <target style="color: purple; background-color: red;">Purple text on red background.</target>
20  <nottarget style="color: purple; background-color: blue;">Purple text on blue background.</nottarget>
21  <target style="color: purple; background-color: blue;">Purple text on blue background.</target>
22  <nottarget style="color: purple; background-color: red;">Purple text on red background.</nottarget>
23  <target style="color: purple; background-color: red;">Purple text on red background.</target>
 4<div style="color: purple; background-color: blue;">Text</div>
 5<div style="color: purple; background-color: green;">Text</div>
 6<div style="color: purple; background-color: blue;">Text</div>
 7<div style="color: purple; background-color: green;">Text</div>
 8<div style="color: purple; background-color: blue;">Text</div>
 9<div style="color: purple; background-color: blue;">Text</div>
 10<div style="color: purple; background-color: blue;">Text</div>
 11<div style="color: purple; background-color: blue;">Text</div>
2412</body>
2513</html>

LayoutTests/fast/css/is-specificity-3.html

88 border: 5px solid black;
99 }
1010
11  /* The following :is() gets a different class of specificity. Depending on what
12  matches, the later rules may override this or not. */
13  :is(.classB, target, #classA, *) {
14  background-color: red;
 11 :is(.classB, target, *) {
1512 color: purple;
1613 border: none;
1714 }

3330</style>
3431</head>
3532<body>
36  <p>This test checks the dynamic specificity of :is() changing the order in which rules are applied depending on the element. Each element should have the colors described in the text and no border.</p>
37  <nottarget>Purple text on red background.</nottarget>
38  <target>White text on green background.</target>
39  <nottarget id="classA">Purple text on red background.</nottarget>
40  <target id="classA">Purple text on red background.</target>
41  <nottarget class="classB">Purple text on blue background.</nottarget>
42  <target class="classB">Purple text on blue background.</target>
43  <nottarget id="classA" class="classB">Purple text on red background.</nottarget>
44  <target id="classA" class="classB">Purple text on red background.</target>
 33 <nottarget>Text</nottarget>
 34 <target>Text</target>
 35 <nottarget id="classA">Text</nottarget>
 36 <target id="classA">Text</target>
 37 <nottarget class="classB">Text</nottarget>
 38 <target class="classB">Text</target>
 39 <nottarget id="classA" class="classB">Text</nottarget>
 40 <target id="classA" class="classB">Text</target>
4541</body>
4642</html>

LayoutTests/fast/css/is-specificity-4-expected.html

11<!doctype html>
22<html>
33<body>
4  <p>This test the dynamic specificity of :is() with a complex selector. The text succeed if the text "Target" shows up in white on green background.</p>
54 <container>
65 <target style="background-color: green; color: white;">Target</target>
76 </container>

LayoutTests/fast/css/is-specificity-4.html

22<html>
33<head>
44<style>
5  /* The position of :is() should override this rule. */
65 container > target {
76 border: 5px solid black;
87 color: blue;
98 }
109
11  /* A class rule should supersede the following :is() because it has higher specificity. */
1210 .target {
1311 color: white;
1412 }
1513
16  /* The only subselector that matches is "container > target". It should override the simple "target"
17  selector but be superseded by anything larger than two tagnames. */
18  :is(foo.bar, bar.foo, container > target, foo#bar, bar#foo) {
 14 :is(foo, foo, container > target) {
1915 background-color: green;
2016 color: purple;
2117 border: 25px solid red;
2218 }
2319
24  /* Those two rules only have score one tagname, they cannot take precedence over :is(). */
2520 target {
2621 background-color: red;
2722 }

2924 color: black;
3025 }
3126
32  /* This rule should have the same specificity as the :is() but higher position. */
3327 container > target {
3428 border: none;
3529 }
3630</style>
3731</head>
3832<body>
39  <p>This test the dynamic specificity of :is() with a complex selector. The text succeed if the text "Target" shows up in white on green background.</p>
4033 <container>
4134 <target class="target">Target</target>
4235 </container>

LayoutTests/fast/css/is-specificity-5.html

66 content: "Target";
77 }
88
9  /* This rule has two .target, making it higher specificity than the rules below. */
109 .target:is(*, target, .target, *, target)::before {
1110 background-color: green;
1211 }
1312
14  /* This rule has a tagname and a class name, making it higher specificity than ".target:is(*)::before". */
1513 target:is(*, target, .target, *, target)::before {
1614 color: white;
1715 }

2119 color: blue;
2220 border: none;
2321 }
24  /* This rule only has (0, 0, 3) and it superseded by the rule above. */
2522 target:is(*, target, *)::before {
2623 border: 25px solid purple;
2724 }
2825
29  /* This rule has lower specificity than all the rules above and its property never applies. */
30  :is(#target, target)::before {
 26 :is(foo, target)::before {
3127 content: "Not Target";
3228 }
3329</style>

LayoutTests/fast/css/matches-specificity-10-expected.html

11<!doctype html>
22<html>
33<body>
4  <p>This test the dynamic specificity of :matches() with a simple descendant backtracking case. The test pass if each block has style matching its description. None of the result should have a border.</p>
5 
64 <foo id="b">
75 <foo id="c">
86 <e>

LayoutTests/fast/css/matches-specificity-10.html

22<html>
33<head>
44<style>
5  /* Specificity (2, 0, 2). */
6  #f#f > padding > target {
 5 /* Specificity (3, 0, 2). */
 6 #f#f#f > padding > target {
77 background-color: purple;
88 }
99

2323 border: 5px blue solid;
2424 }
2525
 26 /* Specificity (3, 0, 1) */
2627 :matches(aBlock, #b) > :matches(#c, d) > :matches(e, #f) target {
2728 background-color: green;
2829 color: white;
2930 border: none;
3031 }
 32
 33 /* Specificity (3, 0, 2) */
 34 #c#c#c padding target {
 35 background-color: green;
 36 }
 37
 38 /* Specificity (3, 0, 1) */
 39 #f#f#f target {
 40 background-color: green;
 41 }
 42
 43 /* Specificity (3, 0, 2) */
 44 a #f#f#f target {
 45 color: green;
 46 }
3147</style>
3248</head>
3349<body>
34  <p>This test the dynamic specificity of :matches() with a simple descendant backtracking case. The test pass if each block has style matching its description. None of the result should have a border.</p>
35 
36  <!--
37  This case should match ":matches(a, #b) > :matches(#c, d) > matches(e, #f) target"
38  like "#a > #c > e target"
39  with the specificity (2, 0, 2).
40  -->
4150 <foo id="b">
4251 <foo id="c">
4352 <e> <!-- Success case from here. -->

6473 </foo>
6574 </foo>
6675
67  <!--
68  This case should match ":matches(a, #b) > :matches(#c, d) > matches(e, #f) target"
69  like "#a > d > e target"
70  with the specificity (1, 0, 3).
71  -->
7276 <foo id="b">
7377 <d>
7478 <e> <!-- Success case from here. -->

9599 </d>
96100 </foo>
97101
98  <!--
99  This case should match ":matches(a, #b) > :matches(#c, d) > matches(e, #f) target"
100  like "a > d > e target"
101  with the specificity (0, 0, 4).
102  -->
103102 <aBlock>
104103 <d>
105104 <e> <!-- Success case from here. -->

LayoutTests/fast/css/matches-specificity-2-expected.html

88</style>
99</head>
1010<body>
11  <p>This test the specificity of :matches() with a dynamic specificity of zero. The test passes if the text "target" is displayed white on green background.</p>
12  <target style="background-color: green; color: white;">Target</target>
 11 <target style="color: blue;">Target</target>
1312</body>
1413</html>

LayoutTests/fast/css/matches-specificity-2.html

1515 background-color: green;
1616 }
1717
18  /* The only dynamic selector that matches is "*". Every rules except the first one (* selector) should override the style defined here.
19  Background-color is defined by the two tag selectors above.
20  Color is defined below by the star rule. It has the same specificity but a higher position.
21  Border overrides the black border defined in the first rule. */
2218 :matches(#foo, .bar, target.notthere, *, foo>bar) {
23  background-color: red;
 19 background-color: white;
2420 color: blue;
2521 border: none;
2622 }

3026</style>
3127</head>
3228<body>
33  <p>This test the specificity of :matches() with a dynamic specificity of zero. The test passes if the text "target" is displayed white on green background.</p>
3429 <target>Target</target>
3530</body>
3631</html>

LayoutTests/fast/css/matches-specificity-3-expected.html

11<!doctype html>
22<html>
3 <head>
4 <style>
5  body > * {
6  display: block;
7  }
8  html, body, p {
9  background-color: white;
10  color: black;
11  }
12 </style>
13 </head>
143<body>
15  <p>This test checks the dynamic specificity of matches changing the order in which rules are applied depending on the element. Each element should have the colors described in the text and no border.</p>
16  <nottarget style="color: purple; background-color: red;">Purple text on red background.</nottarget>
17  <target style="color: white; background-color: green;">White text on green background.</target>
18  <nottarget style="color: purple; background-color: red;">Purple text on red background.</nottarget>
19  <target style="color: purple; background-color: red;">Purple text on red background.</target>
20  <nottarget style="color: purple; background-color: blue;">Purple text on blue background.</nottarget>
21  <target style="color: purple; background-color: blue;">Purple text on blue background.</target>
22  <nottarget style="color: purple; background-color: red;">Purple text on red background.</nottarget>
23  <target style="color: purple; background-color: red;">Purple text on red background.</target>
 4<div style="color: purple; background-color: blue;">Text</div>
 5<div style="color: purple; background-color: green;">Text</div>
 6<div style="color: purple; background-color: blue;">Text</div>
 7<div style="color: purple; background-color: green;">Text</div>
 8<div style="color: purple; background-color: blue;">Text</div>
 9<div style="color: purple; background-color: blue;">Text</div>
 10<div style="color: purple; background-color: blue;">Text</div>
 11<div style="color: purple; background-color: blue;">Text</div>
2412</body>
2513</html>

LayoutTests/fast/css/matches-specificity-3.html

88 border: 5px solid black;
99 }
1010
11  /* The following :matches() gets a different class of specificity. Depending on what
12  matches, the later rules may override this or not. */
13  :matches(.classB, target, #classA, *) {
14  background-color: red;
 11 :matches(.classB, target, *) {
1512 color: purple;
1613 border: none;
1714 }

3330</style>
3431</head>
3532<body>
36  <p>This test checks the dynamic specificity of matches changing the order in which rules are applied depending on the element. Each element should have the colors described in the text and no border.</p>
37  <nottarget>Purple text on red background.</nottarget>
38  <target>White text on green background.</target>
39  <nottarget id="classA">Purple text on red background.</nottarget>
40  <target id="classA">Purple text on red background.</target>
41  <nottarget class="classB">Purple text on blue background.</nottarget>
42  <target class="classB">Purple text on blue background.</target>
43  <nottarget id="classA" class="classB">Purple text on red background.</nottarget>
44  <target id="classA" class="classB">Purple text on red background.</target>
 33 <nottarget>Text</nottarget>
 34 <target>Text</target>
 35 <nottarget id="classA">Text</nottarget>
 36 <target id="classA">Text</target>
 37 <nottarget class="classB">Text</nottarget>
 38 <target class="classB">Text</target>
 39 <nottarget id="classA" class="classB">Text</nottarget>
 40 <target id="classA" class="classB">Text</target>
4541</body>
4642</html>

LayoutTests/fast/css/matches-specificity-4-expected.html

11<!doctype html>
22<html>
33<body>
4  <p>This test the dynamic specificity of :matches() with a complex selector. The text succeed if the text "Target" shows up in white on green background.</p>
54 <container>
65 <target style="background-color: green; color: white;">Target</target>
76 </container>

LayoutTests/fast/css/matches-specificity-4.html

22<html>
33<head>
44<style>
5  /* The position of :matches() should override this rule. */
65 container > target {
76 border: 5px solid black;
87 color: blue;
98 }
109
11  /* A class rule should supersede the following :matches() because it has higher specificity. */
1210 .target {
1311 color: white;
1412 }
1513
16  /* The only subselector that matches is "container > target". It should override the simple "target"
17  selector but be superseded by anything larger than two tagnames. */
18  :matches(foo.bar, bar.foo, container > target, foo#bar, bar#foo) {
 14 :matches(foo, foo, container > target) {
1915 background-color: green;
2016 color: purple;
2117 border: 25px solid red;
2218 }
2319
24  /* Those two rules only have score one tagname, they cannot take precedence over :matches(). */
2520 target {
2621 background-color: red;
2722 }

2924 color: black;
3025 }
3126
32  /* This rule should have the same specificity as the :matches() but higher position. */
3327 container > target {
3428 border: none;
3529 }
3630</style>
3731</head>
3832<body>
39  <p>This test the dynamic specificity of :matches() with a complex selector. The text succeed if the text "Target" shows up in white on green background.</p>
4033 <container>
4134 <target class="target">Target</target>
4235 </container>

LayoutTests/fast/css/matches-specificity-5.html

66 content: "Target";
77 }
88
9  /* This rule has two .target, making it higher specificity than the rules below. */
109 .target:matches(*, target, .target, *, target)::before {
1110 background-color: green;
1211 }
1312
14  /* This rule has a tagname and a class name, making it higher specificity than ".target:matches(*)::before". */
1513 target:matches(*, target, .target, *, target)::before {
1614 color: white;
1715 }

2119 color: blue;
2220 border: none;
2321 }
24  /* This rule only has (0, 0, 3) and it superseded by the rule above. */
2522 target:matches(*, target, *)::before {
2623 border: 25px solid purple;
2724 }
2825
29  /* This rule has lower specificity than all the rules above and its property never applies. */
30  :matches(#target, target)::before {
 26 :matches(foo, target)::before {
3127 content: "Not Target";
3228 }
3329</style>

LayoutTests/fast/css/nth-child-specificity-2-expected.html

99</style>
1010</head>
1111<body>
12  <p>This test the specificity of :nth-child() with dynamic specificity. If the test pass, the style of each line should match its text description.</p>
1312 <div>
1413 <target style="background-color: white; color: black; border: none;">Black text on white background.</target>
1514 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
1615 <target style="background-color: green; color: red; border: none;">Red text on green background.</target>
17  <target style="background-color: green; color: white; border: 5px solid purple;">White text on green background with a purple border.</target>
 16 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
1817 <target style="background-color: white; color: black; border: 5px solid blue;">Black text on white background with a blue border.</target>
1918 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
2019 <target style="background-color: green; color: red; border: 5px solid blue;">Red text on green background with a blue border.</target>
2120 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
2221 </div>
2322</body>
24 </html>
2523\ No newline at end of file
 24</html>

LayoutTests/fast/css/nth-child-specificity-2.html

22<html>
33<head>
44<style>
5  /* The specifity varies with the element being matched. */
 5 /* (1, 1, 0) */
66 :nth-child(even of .foo, #bar, target) {
77 background-color: red;
88 color: white;

3030</style>
3131</head>
3232<body>
33  <p>This test the specificity of :nth-child() with dynamic specificity. If the test pass, the style of each line should match its text description.</p>
3433 <div>
3534 <target>Black text on white background.</target>
3635 <target>White text on red background with a purple border.</target>
3736 <target class="foo">Red text on green background.</target>
38  <target class="foo">White text on green background with a purple border.</target>
 37 <target class="foo">White text on red background with a purple border.</target>
3938 <target id="bar">Black text on white background with a blue border.</target>
4039 <target id="bar">White text on red background with a purple border.</target>
4140 <target class="foo" id="bar">Red text on green background with a blue border.</target>
4241 <target class="foo" id="bar">White text on red background with a purple border.</target>
4342 </div>
4443</body>
45 </html>
4644\ No newline at end of file
 45</html>

LayoutTests/fast/css/nth-child-specificity-3-expected.html

99</style>
1010</head>
1111<body>
12  <p>This test the specificity of :nth-child() with dynamic specificity of compound selectors. If the test pass, the style of each line should match its text description.</p>
1312 <div>
1413 <target>Black text.</target>
1514 <target>Black text.</target>
1615 <target style="color:red; border: 5px solid black;">Red text with black border.</target>
17  <target style="color:white; background-color:red; border: 5px solid black;">White text on red background with black border.</target>
 16 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
1817 <target style="border: 5px solid blue;">Black text with blue border.</target>
1918 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
2019 <target style="color:red; background-color:green; border: 5px solid blue;">Red text on green background with blue border.</target>
2120 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
2221 </div>
2322</body>
24 </html>
2523\ No newline at end of file
 24</html>

LayoutTests/fast/css/nth-child-specificity-3.html

22<html>
33<head>
44<style>
5  /* The specifity varies with the element being matched. */
 5 /* (1, 2, 1) */
66 :nth-child(even of target.foo, .foo#bar, target.foo#bar, target#bar) {
77 background-color: red;
88 color: white;

3434</style>
3535</head>
3636<body>
37  <p>This test the specificity of :nth-child() with dynamic specificity of compound selectors. If the test pass, the style of each line should match its text description.</p>
3837 <div>
3938 <target>Black text.</target>
4039 <target>Black text.</target>
4140 <target class="foo">Red text with black border.</target>
42  <target class="foo">White text on red background with black border.</target>
 41 <target class="foo">White text on red background with purple border.</target>
4342 <target id="bar">Black text with blue border.</target>
4443 <target id="bar">White text on red background with purple border.</target>
4544 <target class="foo" id="bar">Red text on green background with blue border.</target>
4645 <target class="foo" id="bar">White text on red background with purple border.</target>
4746 </div>
4847</body>
49 </html>
5048\ No newline at end of file
 49</html>

LayoutTests/fast/css/nth-child-specificity-4-expected.html

99</style>
1010</head>
1111<body>
12  <p>This test the specificity of :nth-child() with dynamic specificity of compound selectors. In this case, we verify the matching of siblings does not affect the specificity of the current element. If the test pass, the style of each line should match its text description.</p>
1312 <div>
1413 <target>Black text.</target>
1514 <target>Black text.</target>
1615 <target style="border: 5px solid blue;">Black text with blue border.</target>
17  <target style="color:white; background-color:red; border: 5px solid black;">White text on red background with black border.</target>
 16 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
1817 <target style="color:red; background-color:green; border: 5px solid blue;">Red text on green background with blue border.</target>
1918 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
2019 <target style="color:red; border: 5px solid black;">Red text with black border.</target>
2120 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
2221 </div>
2322</body>
24 </html>
2523\ No newline at end of file
 24</html>

LayoutTests/fast/css/nth-child-specificity-4.html

22<html>
33<head>
44<style>
5  /* The specifity varies with the element being matched. */
 5 /* (1, 2, 1) */
66 :nth-child(even of target.foo, .foo#bar, target.foo#bar, target#bar) {
77 background-color: red;
88 color: white;

3434</style>
3535</head>
3636<body>
37  <p>This test the specificity of :nth-child() with dynamic specificity of compound selectors. In this case, we verify the matching of siblings does not affect the specificity of the current element. If the test pass, the style of each line should match its text description.</p>
3837 <div>
3938 <target>Black text.</target>
4039 <target>Black text.</target>
4140 <target id="bar">Black text with blue border.</target>
42  <target class="foo">White text on red background with black border.</target>
 41 <target class="foo">White text on red background with purple border.</target>
4342 <target class="foo" id="bar">Red text on green background with blue border.</target>
4443 <target id="bar">White text on red background with purple border.</target>
4544 <target class="foo">Red text with black border.</target>
4645 <target class="foo" id="bar">White text on red background with purple border.</target>
4746 </div>
4847</body>
49 </html>
5048\ No newline at end of file
 49</html>

LayoutTests/fast/css/nth-last-child-specificity-2-expected.html

99</style>
1010</head>
1111<body>
12  <p>This test the specificity of :nth-last-child() with dynamic specificity. If the test pass, the style of each line should match its text description.</p>
1312 <div>
1413 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
1514 <target style="background-color: white; color: black; border: none;">Black text on white background.</target>
16  <target style="background-color: green; color: white; border: 5px solid purple;">White text on green background with a purple border.</target>
 15 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
1716 <target style="background-color: green; color: red; border: none;">Red text on green background.</target>
1817 <target style="background-color: red; color: white; border: 5px solid purple;">White text on red background with a purple border.</target>
1918 <target style="background-color: white; color: black; border: 5px solid blue;">Black text on white background with a blue border.</target>

2120 <target style="background-color: green; color: red; border: 5px solid blue;">Red text on green background with a blue border.</target>
2221 </div>
2322</body>
24 </html>
2523\ No newline at end of file
 24</html>

LayoutTests/fast/css/nth-last-child-specificity-2.html

22<html>
33<head>
44<style>
5  /* The specifity varies with the element being matched. */
 5 /* (1, 1, 0) */
66 :nth-last-child(even of .foo, #bar, target) {
77 background-color: red;
88 color: white;

3030</style>
3131</head>
3232<body>
33  <p>This test the specificity of :nth-last-child() with dynamic specificity. If the test pass, the style of each line should match its text description.</p>
3433 <div>
3534 <target>White text on red background with a purple border.</target>
3635 <target>Black text on white background.</target>
37  <target class="foo">White text on green background with a purple border.</target>
 36 <target class="foo">White text on red background with a purple border.</target>
3837 <target class="foo">Red text on green background.</target>
3938 <target id="bar">White text on red background with a purple border.</target>
4039 <target id="bar">Black text on white background with a blue border.</target>

4241 <target class="foo" id="bar">Red text on green background with a blue border.</target>
4342 </div>
4443</body>
45 </html>
4644\ No newline at end of file
 45</html>

LayoutTests/fast/css/nth-last-child-specificity-3-expected.html

99</style>
1010</head>
1111<body>
12  <p>This test the specificity of :nth-last-child() with dynamic specificity of compound selectors. If the test pass, the style of each line should match its text description.</p>
1312 <div>
1413 <target>Black text.</target>
1514 <target>Black text.</target>
16  <target style="color:white; background-color:red; border: 5px solid black;">White text on red background with black border.</target>
 15 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
1716 <target style="color:red; border: 5px solid black;">Red text with black border.</target>
1817 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
1918 <target style="border: 5px solid blue;">Black text with blue border.</target>

2120 <target style="color:red; background-color:green; border: 5px solid blue;">Red text on green background with blue border.</target>
2221 </div>
2322</body>
24 </html>
2523\ No newline at end of file
 24</html>

LayoutTests/fast/css/nth-last-child-specificity-3.html

22<html>
33<head>
44<style>
5  /* The specifity varies with the element being matched. */
 5 /* (1, 2, 1) */
66 :nth-last-child(even of target.foo, .foo#bar, target.foo#bar, target#bar) {
77 background-color: red;
88 color: white;

3434</style>
3535</head>
3636<body>
37  <p>This test the specificity of :nth-last-child() with dynamic specificity of compound selectors. If the test pass, the style of each line should match its text description.</p>
3837 <div>
3938 <target>Black text.</target>
4039 <target>Black text.</target>
41  <target class="foo">White text on red background with black border.</target>
 40 <target class="foo">White text on red background with purple border.</target>
4241 <target class="foo">Red text with black border.</target>
4342 <target id="bar">White text on red background with purple border.</target>
4443 <target id="bar">Black text with blue border.</target>

4645 <target class="foo" id="bar">Red text on green background with blue border.</target>
4746 </div>
4847</body>
49 </html>
5048\ No newline at end of file
 49</html>

LayoutTests/fast/css/nth-last-child-specificity-4-expected.html

99</style>
1010</head>
1111<body>
12  <p>This test the specificity of :nth-last-child() with dynamic specificity of compound selectors. In this case, we verify the matching of siblings does not affect the specificity of the current element. If the test pass, the style of each line should match its text description.</p>
1312 <div>
1413 <target>Black text.</target>
1514 <target>Black text.</target>
16  <target style="color:white; background-color:red; border: 5px solid black;">White text on red background with black border.</target>
 15 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
1716 <target style="border: 5px solid blue;">Black text with blue border.</target>
1817 <target style="color:white; background-color:red; border: 5px solid purple;">White text on red background with purple border.</target>
1918 <target style="color:red; background-color:green; border: 5px solid blue;">Red text on green background with blue border.</target>

2120 <target style="color:red; border: 5px solid black;">Red text with black border.</target>
2221 </div>
2322</body>
24 </html>
2523\ No newline at end of file
 24</html>

LayoutTests/fast/css/nth-last-child-specificity-4.html

22<html>
33<head>
44<style>
5  /* The specifity varies with the element being matched. */
 5 /* (1, 2, 1) */
66 :nth-last-child(even of target.foo, .foo#bar, target.foo#bar, target#bar) {
77 background-color: red;
88 color: white;

3434</style>
3535</head>
3636<body>
37  <p>This test the specificity of :nth-last-child() with dynamic specificity of compound selectors. In this case, we verify the matching of siblings does not affect the specificity of the current element. If the test pass, the style of each line should match its text description.</p>
3837 <div>
3938 <target>Black text.</target>
4039 <target>Black text.</target>
41  <target class="foo">White text on red background with black border.</target>
 40 <target class="foo">White text on red background with purple border.</target>
4241 <target id="bar">Black text with blue border.</target>
4342 <target id="bar">White text on red background with purple border.</target>
4443 <target class="foo" id="bar">Red text on green background with blue border.</target>

4645 <target class="foo">Red text with black border.</target>
4746 </div>
4847</body>
49 </html>
5048\ No newline at end of file
 49</html>

LayoutTests/imported/w3c/ChangeLog

 12020-04-14 Antti Koivisto <antti@apple.com>
 2
 3 [CSS Selectors] Selectors Level 4 specificity calculation for pseudo classes
 4 https://bugs.webkit.org/show_bug.cgi?id=210419
 5
 6 Reviewed by Simon Fraser.
 7
 8 * web-platform-tests/css/selectors/invalidation/is-expected.txt:
 9
1102020-04-14 Commit Queue <commit-queue@webkit.org>
211
312 Unreviewed, reverting r260024.

LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/is-expected.txt

@@PASS Invalidate :is() for simple selector arguments.
1313PASS Invalidate :is() for compound selector arguments.
1414PASS Invalidate :is() for complex selector arguments.
1515PASS Invalidate nested :is().
16 FAIL Test specificity of :is(). assert_equals: expected "rgb(0, 0, 255)" but got "rgb(0, 0, 0)"
 16PASS Test specificity of :is().
1717

Source/WebCore/ChangeLog

 12020-04-14 Antti Koivisto <antti@apple.com>
 2
 3 [CSS Selectors] Selectors Level 4 specificity calculation for pseudo classes
 4 https://bugs.webkit.org/show_bug.cgi?id=210419
 5
 6 Reviewed by Simon Fraser.
 7
 8 CSS selector specification drafts at some point had a concept of "dynamic specificity" where
 9 the specificity of a selector depended on the element it matched. It was only ever used with
 10 :matches and :nth-child pseudo classes and has subsequently been removed. Selector specificity
 11 can now always be computed statically.
 12
 13 There is a ton of code to support this obsolete feature. Remove it.
 14
 15 https://drafts.csswg.org/selectors-4/#specificity-rules
 16
 17 "The specificity of an :is(), :not(), or :has() pseudo-class is replaced by the specificity
 18 of the most specific complex selector in its selector list argument.
 19
 20 Analogously, the specificity of an :nth-child() or :nth-last-child() selector is the specificity
 21 of the pseudo class itself (counting as one pseudo-class selector) plus the specificity of the
 22 most specific complex selector in its selector list argument (if any)."
 23
 24 * css/html.css:
 25
 26 Reorganize a :matches rule into a selector list to keep the exact specificites.
 27 It matters here to select between listbox and menulist correctly based on the 'size' and 'multiple' attributes.
 28
 29 * css/CSSSelector.cpp:
 30 (WebCore::selectorSpecificity):
 31 (WebCore::maxSpecificity):
 32 (WebCore::simpleSelectorSpecificityInternal):
 33 (WebCore::CSSSelector::simpleSelectorSpecificity const):
 34
 35 Also handle nth here.
 36
 37 (WebCore::CSSSelector::specificity const):
 38 (WebCore::simpleSelectorFunctionalPseudoClassStaticSpecificity): Deleted.
 39 (WebCore::functionalPseudoClassStaticSpecificity): Deleted.
 40 (WebCore::staticSpecificityInternal): Deleted.
 41 (WebCore::CSSSelector::staticSpecificity const): Deleted.
 42
 43 Rename to just computeSpecificity(), there is no other kind than static.
 44
 45 * css/CSSSelector.h:
 46 * css/SelectorChecker.cpp:
 47 (WebCore::SelectorChecker::match const):
 48 (WebCore::SelectorChecker::matchHostPseudoClass const):
 49 (WebCore::SelectorChecker::matchRecursively const):
 50 (WebCore::SelectorChecker::checkOne const):
 51 (WebCore::SelectorChecker::matchSelectorList const):
 52
 53 SelectorChecker doesn't need to deal with specificity anymore.
 54
 55 * css/SelectorChecker.h:
 56 * cssjit/SelectorCompiler.cpp:
 57 (WebCore::SelectorCompiler::addNthChildType):
 58 (WebCore::SelectorCompiler::addPseudoClassType):
 59 (WebCore::SelectorCompiler::constructFragmentsInternal):
 60 (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
 61 (WebCore::SelectorCompiler::SelectorCodeGenerator::generateElementAttributeFunctionCallValueMatching):
 62
 63 Neither does SelectorCompiler.
 64
 65 * cssjit/SelectorCompiler.h:
 66 * dom/SelectorQuery.cpp:
 67 (WebCore::SelectorDataList::selectorMatches const):
 68 (WebCore::SelectorDataList::selectorClosest const):
 69 * inspector/InspectorStyleSheet.cpp:
 70 (WebCore::buildObjectForSelectorHelper):
 71 (WebCore::selectorsFromSource):
 72 (WebCore::InspectorStyleSheet::buildObjectForSelector):
 73 (WebCore::InspectorStyleSheet::buildObjectForSelectorList):
 74 (WebCore::InspectorStyleSheet::buildObjectForRule):
 75 (WebCore::InspectorStyleSheet::buildArrayForRuleList):
 76 (WebCore::hasDynamicSpecificity): Deleted.
 77 * inspector/InspectorStyleSheet.h:
 78 * inspector/agents/InspectorCSSAgent.cpp:
 79 (WebCore::InspectorCSSAgent::setRuleSelector):
 80 (WebCore::InspectorCSSAgent::addRule):
 81 (WebCore::InspectorCSSAgent::buildObjectForRule):
 82 (WebCore::InspectorCSSAgent::buildArrayForMatchedRuleList):
 83 * inspector/agents/InspectorDOMAgent.cpp:
 84 (WebCore::InspectorDOMAgent::highlightSelector):
 85 * style/ElementRuleCollector.cpp:
 86 (WebCore::Style::ElementRuleCollector::ruleMatches):
 87
 88 Switch to get the specificity from the selector instead of computing it during selector checking.
 89
 90 * style/ElementRuleCollector.h:
 91
1922020-04-14 Commit Queue <commit-queue@webkit.org>
293
394 Unreviewed, reverting r260024.

Source/WebCore/css/CSSSelector.cpp

@@void CSSSelector::createRareData()
9090 m_hasRareData = true;
9191}
9292
93 static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity);
 93static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector);
9494
95 static unsigned selectorSpecificity(const CSSSelector& firstSimpleSelector, bool isComputingMaximumSpecificity)
 95static unsigned selectorSpecificity(const CSSSelector& firstSimpleSelector)
9696{
97  unsigned total = simpleSelectorSpecificityInternal(firstSimpleSelector, isComputingMaximumSpecificity);
98 
99  for (const CSSSelector* selector = firstSimpleSelector.tagHistory(); selector; selector = selector->tagHistory())
100  total = CSSSelector::addSpecificities(total, simpleSelectorSpecificityInternal(*selector, isComputingMaximumSpecificity));
 97 unsigned total = 0;
 98 for (const CSSSelector* selector = &firstSimpleSelector; selector; selector = selector->tagHistory())
 99 total = CSSSelector::addSpecificities(total, simpleSelectorSpecificityInternal(*selector));
101100 return total;
102101}
103102

@@static unsigned maxSpecificity(const CSSSelectorList& selectorList)
105104{
106105 unsigned maxSpecificity = 0;
107106 for (const CSSSelector* subSelector = selectorList.first(); subSelector; subSelector = CSSSelectorList::next(subSelector))
108  maxSpecificity = std::max(maxSpecificity, selectorSpecificity(*subSelector, true));
 107 maxSpecificity = std::max(maxSpecificity, selectorSpecificity(*subSelector));
109108 return maxSpecificity;
110109}
111110
112 static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity)
 111static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector)
113112{
114113 ASSERT_WITH_MESSAGE(!simpleSelector.isForPage(), "At the time of this writing, page selectors are not treated as real selectors that are matched. The value computed here only account for real selectors.");
115114

@@static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelec
120119 case CSSSelector::PagePseudoClass:
121120 break;
122121 case CSSSelector::PseudoClass:
123  if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassIs || simpleSelector.pseudoClassType() == CSSSelector::PseudoClassMatches) {
124  ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :is()/:matches().");
125  if (!isComputingMaximumSpecificity)
126  return 0;
127  return maxSpecificity(*simpleSelector.selectorList());
128  }
129 
130  if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassNot) {
131  ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :not().");
 122 switch (simpleSelector.pseudoClassType()) {
 123 case CSSSelector::PseudoClassIs:
 124 case CSSSelector::PseudoClassMatches:
 125 case CSSSelector::PseudoClassNot:
132126 return maxSpecificity(*simpleSelector.selectorList());
 127 case CSSSelector::PseudoClassNthChild:
 128 case CSSSelector::PseudoClassNthLastChild:
 129 return CSSSelector::addSpecificities(static_cast<unsigned>(SelectorSpecificityIncrement::ClassB), simpleSelector.selectorList() ? maxSpecificity(*simpleSelector.selectorList()) : 0);
 130 default:
 131 break;
133132 }
134  FALLTHROUGH;
 133 return static_cast<unsigned>(SelectorSpecificityIncrement::ClassB);
135134 case CSSSelector::Exact:
136135 case CSSSelector::Class:
137136 case CSSSelector::Set:

@@static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelec
154153
155154unsigned CSSSelector::simpleSelectorSpecificity() const
156155{
157  return simpleSelectorSpecificityInternal(*this, false);
158 }
159 
160 static unsigned staticSpecificityInternal(const CSSSelector& firstSimpleSelector, bool& ok);
161 
162 static unsigned simpleSelectorFunctionalPseudoClassStaticSpecificity(const CSSSelector& simpleSelector, bool& ok)
163 {
164  if (simpleSelector.match() == CSSSelector::PseudoClass) {
165  CSSSelector::PseudoClassType pseudoClassType = simpleSelector.pseudoClassType();
166  if (pseudoClassType == CSSSelector::PseudoClassIs || pseudoClassType == CSSSelector::PseudoClassMatches || pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild) {
167  const CSSSelectorList* selectorList = simpleSelector.selectorList();
168  if (!selectorList) {
169  ASSERT_WITH_MESSAGE(pseudoClassType != CSSSelector::PseudoClassIs && pseudoClassType != CSSSelector::PseudoClassMatches, ":is()/:matches() should never be created without a valid selector list.");
170  return 0;
171  }
172 
173  const CSSSelector& firstSubselector = *selectorList->first();
174 
175  unsigned initialSpecificity = staticSpecificityInternal(firstSubselector, ok);
176  if (!ok)
177  return 0;
178 
179  const CSSSelector* subselector = &firstSubselector;
180  while ((subselector = CSSSelectorList::next(subselector))) {
181  unsigned subSelectorSpecificity = staticSpecificityInternal(*subselector, ok);
182  if (initialSpecificity != subSelectorSpecificity)
183  ok = false;
184  if (!ok)
185  return 0;
186  }
187  return initialSpecificity;
188  }
189  }
190  return 0;
191 }
192 
193 static unsigned functionalPseudoClassStaticSpecificity(const CSSSelector& firstSimpleSelector, bool& ok)
194 {
195  unsigned total = 0;
196  for (const CSSSelector* selector = &firstSimpleSelector; selector; selector = selector->tagHistory()) {
197  total = CSSSelector::addSpecificities(total, simpleSelectorFunctionalPseudoClassStaticSpecificity(*selector, ok));
198  if (!ok)
199  return 0;
200  }
201  return total;
202 }
203 
204 static unsigned staticSpecificityInternal(const CSSSelector& firstSimpleSelector, bool& ok)
205 {
206  unsigned staticSpecificity = selectorSpecificity(firstSimpleSelector, false);
207  return CSSSelector::addSpecificities(staticSpecificity, functionalPseudoClassStaticSpecificity(firstSimpleSelector, ok));
 156 return simpleSelectorSpecificityInternal(*this);
208157}
209158
210 unsigned CSSSelector::staticSpecificity(bool &ok) const
 159unsigned CSSSelector::computeSpecificity() const
211160{
212  ok = true;
213  return staticSpecificityInternal(*this, ok);
 161 return selectorSpecificity(*this);
214162}
215163
216164unsigned CSSSelector::addSpecificities(unsigned a, unsigned b)

Source/WebCore/css/CSSSelector.h

@@namespace WebCore {
5757 static const unsigned classMask = 0xff00;
5858 static const unsigned elementMask = 0xff;
5959
60  unsigned staticSpecificity(bool& ok) const;
 60 unsigned computeSpecificity() const;
6161 unsigned specificityForPage() const;
6262 unsigned simpleSelectorSpecificity() const;
6363 static unsigned addSpecificities(unsigned, unsigned);

Source/WebCore/css/SelectorChecker.cpp

@@SelectorChecker::SelectorChecker(Document& document)
170170{
171171}
172172
173 bool SelectorChecker::match(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const
 173bool SelectorChecker::match(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext) const
174174{
175  specificity = 0;
176 
177175 LocalContext context(selector, element, checkingContext.resolvingMode == SelectorChecker::Mode::QueryingRules ? VisitedMatchType::Disabled : VisitedMatchType::Enabled, checkingContext.pseudoId);
178176
179177 if (checkingContext.isMatchingHostPseudoClass) {

@@bool SelectorChecker::match(const CSSSelector& selector, const Element& element,
182180 }
183181
184182 PseudoIdSet pseudoIdSet;
185  MatchResult result = matchRecursively(checkingContext, context, pseudoIdSet, specificity);
 183 MatchResult result = matchRecursively(checkingContext, context, pseudoIdSet);
186184 if (result.match != Match::SelectorMatches)
187185 return false;
188186 if (checkingContext.pseudoId != PseudoId::None && !pseudoIdSet.has(checkingContext.pseudoId))

@@bool SelectorChecker::match(const CSSSelector& selector, const Element& element,
200198 return true;
201199}
202200
203 bool SelectorChecker::matchHostPseudoClass(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const
 201bool SelectorChecker::matchHostPseudoClass(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext) const
204202{
205203 ASSERT(element.shadowRoot());
206204 ASSERT(selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost);
207205
208  specificity = selector.simpleSelectorSpecificity();
209 
210206 if (auto* selectorList = selector.selectorList()) {
211207 LocalContext context(*selectorList->first(), element, VisitedMatchType::Enabled, PseudoId::None);
212208 context.inFunctionalPseudoClass = true;
213209 context.pseudoElementEffective = false;
214210 PseudoIdSet ignoreDynamicPseudo;
215  unsigned subselectorSpecificity = 0;
216  if (matchRecursively(checkingContext, context, ignoreDynamicPseudo, subselectorSpecificity).match != Match::SelectorMatches)
 211 if (matchRecursively(checkingContext, context, ignoreDynamicPseudo).match != Match::SelectorMatches)
217212 return false;
218  specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity);
219213 }
220214 return true;
221215}

@@static SelectorChecker::LocalContext localContextForParent(const SelectorChecker
263257// * SelectorFailsLocally - the selector fails for the element e
264258// * SelectorFailsAllSiblings - the selector fails for e and any sibling of e
265259// * SelectorFailsCompletely - the selector fails for e and any sibling or ancestor of e
266 SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet, unsigned& specificity) const
 260SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet) const
267261{
268262 MatchType matchType = MatchType::Element;
269263
270264 // The first selector has to match.
271  if (!checkOne(checkingContext, context, matchType, specificity))
 265 if (!checkOne(checkingContext, context, matchType))
272266 return MatchResult::fails(Match::SelectorFailsLocally);
273267
274268 if (context.selector->match() == CSSSelector::PseudoElement) {

@@SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
336330 nextContext.firstSelectorOfTheFragment = nextContext.selector;
337331 for (; nextContext.element; nextContext = localContextForParent(nextContext)) {
338332 PseudoIdSet ignoreDynamicPseudo;
339  unsigned descendantsSpecificity = 0;
340  MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, descendantsSpecificity);
 333 MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
341334 ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
342335
343  if (result.match == Match::SelectorMatches)
344  specificity = CSSSelector::addSpecificities(specificity, descendantsSpecificity);
345 
346336 if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
347337 return MatchResult::updateWithMatchType(result, matchType);
348338 }

@@SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
355345 return MatchResult::fails(Match::SelectorFailsCompletely);
356346 nextContext.firstSelectorOfTheFragment = nextContext.selector;
357347 PseudoIdSet ignoreDynamicPseudo;
358  unsigned childSpecificity = 0;
359  MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, childSpecificity);
 348 MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
360349 ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
361350
362  if (result.match == Match::SelectorMatches)
363  specificity = CSSSelector::addSpecificities(specificity, childSpecificity);
364 
365351 if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsCompletely)
366352 return MatchResult::updateWithMatchType(result, matchType);
367353 return MatchResult::fails(Match::SelectorFailsAllSiblings);

@@SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
381367 nextContext.element = previousElement;
382368 nextContext.firstSelectorOfTheFragment = nextContext.selector;
383369 PseudoIdSet ignoreDynamicPseudo;
384  unsigned adjacentSpecificity = 0;
385  MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, adjacentSpecificity);
 370 MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
386371 ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
387372
388  if (result.match == Match::SelectorMatches)
389  specificity = CSSSelector::addSpecificities(specificity, adjacentSpecificity);
390 
391373 return MatchResult::updateWithMatchType(result, matchType);
392374 }
393375 case CSSSelector::IndirectAdjacent: {

@@SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
400382 addStyleRelation(checkingContext, *nextContext.element, Style::Relation::AffectsNextSibling);
401383
402384 PseudoIdSet ignoreDynamicPseudo;
403  unsigned indirectAdjacentSpecificity = 0;
404  MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, indirectAdjacentSpecificity);
 385 MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
405386 ASSERT(!nextContext.pseudoElementEffective && !ignoreDynamicPseudo);
406387
407  if (result.match == Match::SelectorMatches)
408  specificity = CSSSelector::addSpecificities(specificity, indirectAdjacentSpecificity);
409 
410388 if (result.match == Match::SelectorMatches || result.match == Match::SelectorFailsAllSiblings || result.match == Match::SelectorFailsCompletely)
411389 return MatchResult::updateWithMatchType(result, matchType);
412390 };

@@SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
424402 && !(nextContext.hasScrollbarPseudo && nextContext.selector->match() == CSSSelector::PseudoClass))
425403 return MatchResult::fails(Match::SelectorFailsCompletely);
426404
427  unsigned subselectorSpecificity = 0;
428  MatchResult result = matchRecursively(checkingContext, nextContext, dynamicPseudoIdSet, subselectorSpecificity);
429 
430  if (result.match == Match::SelectorMatches)
431  specificity = CSSSelector::addSpecificities(specificity, subselectorSpecificity);
 405 MatchResult result = matchRecursively(checkingContext, nextContext, dynamicPseudoIdSet);
432406
433407 return MatchResult::updateWithMatchType(result, matchType);
434408 }

@@SelectorChecker::MatchResult SelectorChecker::matchRecursively(CheckingContext&
443417 nextContext.firstSelectorOfTheFragment = nextContext.selector;
444418 nextContext.isSubjectOrAdjacentElement = false;
445419 PseudoIdSet ignoreDynamicPseudo;
446  unsigned shadowDescendantSpecificity = 0;
447  MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo, shadowDescendantSpecificity);
448 
449  if (result.match == Match::SelectorMatches)
450  specificity = CSSSelector::addSpecificities(specificity, shadowDescendantSpecificity);
 420 MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
451421
452422 return MatchResult::updateWithMatchType(result, matchType);
453423 }

@@static inline bool tagMatches(const Element& element, const CSSSelector& simpleS
651621 return namespaceURI == starAtom() || namespaceURI == element.namespaceURI();
652622}
653623
654 bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalContext& context, MatchType& matchType, unsigned& specificity) const
 624bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalContext& context, MatchType& matchType) const
655625{
656626 const Element& element = *context.element;
657627 const CSSSelector& selector = *context.selector;
658628
659  specificity = CSSSelector::addSpecificities(specificity, selector.simpleSelectorSpecificity());
660 
661629 if (context.mayMatchHostPseudoClass) {
662630 // :host doesn't combine with anything except pseudo elements.
663631 bool isHostPseudoClass = selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost;

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
704672 subcontext.firstSelectorOfTheFragment = selectorList->first();
705673 PseudoIdSet ignoreDynamicPseudo;
706674
707  unsigned ignoredSpecificity;
708  if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches) {
 675 if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches) {
709676 ASSERT(!ignoreDynamicPseudo);
710677 return false;
711678 }

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
833800 case CSSSelector::PseudoClassMatches:
834801 {
835802 bool hasMatchedAnything = false;
836  unsigned maxSpecificity = 0;
837803
838804 MatchType localMatchType = MatchType::VirtualPseudoElementOnly;
839805 for (const CSSSelector* subselector = selector.selectorList()->first(); subselector; subselector = CSSSelectorList::next(subselector)) {

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
844810 subcontext.firstSelectorOfTheFragment = subselector;
845811 subcontext.pseudoId = PseudoId::None;
846812 PseudoIdSet localDynamicPseudoIdSet;
847  unsigned localSpecificity = 0;
848  MatchResult result = matchRecursively(checkingContext, subcontext, localDynamicPseudoIdSet, localSpecificity);
 813 MatchResult result = matchRecursively(checkingContext, subcontext, localDynamicPseudoIdSet);
849814
850815 // Pseudo elements are not valid inside :is()/:matches()
851816 if (localDynamicPseudoIdSet)
852817 continue;
853818
854819 if (result.match == Match::SelectorMatches) {
855  maxSpecificity = std::max(maxSpecificity, localSpecificity);
856 
857820 if (result.matchType == MatchType::Element)
858821 localMatchType = MatchType::Element;
859822
860823 hasMatchedAnything = true;
861824 }
862825 }
863  if (hasMatchedAnything) {
 826 if (hasMatchedAnything)
864827 matchType = localMatchType;
865  specificity = CSSSelector::addSpecificities(specificity, maxSpecificity);
866  }
867828 return hasMatchedAnything;
868829 }
869830 case CSSSelector::PseudoClassPlaceholderShown:

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
881842 break; // FIXME: Add the support for specifying relations on ShadowRoot.
882843
883844 if (const CSSSelectorList* selectorList = selector.selectorList()) {
884  unsigned selectorListSpecificity;
885  if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity))
 845 if (!matchSelectorList(checkingContext, context, element, *selectorList))
886846 return false;
887  specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity);
888847 }
889848
890849 int count = 1;
891850 if (const CSSSelectorList* selectorList = selector.selectorList()) {
892851 for (Element* sibling = ElementTraversal::previousSibling(element); sibling; sibling = ElementTraversal::previousSibling(*sibling)) {
893  unsigned ignoredSpecificity;
894  if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity))
 852 if (matchSelectorList(checkingContext, context, *sibling, *selectorList))
895853 ++count;
896854 }
897855 } else {

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
921879 if (is<Element>(parent)) {
922880 auto& parentElement = downcast<Element>(*parent);
923881 if (const CSSSelectorList* selectorList = selector.selectorList()) {
924  unsigned selectorListSpecificity;
925  if (!matchSelectorList(checkingContext, context, element, *selectorList, selectorListSpecificity))
 882 if (!matchSelectorList(checkingContext, context, element, *selectorList))
926883 return false;
927  specificity = CSSSelector::addSpecificities(specificity, selectorListSpecificity);
928884
929885 addStyleRelation(checkingContext, parentElement, Style::Relation::ChildrenAffectedByPropertyBasedBackwardPositionalRules);
930886 } else {

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
939895 int count = 1;
940896 if (const CSSSelectorList* selectorList = selector.selectorList()) {
941897 for (Element* sibling = ElementTraversal::nextSibling(element); sibling; sibling = ElementTraversal::nextSibling(*sibling)) {
942  unsigned ignoredSpecificity;
943  if (matchSelectorList(checkingContext, context, *sibling, *selectorList, ignoredSpecificity))
 898 if (matchSelectorList(checkingContext, context, *sibling, *selectorList))
944899 ++count;
945900 }
946901 } else

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
974929 for (subcontext.selector = selector.selectorList()->first(); subcontext.selector; subcontext.selector = CSSSelectorList::next(subcontext.selector)) {
975930 subcontext.firstSelectorOfTheFragment = subcontext.selector;
976931 PseudoIdSet ignoreDynamicPseudo;
977  unsigned ingoredSpecificity = 0;
978  if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, ingoredSpecificity).match == Match::SelectorMatches)
 932 if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches)
979933 return true;
980934 }
981935 }

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
10901044 case CSSSelector::PseudoClassHost: {
10911045 if (!context.mayMatchHostPseudoClass)
10921046 return false;
1093  unsigned hostSpecificity;
1094  if (!matchHostPseudoClass(selector, element, checkingContext, hostSpecificity))
1095  return false;
1096  specificity = CSSSelector::addSpecificities(specificity, hostSpecificity);
1097  return true;
 1047 return matchHostPseudoClass(selector, element, checkingContext);
10981048 }
10991049 case CSSSelector::PseudoClassDefined:
11001050 return isDefinedElement(element);

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
11471097 subcontext.inFunctionalPseudoClass = true;
11481098 subcontext.pseudoElementEffective = false;
11491099 PseudoIdSet ignoredDynamicPseudo;
1150  unsigned ignoredSpecificity = 0;
1151  if (matchRecursively(checkingContext, subcontext, ignoredDynamicPseudo, ignoredSpecificity).match == Match::SelectorMatches)
 1100 if (matchRecursively(checkingContext, subcontext, ignoredDynamicPseudo).match == Match::SelectorMatches)
11521101 return true;
11531102 }
11541103 return false;

@@bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalCont
12041153 return true;
12051154}
12061155
1207 bool SelectorChecker::matchSelectorList(CheckingContext& checkingContext, const LocalContext& context, const Element& element, const CSSSelectorList& selectorList, unsigned& specificity) const
 1156bool SelectorChecker::matchSelectorList(CheckingContext& checkingContext, const LocalContext& context, const Element& element, const CSSSelectorList& selectorList) const
12081157{
1209  specificity = 0;
12101158 bool hasMatchedAnything = false;
12111159
12121160 for (const CSSSelector* subselector = selectorList.first(); subselector; subselector = CSSSelectorList::next(subselector)) {

@@bool SelectorChecker::matchSelectorList(CheckingContext& checkingContext, const
12171165 subcontext.pseudoElementEffective = false;
12181166 subcontext.firstSelectorOfTheFragment = subselector;
12191167 PseudoIdSet ignoreDynamicPseudo;
1220  unsigned localSpecificity = 0;
1221  if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo, localSpecificity).match == Match::SelectorMatches) {
 1168 if (matchRecursively(checkingContext, subcontext, ignoreDynamicPseudo).match == Match::SelectorMatches) {
12221169 ASSERT(!ignoreDynamicPseudo);
12231170
12241171 hasMatchedAnything = true;
1225  specificity = std::max(specificity, localSpecificity);
12261172 }
12271173 }
12281174 return hasMatchedAnything;

Source/WebCore/css/SelectorChecker.h

@@public:
101101 PseudoIdSet pseudoIDSet;
102102 };
103103
104  bool match(const CSSSelector&, const Element&, CheckingContext&, unsigned& specificity) const;
 104 bool match(const CSSSelector&, const Element&, CheckingContext&) const;
105105
106  bool matchHostPseudoClass(const CSSSelector&, const Element&, CheckingContext&, unsigned& specificity) const;
 106 bool matchHostPseudoClass(const CSSSelector&, const Element&, CheckingContext&) const;
107107
108108 static bool isCommonPseudoClassSelector(const CSSSelector*);
109109 static bool matchesFocusPseudoClass(const Element&);

@@public:
116116 struct LocalContext;
117117
118118private:
119  MatchResult matchRecursively(CheckingContext&, const LocalContext&, PseudoIdSet&, unsigned& specificity) const;
120  bool checkOne(CheckingContext&, const LocalContext&, MatchType&, unsigned& specificity) const;
121  bool matchSelectorList(CheckingContext&, const LocalContext&, const Element&, const CSSSelectorList&, unsigned& specificity) const;
 119 MatchResult matchRecursively(CheckingContext&, const LocalContext&, PseudoIdSet&) const;
 120 bool checkOne(CheckingContext&, const LocalContext&, MatchType&) const;
 121 bool matchSelectorList(CheckingContext&, const LocalContext&, const Element&, const CSSSelectorList&) const;
122122
123123 bool checkScrollbarPseudoClass(const CheckingContext&, const Element&, const CSSSelector&) const;
124124

Source/WebCore/css/html.css

@@select {
970970}
971971
972972#if !(defined(WTF_PLATFORM_IOS_FAMILY) && WTF_PLATFORM_IOS_FAMILY)
973 select:matches([size], [multiple], [size][multiple]) {
 973select:matches([size], [multiple]), select[size][multiple] {
974974 -webkit-appearance: listbox;
975975 align-items: flex-start;
976976 border: 1px inset gray;

Source/WebCore/cssjit/SelectorCompiler.cpp

@@static inline FunctionType addScrollbarPseudoClassType(const CSSSelector&, Selec
464464}
465465
466466// Handle the forward :nth-child() and backward :nth-last-child().
467 static FunctionType addNthChildType(const CSSSelector& selector, SelectorContext selectorContext, FragmentPositionInRootFragments positionInRootFragments, CSSSelector::PseudoClassType firstMatchAlternative, bool visitedMatchEnabled, Vector<std::pair<int, int>, 2>& simpleCases, Vector<NthChildOfSelectorInfo>& filteredCases, HashSet<unsigned>& pseudoClasses, unsigned& internalSpecificity)
 467static FunctionType addNthChildType(const CSSSelector& selector, SelectorContext selectorContext, FragmentPositionInRootFragments positionInRootFragments, CSSSelector::PseudoClassType firstMatchAlternative, bool visitedMatchEnabled, Vector<std::pair<int, int>, 2>& simpleCases, Vector<NthChildOfSelectorInfo>& filteredCases, HashSet<unsigned>& pseudoClasses)
468468{
469469 int a = selector.nthA();
470470 int b = selector.nthB();

@@static FunctionType addNthChildType(const CSSSelector& selector, SelectorContext
482482 if (selectorContext != SelectorContext::QuerySelector)
483483 globalFunctionType = FunctionType::SelectorCheckerWithCheckingContext;
484484
485  unsigned firstFragmentListSpecificity = 0;
486  bool firstFragmentListSpecificitySet = false;
487 
488485 SelectorFragmentList* selectorFragments = nullptr;
489486 for (const CSSSelector* subselector = selectorList->first(); subselector; subselector = CSSSelectorList::next(subselector)) {
490487 if (!selectorFragments) {

@@static FunctionType addNthChildType(const CSSSelector& selector, SelectorContext
505502 return FunctionType::CannotCompile;
506503 }
507504
508  if (firstFragmentListSpecificitySet) {
509  // The CSS JIT does not handle dynamic specificity yet.
510  if (selectorContext == SelectorContext::RuleCollector && selectorFragments->staticSpecificity != firstFragmentListSpecificity)
511  return FunctionType::CannotCompile;
512  } else {
513  firstFragmentListSpecificitySet = true;
514  firstFragmentListSpecificity = selectorFragments->staticSpecificity;
515  }
516 
517505 globalFunctionType = mostRestrictiveFunctionType(globalFunctionType, functionType);
518506 selectorFragments = nullptr;
519507 }

@@static FunctionType addNthChildType(const CSSSelector& selector, SelectorContext
526514 if (nthChildOfSelectorInfo.selectorList.isEmpty())
527515 return FunctionType::CannotMatchAnything;
528516
529  internalSpecificity = firstFragmentListSpecificity;
530517 filteredCases.append(nthChildOfSelectorInfo);
531518 return globalFunctionType;
532519 }

@@static FunctionType addNthChildType(const CSSSelector& selector, SelectorContext
540527 return FunctionType::SelectorCheckerWithCheckingContext;
541528}
542529
543 static inline FunctionType addPseudoClassType(const CSSSelector& selector, SelectorFragment& fragment, unsigned& internalSpecificity, SelectorContext selectorContext, FragmentsLevel fragmentLevel, FragmentPositionInRootFragments positionInRootFragments, bool visitedMatchEnabled, VisitedMode& visitedMode, PseudoElementMatchingBehavior pseudoElementMatchingBehavior)
 530static inline FunctionType addPseudoClassType(const CSSSelector& selector, SelectorFragment& fragment, SelectorContext selectorContext, FragmentsLevel fragmentLevel, FragmentPositionInRootFragments positionInRootFragments, bool visitedMatchEnabled, VisitedMode& visitedMode, PseudoElementMatchingBehavior pseudoElementMatchingBehavior)
544531{
545532 CSSSelector::PseudoClassType type = selector.pseudoClassType();
546533 switch (type) {

@@static inline FunctionType addPseudoClassType(const CSSSelector& selector, Selec
722709 return FunctionType::SelectorCheckerWithCheckingContext;
723710
724711 case CSSSelector::PseudoClassNthChild:
725  return addNthChildType(selector, selectorContext, positionInRootFragments, CSSSelector::PseudoClassFirstChild, visitedMatchEnabled, fragment.nthChildFilters, fragment.nthChildOfFilters, fragment.pseudoClasses, internalSpecificity);
 712 return addNthChildType(selector, selectorContext, positionInRootFragments, CSSSelector::PseudoClassFirstChild, visitedMatchEnabled, fragment.nthChildFilters, fragment.nthChildOfFilters, fragment.pseudoClasses);
726713
727714 case CSSSelector::PseudoClassNthLastChild:
728  return addNthChildType(selector, selectorContext, positionInRootFragments, CSSSelector::PseudoClassLastChild, visitedMatchEnabled, fragment.nthLastChildFilters, fragment.nthLastChildOfFilters, fragment.pseudoClasses, internalSpecificity);
 715 return addNthChildType(selector, selectorContext, positionInRootFragments, CSSSelector::PseudoClassLastChild, visitedMatchEnabled, fragment.nthLastChildFilters, fragment.nthLastChildOfFilters, fragment.pseudoClasses);
729716
730717 case CSSSelector::PseudoClassNot:
731718 {

@@static inline FunctionType addPseudoClassType(const CSSSelector& selector, Selec
817804 SelectorList matchesList;
818805 const CSSSelectorList* selectorList = selector.selectorList();
819806 FunctionType functionType = FunctionType::SimpleSelectorChecker;
820  unsigned firstFragmentListSpecificity = 0;
821  bool firstFragmentListSpecificitySet = false;
822807 SelectorFragmentList* selectorFragments = nullptr;
823808 for (const CSSSelector* subselector = selectorList->first(); subselector; subselector = CSSSelectorList::next(subselector)) {
824809 if (!selectorFragments) {

@@static inline FunctionType addPseudoClassType(const CSSSelector& selector, Selec
841826 if (selectorFragments->first().pseudoElementSelector)
842827 return FunctionType::CannotCompile;
843828
844  if (firstFragmentListSpecificitySet) {
845  // The CSS JIT does not handle dynamic specificity yet.
846  if (selectorContext == SelectorContext::RuleCollector && selectorFragments->staticSpecificity != firstFragmentListSpecificity)
847  return FunctionType::CannotCompile;
848  } else {
849  firstFragmentListSpecificitySet = true;
850  firstFragmentListSpecificity = selectorFragments->staticSpecificity;
851  }
852 
853829 functionType = mostRestrictiveFunctionType(functionType, localFunctionType);
854830 selectorFragments = nullptr;
855831 }

@@static inline FunctionType addPseudoClassType(const CSSSelector& selector, Selec
863839 if (matchesList.isEmpty())
864840 return FunctionType::CannotMatchAnything;
865841
866  internalSpecificity = firstFragmentListSpecificity;
867 
868842 fragment.matchesFilters.append(matchesList);
869843
870844 return functionType;

@@static FunctionType constructFragmentsInternal(const CSSSelector* rootSelector,
919893 bool isRightmostOrAdjacent = positionInRootFragments != FragmentPositionInRootFragments::Other;
920894 FunctionType functionType = FunctionType::SimpleSelectorChecker;
921895 SelectorFragment* fragment = nullptr;
922  unsigned specificity = 0;
923896 for (const CSSSelector* selector = rootSelector; selector; selector = selector->tagHistory()) {
924897 if (!fragment) {
925898 selectorFragments.append(SelectorFragment());
926899 fragment = &selectorFragments.last();
927900 }
928901
929  specificity = CSSSelector::addSpecificities(specificity, selector->simpleSelectorSpecificity());
930 
931902 // A selector is invalid if something follows a pseudo-element.
932903 // We make an exception for scrollbar pseudo elements and allow a set of pseudo classes (but nothing else)
933904 // to follow the pseudo elements.

@@static FunctionType constructFragmentsInternal(const CSSSelector* rootSelector,
962933 if (fragment->pseudoElementSelector && isScrollbarPseudoElement(fragment->pseudoElementSelector->pseudoElementType()))
963934 functionType = mostRestrictiveFunctionType(functionType, addScrollbarPseudoClassType(*selector, *fragment));
964935 else {
965  unsigned internalSpecificity = 0;
966  functionType = mostRestrictiveFunctionType(functionType, addPseudoClassType(*selector, *fragment, internalSpecificity, selectorContext, fragmentLevel, subPosition, visitedMatchEnabled, visitedMode, pseudoElementMatchingBehavior));
967  specificity = CSSSelector::addSpecificities(specificity, internalSpecificity);
 936 functionType = mostRestrictiveFunctionType(functionType, addPseudoClassType(*selector, *fragment, selectorContext, fragmentLevel, subPosition, visitedMatchEnabled, visitedMode, pseudoElementMatchingBehavior));
968937 }
969938 if (!pseudoClassOnlyMatchesLinksInQuirksMode(*selector))
970939 fragment->onlyMatchesLinksInQuirksMode = false;

@@static FunctionType constructFragmentsInternal(const CSSSelector* rootSelector,
10731042
10741043 ASSERT(!fragment);
10751044
1076  selectorFragments.staticSpecificity = specificity;
 1045 selectorFragments.staticSpecificity = rootSelector->computeSpecificity();
10771046
10781047 return functionType;
10791048}

Source/WebCore/dom/SelectorQuery.cpp

@@inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData,
124124 SelectorChecker selectorChecker(element.document());
125125 SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
126126 selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
127  unsigned ignoredSpecificity;
128  return selectorChecker.match(*selectorData.selector, element, selectorCheckingContext, ignoredSpecificity);
 127 return selectorChecker.match(*selectorData.selector, element, selectorCheckingContext);
129128}
130129
131130inline Element* SelectorDataList::selectorClosest(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const

@@inline Element* SelectorDataList::selectorClosest(const SelectorData& selectorDa
133132 SelectorChecker selectorChecker(element.document());
134133 SelectorChecker::CheckingContext selectorCheckingContext(SelectorChecker::Mode::QueryingRules);
135134 selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode;
136  unsigned ignoredSpecificity;
137  if (!selectorChecker.match(*selectorData.selector, element, selectorCheckingContext, ignoredSpecificity))
 135 if (!selectorChecker.match(*selectorData.selector, element, selectorCheckingContext))
138136 return nullptr;
139137 return &element;
140138}

Source/WebCore/inspector/InspectorStyleSheet.cpp

@@RefPtr<Inspector::Protocol::CSS::CSSStyleSheetHeader> InspectorStyleSheet::build
10471047 .release();
10481048}
10491049
1050 static bool hasDynamicSpecificity(const CSSSelector& simpleSelector)
1051 {
1052  // It is possible that these can have a static specificity if each selector in the list has
1053  // equal specificity, but lets always report that they can be dynamic.
1054  for (const CSSSelector* selector = &simpleSelector; selector; selector = selector->tagHistory()) {
1055  if (selector->match() == CSSSelector::PseudoClass) {
1056  CSSSelector::PseudoClassType pseudoClassType = selector->pseudoClassType();
1057  if (pseudoClassType == CSSSelector::PseudoClassIs || pseudoClassType == CSSSelector::PseudoClassMatches)
1058  return true;
1059  if (pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild) {
1060  if (selector->selectorList())
1061  return true;
1062  return false;
1063  }
1064  }
1065  }
1066 
1067  return false;
1068 }
1069 
1070 static Ref<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelectorHelper(const String& selectorText, const CSSSelector& selector, Element* element)
 1050static Ref<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelectorHelper(const String& selectorText, const CSSSelector& selector)
10711051{
10721052 auto inspectorSelector = Inspector::Protocol::CSS::CSSSelector::create()
10731053 .setText(selectorText)
10741054 .release();
10751055
1076  if (element) {
1077  bool dynamic = hasDynamicSpecificity(selector);
1078  if (dynamic)
1079  inspectorSelector->setDynamic(true);
1080 
1081  SelectorChecker::CheckingContext context(SelectorChecker::Mode::CollectingRules);
1082  SelectorChecker selectorChecker(element->document());
1083 
1084  unsigned specificity;
1085  bool okay = selectorChecker.match(selector, *element, context, specificity);
1086  if (!okay)
1087  specificity = selector.staticSpecificity(okay);
1088 
1089  if (okay) {
1090  auto tuple = JSON::ArrayOf<int>::create();
1091  tuple->addItem(static_cast<int>((specificity & CSSSelector::idMask) >> 16));
1092  tuple->addItem(static_cast<int>((specificity & CSSSelector::classMask) >> 8));
1093  tuple->addItem(static_cast<int>(specificity & CSSSelector::elementMask));
1094  inspectorSelector->setSpecificity(WTFMove(tuple));
1095  }
1096  }
 1056 auto specificity = selector.computeSpecificity();
 1057
 1058 auto tuple = JSON::ArrayOf<int>::create();
 1059 tuple->addItem(static_cast<int>((specificity & CSSSelector::idMask) >> 16));
 1060 tuple->addItem(static_cast<int>((specificity & CSSSelector::classMask) >> 8));
 1061 tuple->addItem(static_cast<int>(specificity & CSSSelector::elementMask));
 1062 inspectorSelector->setSpecificity(WTFMove(tuple));
10971063
10981064 return inspectorSelector;
10991065}
11001066
1101 static Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSSelector>> selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText, const CSSSelectorList& selectorList, Element* element)
 1067static Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSSelector>> selectorsFromSource(const CSSRuleSourceData* sourceData, const String& sheetText, const CSSSelectorList& selectorList)
11021068{
11031069 static NeverDestroyed<JSC::Yarr::RegularExpression> comment("/\\*[^]*?\\*/", JSC::Yarr::TextCaseSensitive, JSC::Yarr::MultilineEnabled);
11041070

@@static Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSSelector>> selectorsFromSo
11151081
11161082 // We don't want to see any comments in the selector components, only the meaningful parts.
11171083 replace(selectorText, comment, String());
1118  result->addItem(buildObjectForSelectorHelper(selectorText.stripWhiteSpace(), *selector, element));
 1084 result->addItem(buildObjectForSelectorHelper(selectorText.stripWhiteSpace(), *selector));
11191085
11201086 selector = CSSSelectorList::next(selector);
11211087 }
11221088 return result;
11231089}
11241090
1125 Ref<Inspector::Protocol::CSS::CSSSelector> InspectorStyleSheet::buildObjectForSelector(const CSSSelector* selector, Element* element)
 1091Ref<Inspector::Protocol::CSS::CSSSelector> InspectorStyleSheet::buildObjectForSelector(const CSSSelector* selector)
11261092{
1127  return buildObjectForSelectorHelper(selector->selectorText(), *selector, element);
 1093 return buildObjectForSelectorHelper(selector->selectorText(), *selector);
11281094}
11291095
1130 Ref<Inspector::Protocol::CSS::SelectorList> InspectorStyleSheet::buildObjectForSelectorList(CSSStyleRule* rule, Element* element, int& endingLine)
 1096Ref<Inspector::Protocol::CSS::SelectorList> InspectorStyleSheet::buildObjectForSelectorList(CSSStyleRule* rule, int& endingLine)
11311097{
11321098 RefPtr<CSSRuleSourceData> sourceData;
11331099 if (ensureParsedDataReady())

@@Ref<Inspector::Protocol::CSS::SelectorList> InspectorStyleSheet::buildObjectForS
11381104 String selectorText = rule->selectorText();
11391105
11401106 if (sourceData)
1141  selectors = selectorsFromSource(sourceData.get(), m_parsedStyleSheet->text(), rule->styleRule().selectorList(), element);
 1107 selectors = selectorsFromSource(sourceData.get(), m_parsedStyleSheet->text(), rule->styleRule().selectorList());
11421108 else {
11431109 selectors = JSON::ArrayOf<Inspector::Protocol::CSS::CSSSelector>::create();
11441110 const CSSSelectorList& selectorList = rule->styleRule().selectorList();
11451111 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector))
1146  selectors->addItem(buildObjectForSelector(selector, element));
 1112 selectors->addItem(buildObjectForSelector(selector));
11471113 }
11481114 auto result = Inspector::Protocol::CSS::SelectorList::create()
11491115 .setSelectors(WTFMove(selectors))

@@Ref<Inspector::Protocol::CSS::SelectorList> InspectorStyleSheet::buildObjectForS
11541120 return result;
11551121}
11561122
1157 RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorStyleSheet::buildObjectForRule(CSSStyleRule* rule, Element* element)
 1123RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorStyleSheet::buildObjectForRule(CSSStyleRule* rule)
11581124{
11591125 CSSStyleSheet* styleSheet = pageStyleSheet();
11601126 if (!styleSheet)

@@RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorStyleSheet::buildObjectForRul
11621128
11631129 int endingLine = 0;
11641130 auto result = Inspector::Protocol::CSS::CSSRule::create()
1165  .setSelectorList(buildObjectForSelectorList(rule, element, endingLine))
 1131 .setSelectorList(buildObjectForSelectorList(rule, endingLine))
11661132 .setSourceLine(endingLine)
11671133 .setOrigin(m_origin)
11681134 .setStyle(buildObjectForStyle(&rule->style()))

@@Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSRule>> InspectorStyleSheet::build
14581424 collectFlatRules(WTFMove(refRuleList), &rules);
14591425
14601426 for (auto& rule : rules)
1461  result->addItem(buildObjectForRule(rule.get(), nullptr));
 1427 result->addItem(buildObjectForRule(rule.get()));
14621428
14631429 return result;
14641430}

Source/WebCore/inspector/InspectorStyleSheet.h

@@public:
174174 CSSStyleRule* ruleForId(const InspectorCSSId&) const;
175175 RefPtr<Inspector::Protocol::CSS::CSSStyleSheetBody> buildObjectForStyleSheet();
176176 RefPtr<Inspector::Protocol::CSS::CSSStyleSheetHeader> buildObjectForStyleSheetInfo();
177  RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(CSSStyleRule*, Element*);
 177 RefPtr<Inspector::Protocol::CSS::CSSRule> buildObjectForRule(CSSStyleRule*);
178178 RefPtr<Inspector::Protocol::CSS::CSSStyle> buildObjectForStyle(CSSStyleDeclaration*);
179179 ExceptionOr<void> setStyleText(const InspectorCSSId&, const String& text, String* oldText);
180180

@@private:
215215 bool inlineStyleSheetText(String* result) const;
216216 bool extensionStyleSheetText(String* result) const;
217217 Ref<JSON::ArrayOf<Inspector::Protocol::CSS::CSSRule>> buildArrayForRuleList(CSSRuleList*);
218  Ref<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelector(const CSSSelector*, Element*);
219  Ref<Inspector::Protocol::CSS::SelectorList> buildObjectForSelectorList(CSSStyleRule*, Element*, int& endingLine);
 218 Ref<Inspector::Protocol::CSS::CSSSelector> buildObjectForSelector(const CSSSelector*);
 219 Ref<Inspector::Protocol::CSS::SelectorList> buildObjectForSelectorList(CSSStyleRule*, int& endingLine);
220220
221221 InspectorPageAgent* m_pageAgent;
222222 String m_id;

Source/WebCore/inspector/agents/InspectorCSSAgent.cpp

@@void InspectorCSSAgent::setRuleSelector(ErrorString& errorString, const JSON::Ob
679679 return;
680680 }
681681
682  result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId), nullptr);
 682 result = inspectorStyleSheet->buildObjectForRule(inspectorStyleSheet->ruleForId(compoundId));
683683}
684684
685685void InspectorCSSAgent::createStyleSheet(ErrorString& errorString, const String& frameId, String* styleSheetId)

@@void InspectorCSSAgent::addRule(ErrorString& errorString, const String& styleShe
772772
773773 InspectorCSSId ruleId = rawAction.newRuleId();
774774 CSSStyleRule* rule = inspectorStyleSheet->ruleForId(ruleId);
775  result = inspectorStyleSheet->buildObjectForRule(rule, nullptr);
 775 result = inspectorStyleSheet->buildObjectForRule(rule);
776776}
777777
778778void InspectorCSSAgent::getSupportedCSSProperties(ErrorString&, RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::CSSPropertyInfo>>& cssProperties)

@@RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(
963963 return nullptr;
964964
965965 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(cssomWrapper->parentStyleSheet());
966  return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper, &element) : nullptr;
 966 return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(cssomWrapper) : nullptr;
967967}
968968
969969RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(CSSStyleRule* rule)

@@RefPtr<Inspector::Protocol::CSS::CSSRule> InspectorCSSAgent::buildObjectForRule(
973973
974974 ASSERT(rule->parentStyleSheet());
975975 InspectorStyleSheet* inspectorStyleSheet = bindStyleSheet(rule->parentStyleSheet());
976  return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule, nullptr) : nullptr;
 976 return inspectorStyleSheet ? inspectorStyleSheet->buildObjectForRule(rule) : nullptr;
977977}
978978
979979RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::buildArrayForMatchedRuleList(const Vector<RefPtr<const StyleRule>>& matchedRules, Style::Resolver& styleResolver, Element& element, PseudoId pseudoId)

@@RefPtr<JSON::ArrayOf<Inspector::Protocol::CSS::RuleMatch>> InspectorCSSAgent::bu
993993 const CSSSelectorList& selectorList = matchedRule->selectorList();
994994 int index = 0;
995995 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
996  unsigned ignoredSpecificity;
997  bool matched = selectorChecker.match(*selector, element, context, ignoredSpecificity);
 996 bool matched = selectorChecker.match(*selector, element, context);
998997 if (matched)
999998 matchingSelectors->addItem(index);
1000999 ++index;

Source/WebCore/inspector/agents/InspectorDOMAgent.cpp

@@void InspectorDOMAgent::highlightSelector(ErrorString& errorString, const JSON::
12911291 SelectorChecker::CheckingContext context(SelectorChecker::Mode::ResolvingStyle);
12921292 context.pseudoId = pseudoId;
12931293
1294  unsigned ignoredSpecificity;
1295  if (selectorChecker.match(*selector, descendantElement, context, ignoredSpecificity)) {
 1294 if (selectorChecker.match(*selector, descendantElement, context)) {
12961295 if (seenNodes.add(&descendantElement))
12971296 nodeList.append(descendantElement);
12981297 }

Source/WebCore/style/ElementRuleCollector.cpp

@@inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned
495495 }
496496 // Slow path.
497497 SelectorChecker selectorChecker(element().document());
498  selectorMatches = selectorChecker.match(*selector, element(), context, specificity);
 498 selectorMatches = selectorChecker.match(*selector, element(), context);
 499 if (selectorMatches)
 500 specificity = selector->computeSpecificity();
499501 }
500502
501503 if (ruleData.containsUncommonAttributeSelector()) {

Source/WebCore/style/ElementRuleCollector.h

@@private:
137137
138138 void collectMatchingRules(const MatchRequest&);
139139 void collectMatchingRulesForList(const RuleSet::RuleDataVector*, const MatchRequest&);
140  bool ruleMatches(const RuleData&, unsigned &specificity);
 140 bool ruleMatches(const RuleData&, unsigned& specificity);
141141
142142 void sortMatchedRules();
143143