Title: [284973] trunk
Revision
284973
Author
an...@apple.com
Date
2021-10-28 01:59:03 -0700 (Thu, 28 Oct 2021)

Log Message

Support ::before and ::after pseudo elements after ::slotted
https://bugs.webkit.org/show_bug.cgi?id=178237

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

Update the tests from WPT repo.

* web-platform-tests/css/css-scoping/host-context-parsing-expected.txt: Added.
* web-platform-tests/css/css-scoping/host-context-parsing.html: Added.
* web-platform-tests/css/css-scoping/host-parsing-expected.txt: Added.
* web-platform-tests/css/css-scoping/host-parsing.html: Added.
* web-platform-tests/css/css-scoping/keyframes-001-expected.txt:
* web-platform-tests/css/css-scoping/shadow-shared-style-cache-001-expected.txt: Added.
* web-platform-tests/css/css-scoping/shadow-shared-style-cache-001.html: Added.
* web-platform-tests/css/css-scoping/slotted-link-expected.txt:
* web-platform-tests/css/css-scoping/slotted-parsing-expected.txt:
* web-platform-tests/css/css-scoping/slotted-parsing.html:
* web-platform-tests/css/css-scoping/w3c-import.log:

Source/WebCore:

Change the way we resolve ::slotted to improve compatibility. We now traverse through the assigned slot chain in
a single pass, similar to ::part matching.

* css/CSSSelector.cpp:
(WebCore::CSSSelector::selectorText const):
* css/CSSSelector.h:

Add a new selection relation ShadowSlotted, similar to the existing ShadowDescendant and ShadowPartDescendant,
for switching scopes during selector matching.

* css/SelectorChecker.cpp:
(WebCore::SelectorChecker::matchRecursively const):

Find the right scope to continue matching on ShadowSlotted relation. Pass in the scope ordinal to find the scope.

(WebCore::SelectorChecker::checkOne const):

Match the ::slotted() element.

* css/SelectorChecker.h:
* css/SelectorFilter.cpp:
(WebCore::collectSelectorHashes):
* css/parser/CSSParserSelector.h:
(WebCore::CSSParserSelector::needsImplicitShadowCombinatorForMatching const):
* css/parser/CSSSelectorParser.cpp:
(WebCore::isPseudoClassValidAfterPseudoElement):
(WebCore::isTreeAbidingPseudoElement):

Add a spec-termed helper.

(WebCore::isSimpleSelectorValidAfterPseudoElement):
(WebCore::CSSSelectorParser::splitCompoundAtImplicitShadowCrossingCombinator):

Insert ShadowSlotted relation for ::slotted().

* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::fragmentRelationForSelectorRelation):
(WebCore::SelectorCompiler::constructFragmentsInternal):
* style/ElementRuleCollector.cpp:
(WebCore::Style::ElementRuleCollector::clearMatchedRules):
(WebCore::Style::ElementRuleCollector::matchSlottedPseudoElementRules):

Simply get the rules from scopes in the assinged slot chaing and match against them.
No need for two passes.

(WebCore::Style::ElementRuleCollector::ruleMatches):
(WebCore::Style::ElementRuleCollector::collectMatchingRulesForList):
(WebCore::Style::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot): Deleted.

Not needed anymore.

(WebCore::Style::findSlottedPseudoElementSelector): Deleted.
* style/ElementRuleCollector.h:
* style/RuleFeature.cpp:
(WebCore::Style::RuleFeatureSet::computeNextMatchElement):

LayoutTests:

* TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (284972 => 284973)


--- trunk/LayoutTests/ChangeLog	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/ChangeLog	2021-10-28 08:59:03 UTC (rev 284973)
@@ -1,3 +1,12 @@
+2021-10-28  Antti Koivisto  <an...@apple.com>
+
+        Support ::before and ::after pseudo elements after ::slotted
+        https://bugs.webkit.org/show_bug.cgi?id=178237
+
+        Reviewed by Ryosuke Niwa.
+
+        * TestExpectations:
+
 2021-10-28  Carlos Garcia Campos  <cgar...@igalia.com>
 
         AX: AXValueChanged is only sent for range elements when value is changed with the keyboard

Modified: trunk/LayoutTests/TestExpectations (284972 => 284973)


--- trunk/LayoutTests/TestExpectations	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/TestExpectations	2021-10-28 08:59:03 UTC (rev 284973)
@@ -3097,7 +3097,6 @@
 imported/w3c/web-platform-tests/css/css-display/run-in/run-in-text-between-004.xht [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-display/run-in/run-in-text-between-005.xht [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-pseudo/placeholder-input-number.html [ ImageOnlyFailure ]
-imported/w3c/web-platform-tests/css/css-scoping/slotted-with-pseudo-element.html [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-text-decor/text-emphasis-color-001.xht [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-text-decor/text-emphasis-position-above-left-001.xht [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-text-decor/text-emphasis-position-above-left-002.xht [ ImageOnlyFailure ]
@@ -3208,7 +3207,6 @@
 webkit.org/b/190032 compositing/layer-creation/translate-scale-transition-overlap.html [ Failure ]
 webkit.org/b/190032 compositing/layer-creation/translate-transition-overlap.html [ Failure ]
 webkit.org/b/190032 imported/w3c/web-platform-tests/css/css-logical/animation-003.tentative.html [ Failure ]
-webkit.org/b/190032 imported/w3c/web-platform-tests/css/css-scoping/keyframes-001.html [ Failure ]
 
 # FIXME: Need to implement MediaRecorder dataavailable event to support these testcases
 fast/mediacapturefromelement/CanvasCaptureMediaStream-imagebitmaprenderingcontext.html [ Skip ]

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (284972 => 284973)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-10-28 08:59:03 UTC (rev 284973)
@@ -1,3 +1,24 @@
+2021-10-28  Antti Koivisto  <an...@apple.com>
+
+        Support ::before and ::after pseudo elements after ::slotted
+        https://bugs.webkit.org/show_bug.cgi?id=178237
+
+        Reviewed by Ryosuke Niwa.
+
+        Update the tests from WPT repo.
+
+        * web-platform-tests/css/css-scoping/host-context-parsing-expected.txt: Added.
+        * web-platform-tests/css/css-scoping/host-context-parsing.html: Added.
+        * web-platform-tests/css/css-scoping/host-parsing-expected.txt: Added.
+        * web-platform-tests/css/css-scoping/host-parsing.html: Added.
+        * web-platform-tests/css/css-scoping/keyframes-001-expected.txt:
+        * web-platform-tests/css/css-scoping/shadow-shared-style-cache-001-expected.txt: Added.
+        * web-platform-tests/css/css-scoping/shadow-shared-style-cache-001.html: Added.
+        * web-platform-tests/css/css-scoping/slotted-link-expected.txt:
+        * web-platform-tests/css/css-scoping/slotted-parsing-expected.txt:
+        * web-platform-tests/css/css-scoping/slotted-parsing.html:
+        * web-platform-tests/css/css-scoping/w3c-import.log:
+
 2021-10-27  Kiet Ho  <th...@apple.com>
 
         Add discrete animation support between PathOperations

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing-expected.txt (0 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing-expected.txt	2021-10-28 08:59:03 UTC (rev 284973)
@@ -0,0 +1,9 @@
+
+FAIL ":host-context(.a)" should be a valid selector The string did not match the expected pattern.
+FAIL ":host-context(div.a)" should be a valid selector The string did not match the expected pattern.
+PASS ":host-context" should be an invalid selector
+PASS ":host-context()" should be an invalid selector
+PASS ":host-context(.a, .b)" should be an invalid selector
+PASS ":host-context(.a + .b)" should be an invalid selector
+PASS ":host-context(.a + .b, #c > #d)" should be an invalid selector
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing.html (0 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing.html	2021-10-28 08:59:03 UTC (rev 284973)
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Test parsing of the host-context() pseudo-classes</title>
+<link rel="help" href=""
+<script src=""
+<script src=""
+<script src=""
+<script>
+  test_valid_selector(':host-context(.a)');
+  test_valid_selector(':host-context(div.a)');
+
+  test_invalid_selector(':host-context');
+  test_invalid_selector(':host-context()');
+  test_invalid_selector(':host-context(.a, .b)');
+  test_invalid_selector(':host-context(.a + .b)');
+  test_invalid_selector(':host-context(.a + .b, #c > #d)');
+</script>

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing-expected.txt (0 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing-expected.txt	2021-10-28 08:59:03 UTC (rev 284973)
@@ -0,0 +1,9 @@
+
+PASS ":host" should be a valid selector
+PASS ":host(.a)" should be a valid selector
+PASS ":host(div.a)" should be a valid selector
+PASS ":host()" should be an invalid selector
+FAIL ":host(.a, .b)" should be an invalid selector assert_throws_dom: ":host(.a, .b)" should throw in querySelector function "() => document.querySelector(selector)" did not throw
+PASS ":host(.a + .b)" should be an invalid selector
+PASS ":host(.a + .b, #c > #d)" should be an invalid selector
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing.html (0 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing.html	2021-10-28 08:59:03 UTC (rev 284973)
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<title>Test parsing of the :host/host() pseudo-classes</title>
+<link rel="help" href=""
+<script src=""
+<script src=""
+<script src=""
+<script>
+  test_valid_selector(':host');
+  test_valid_selector(':host(.a)');
+  test_valid_selector(':host(div.a)');
+
+  test_invalid_selector(':host()');
+  test_invalid_selector(':host(.a, .b)');
+  test_invalid_selector(':host(.a + .b)');
+  test_invalid_selector(':host(.a + .b, #c > #d)');
+</script>

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/keyframes-001-expected.txt (284972 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/keyframes-001-expected.txt	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/keyframes-001-expected.txt	2021-10-28 08:59:03 UTC (rev 284973)
@@ -1,3 +1,3 @@
 
-FAIL @keyframes applies in the shadow tree assert_equals: expected 1 but got 0
+PASS @keyframes applies in the shadow tree
 

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001-expected.txt (0 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001-expected.txt	2021-10-28 08:59:03 UTC (rev 284973)
@@ -0,0 +1,3 @@
+
+PASS Shared style invalidation with removals
+

Added: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001.html (0 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001.html	                        (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001.html	2021-10-28 08:59:03 UTC (rev 284973)
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Shared style invalidation with removals</title>
+<link rel="help" href=""
+<link rel="help" href=""
+<link rel="author" href="" title="Emilio Cobos Álvarez">
+<link rel="author" href="" title="Mozilla">
+<script src=""
+<script src=""
+<div id="host-1"></div>
+<div id="host-2"></div>
+<script>
+const INITIALLY_COMMON_STYLE = `<style>:host { background-color: red !important }</style>`;
+let helper = document.querySelector("#host-1");
+let host = document.querySelector("#host-2");
+
+test(function() {
+  helper.attachShadow({ mode: "open" }).innerHTML = INITIALLY_COMMON_STYLE;
+  assert_equals(getComputedStyle(helper).backgroundColor, "rgb(255, 0, 0)", "Common style should apply to helper");
+
+  host.attachShadow({ mode: "open" }).innerHTML = INITIALLY_COMMON_STYLE;
+  assert_equals(getComputedStyle(host).backgroundColor, "rgb(255, 0, 0)", "Common style should apply to host");
+
+  host.shadowRoot.innerHTML = `<style>:host { background-color: lime; width: 100px; height: 100px; }</style>`;
+  assert_equals(getComputedStyle(host).backgroundColor, "rgb(0, 255, 0)", "Common style should no longer apply to host");
+});
+</script>

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-link-expected.txt (284972 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-link-expected.txt	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-link-expected.txt	2021-10-28 08:59:03 UTC (rev 284973)
@@ -1,4 +1,4 @@
 This link should be green.
 
-FAIL Check that we match :link and not :visited for slotted anchor. assert_equals: Unvisited link should be green. expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS Check that we match :link and not :visited for slotted anchor.
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-parsing-expected.txt (284972 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-parsing-expected.txt	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-parsing-expected.txt	2021-10-28 08:59:03 UTC (rev 284973)
@@ -7,10 +7,6 @@
 PASS "::slotted(*):host" should be an invalid selector
 PASS "::slotted(*):host(div)" should be an invalid selector
 PASS "::slotted(*):hover" should be an invalid selector
-PASS "::slotted(*):is(:hover)" should be an invalid selector
-PASS "::slotted(*):where(:hover)" should be an invalid selector
-PASS "::slotted(*):is(#id)" should be an invalid selector
-PASS "::slotted(*):where(#id)" should be an invalid selector
 PASS "::slotted(*):read-only" should be an invalid selector
 PASS "::slotted(*)::slotted(*)" should be an invalid selector
 PASS "::slotted(*)::before::slotted(*)" should be an invalid selector
@@ -19,10 +15,16 @@
 PASS "::slotted(div)" should be a valid selector
 PASS "::slotted([attr]:hover)" should be a valid selector
 PASS "::slotted(:not(.a))" should be a valid selector
-FAIL "::slotted(*)::before" should be a valid selector The string did not match the expected pattern.
-FAIL "::slotted(*)::after" should be a valid selector The string did not match the expected pattern.
+FAIL "::slotted(*):is()" should be a valid selector The string did not match the expected pattern.
+FAIL "::slotted(*):is(:hover)" should be a valid selector The string did not match the expected pattern.
+FAIL "::slotted(*):is(#id)" should be a valid selector The string did not match the expected pattern.
+FAIL "::slotted(*):where()" should be a valid selector The string did not match the expected pattern.
+FAIL "::slotted(*):where(:hover)" should be a valid selector The string did not match the expected pattern.
+FAIL "::slotted(*):where(#id)" should be a valid selector The string did not match the expected pattern.
+PASS "::slotted(*)::before" should be a valid selector
+PASS "::slotted(*)::after" should be a valid selector
 FAIL "::slotted(*)::placeholder" should be a valid selector The string did not match the expected pattern.
-FAIL "::slotted(*)::marker" should be a valid selector The string did not match the expected pattern.
+PASS "::slotted(*)::marker" should be a valid selector
 PASS "::slotted(*)::first-line" should be an invalid selector
 PASS "::slotted(*)::first-letter" should be an invalid selector
 PASS "::slotted(*)::selection" should be an invalid selector

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-parsing.html (284972 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-parsing.html	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-parsing.html	2021-10-28 08:59:03 UTC (rev 284973)
@@ -17,10 +17,6 @@
   test_invalid_selector("::slotted(*):host");
   test_invalid_selector("::slotted(*):host(div)");
   test_invalid_selector("::slotted(*):hover");
-  test_invalid_selector("::slotted(*):is(:hover)");
-  test_invalid_selector("::slotted(*):where(:hover)");
-  test_invalid_selector("::slotted(*):is(#id)");
-  test_invalid_selector("::slotted(*):where(#id)");
   test_invalid_selector("::slotted(*):read-only");
   test_invalid_selector("::slotted(*)::slotted(*)");
   test_invalid_selector("::slotted(*)::before::slotted(*)");
@@ -31,6 +27,14 @@
   test_valid_selector("::slotted([attr]:hover)");
   test_valid_selector("::slotted(:not(.a))");
 
+  test_valid_selector("::slotted(*):is()");
+  test_valid_selector("::slotted(*):is(:hover)", "::slotted(*):is()");
+  test_valid_selector("::slotted(*):is(#id)", "::slotted(*):is()");
+
+  test_valid_selector("::slotted(*):where()");
+  test_valid_selector("::slotted(*):where(:hover)", "::slotted(*):where()");
+  test_valid_selector("::slotted(*):where(#id)", "::slotted(*):where()");
+
   // Allow tree-abiding pseudo elements after ::slotted
   test_valid_selector("::slotted(*)::before");
   test_valid_selector("::slotted(*)::after");

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/w3c-import.log (284972 => 284973)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/w3c-import.log	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/w3c-import.log	2021-10-28 08:59:03 UTC (rev 284973)
@@ -52,6 +52,7 @@
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/css-scoping-shadow-with-rules-no-style-leak-expected.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/css-scoping-shadow-with-rules-no-style-leak.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/css-scoping-shadow-with-rules.html
+/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-parsing.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-specificity-001-expected.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-specificity-001.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-context-specificity-002-expected.html
@@ -69,6 +70,7 @@
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-multiple-001.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-nested-001-expected.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-nested-001.html
+/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-parsing.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-slotted-001-expected.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-slotted-001.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/host-specificity-002-expected.html
@@ -125,6 +127,7 @@
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-reassign-dynamic-004.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-root-insert-into-document-expected.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-root-insert-into-document.html
+/LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/shadow-shared-style-cache-001.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slot-non-html-display-value.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-invalidation.html
 /LayoutTests/imported/w3c/web-platform-tests/css/css-scoping/slotted-link.html

Modified: trunk/Source/WebCore/ChangeLog (284972 => 284973)


--- trunk/Source/WebCore/ChangeLog	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/ChangeLog	2021-10-28 08:59:03 UTC (rev 284973)
@@ -1,3 +1,66 @@
+2021-10-28  Antti Koivisto  <an...@apple.com>
+
+        Support ::before and ::after pseudo elements after ::slotted
+        https://bugs.webkit.org/show_bug.cgi?id=178237
+
+        Reviewed by Ryosuke Niwa.
+
+        Change the way we resolve ::slotted to improve compatibility. We now traverse through the assigned slot chain in
+        a single pass, similar to ::part matching.
+
+        * css/CSSSelector.cpp:
+        (WebCore::CSSSelector::selectorText const):
+        * css/CSSSelector.h:
+
+        Add a new selection relation ShadowSlotted, similar to the existing ShadowDescendant and ShadowPartDescendant,
+        for switching scopes during selector matching.
+
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::matchRecursively const):
+
+        Find the right scope to continue matching on ShadowSlotted relation. Pass in the scope ordinal to find the scope.
+
+        (WebCore::SelectorChecker::checkOne const):
+
+        Match the ::slotted() element.
+
+        * css/SelectorChecker.h:
+        * css/SelectorFilter.cpp:
+        (WebCore::collectSelectorHashes):
+        * css/parser/CSSParserSelector.h:
+        (WebCore::CSSParserSelector::needsImplicitShadowCombinatorForMatching const):
+        * css/parser/CSSSelectorParser.cpp:
+        (WebCore::isPseudoClassValidAfterPseudoElement):
+        (WebCore::isTreeAbidingPseudoElement):
+
+        Add a spec-termed helper.
+
+        (WebCore::isSimpleSelectorValidAfterPseudoElement):
+        (WebCore::CSSSelectorParser::splitCompoundAtImplicitShadowCrossingCombinator):
+
+        Insert ShadowSlotted relation for ::slotted().
+
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::fragmentRelationForSelectorRelation):
+        (WebCore::SelectorCompiler::constructFragmentsInternal):
+        * style/ElementRuleCollector.cpp:
+        (WebCore::Style::ElementRuleCollector::clearMatchedRules):
+        (WebCore::Style::ElementRuleCollector::matchSlottedPseudoElementRules):
+
+        Simply get the rules from scopes in the assinged slot chaing and match against them.
+        No need for two passes.
+
+        (WebCore::Style::ElementRuleCollector::ruleMatches):
+        (WebCore::Style::ElementRuleCollector::collectMatchingRulesForList):
+        (WebCore::Style::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot): Deleted.
+
+        Not needed anymore.
+
+        (WebCore::Style::findSlottedPseudoElementSelector): Deleted.
+        * style/ElementRuleCollector.h:
+        * style/RuleFeature.cpp:
+        (WebCore::Style::RuleFeatureSet::computeNextMatchElement):
+
 2021-10-28  Carlos Garcia Campos  <cgar...@igalia.com>
 
         AX: AXValueChanged is only sent for range elements when value is changed with the keyboard

Modified: trunk/Source/WebCore/css/CSSSelector.cpp (284972 => 284973)


--- trunk/Source/WebCore/css/CSSSelector.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/CSSSelector.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -823,6 +823,7 @@
 #endif
         case CSSSelector::ShadowDescendant:
         case CSSSelector::ShadowPartDescendant:
+        case CSSSelector::ShadowSlotted:
             builder.append(rightSide);
             return tagHistory->selectorText(builder.toString());
         }

Modified: trunk/Source/WebCore/css/CSSSelector.h (284972 => 284973)


--- trunk/Source/WebCore/css/CSSSelector.h	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/CSSSelector.h	2021-10-28 08:59:03 UTC (rev 284973)
@@ -87,7 +87,8 @@
             DirectAdjacent,
             IndirectAdjacent,
             ShadowDescendant,
-            ShadowPartDescendant
+            ShadowPartDescendant,
+            ShadowSlotted
         };
 
         enum PseudoClassType {

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (284972 => 284973)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -408,22 +408,40 @@
             return MatchResult::updateWithMatchType(result, matchType);
         }
     case CSSSelector::ShadowDescendant:
-    case CSSSelector::ShadowPartDescendant:
-        {
-            // When matching foo::part(bar) we skip directly to the tree of element 'foo'.
-            auto* shadowHost = relation == CSSSelector::ShadowPartDescendant ? checkingContext.shadowHostInPartRuleScope : context.element->shadowHost();
-            if (!shadowHost)
-                return MatchResult::fails(Match::SelectorFailsCompletely);
-            nextContext.element = shadowHost;
-            nextContext.firstSelectorOfTheFragment = nextContext.selector;
-            nextContext.isSubjectOrAdjacentElement = false;
-            PseudoIdSet ignoreDynamicPseudo;
-            MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
+    case CSSSelector::ShadowPartDescendant: {
+        // When matching foo::part(bar) we skip directly to the tree of element 'foo'.
+        auto* shadowHost = relation == CSSSelector::ShadowPartDescendant ? checkingContext.shadowHostInPartRuleScope : context.element->shadowHost();
+        if (!shadowHost)
+            return MatchResult::fails(Match::SelectorFailsCompletely);
+        nextContext.element = shadowHost;
+        nextContext.firstSelectorOfTheFragment = nextContext.selector;
+        nextContext.isSubjectOrAdjacentElement = false;
+        PseudoIdSet ignoreDynamicPseudo;
+        MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
 
-            return MatchResult::updateWithMatchType(result, matchType);
-        }
+        return MatchResult::updateWithMatchType(result, matchType);
     }
+    case CSSSelector::ShadowSlotted: {
+        auto* slot = context.element->assignedSlot();
+        if (!slot)
+            return MatchResult::fails(Match::SelectorFailsCompletely);
+        // We continue matching in the scope where this rule came from.
+        auto scopeDepth = static_cast<int>(checkingContext.styleScopeOrdinal);
+        while (--scopeDepth && slot->assignedSlot())
+            slot = slot->assignedSlot();
+        if (scopeDepth)
+            return MatchResult::fails(Match::SelectorFailsCompletely);
 
+        nextContext.element = slot;
+        nextContext.firstSelectorOfTheFragment = nextContext.selector;
+        nextContext.isSubjectOrAdjacentElement = false;
+        PseudoIdSet ignoreDynamicPseudo;
+        MatchResult result = matchRecursively(checkingContext, nextContext, ignoreDynamicPseudo);
+
+        return MatchResult::updateWithMatchType(result, matchType);
+    }
+    }
+
     ASSERT_NOT_REACHED();
     return MatchResult::fails(Match::SelectorFailsCompletely);
 }
@@ -1150,11 +1168,18 @@
             return false;
         }
 #endif
-        case CSSSelector::PseudoElementSlotted:
-            // We see ::slotted() pseudo elements when collecting slotted rules from the slot shadow tree only.
-            ASSERT(checkingContext.resolvingMode == Mode::CollectingRules);
-            return is<HTMLSlotElement>(element);
-
+        case CSSSelector::PseudoElementSlotted: {
+            if (!context.element->assignedSlot())
+                return false;
+            auto* subselector = context.selector->selectorList()->first();
+            LocalContext subcontext(context);
+            subcontext.selector = subselector;
+            subcontext.firstSelectorOfTheFragment = subselector;
+            subcontext.pseudoElementEffective = false;
+            subcontext.inFunctionalPseudoClass = true;
+            PseudoIdSet ignoredDynamicPseudo;
+            return matchRecursively(checkingContext, subcontext, ignoredDynamicPseudo).match == Match::SelectorMatches;
+        }
         case CSSSelector::PseudoElementPart: {
             auto translatePartNameToRuleScope = [&](AtomString partName) {
                 Vector<AtomString, 1> mappedNames { partName };

Modified: trunk/Source/WebCore/css/SelectorChecker.h (284972 => 284973)


--- trunk/Source/WebCore/css/SelectorChecker.h	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/SelectorChecker.h	2021-10-28 08:59:03 UTC (rev 284973)
@@ -30,6 +30,7 @@
 #include "CSSSelector.h"
 #include "Element.h"
 #include "StyleRelations.h"
+#include "StyleScopeOrdinal.h"
 
 namespace WebCore {
 
@@ -95,6 +96,7 @@
         const ContainerNode* scope { nullptr };
         bool isMatchingHostPseudoClass { false };
         const Element* shadowHostInPartRuleScope { nullptr };
+        Style::ScopeOrdinal styleScopeOrdinal { Style::ScopeOrdinal::Element };
 
         // FIXME: It would be nicer to have a separate object for return values. This requires some more work in the selector compiler.
         Style::Relations styleRelations;

Modified: trunk/Source/WebCore/css/SelectorFilter.cpp (284972 => 284973)


--- trunk/Source/WebCore/css/SelectorFilter.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/SelectorFilter.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -195,6 +195,7 @@
         case CSSSelector::IndirectAdjacent:
         case CSSSelector::ShadowDescendant:
         case CSSSelector::ShadowPartDescendant:
+        case CSSSelector::ShadowSlotted:
             skipOverSubselectors = true;
             break;
         case CSSSelector::DescendantSpace:

Modified: trunk/Source/WebCore/css/parser/CSSParserSelector.h (284972 => 284973)


--- trunk/Source/WebCore/css/parser/CSSParserSelector.h	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/parser/CSSParserSelector.h	2021-10-28 08:59:03 UTC (rev 284973)
@@ -103,6 +103,7 @@
             || pseudoElementType() == CSSSelector::PseudoElementCue
 #endif
             || pseudoElementType() == CSSSelector::PseudoElementPart
+            || pseudoElementType() == CSSSelector::PseudoElementSlotted
             || pseudoElementType() == CSSSelector::PseudoElementWebKitCustomLegacyPrefixed);
 }
 

Modified: trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp (284972 => 284973)


--- trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -343,6 +343,9 @@
     switch (compoundPseudoElement) {
     case CSSSelector::PseudoElementPart:
         return !isTreeStructuralPseudoClass(pseudoClass);
+    case CSSSelector::PseudoElementSlotted:
+        // FIXME: A WPT indicates :is/:where should be parsed but reduce to nothing as their content is not legal in the context.
+        return false;
     case CSSSelector::PseudoElementResizer:
     case CSSSelector::PseudoElementScrollbar:
     case CSSSelector::PseudoElementScrollbarCorner:
@@ -361,6 +364,19 @@
     }
 }
 
+static bool isTreeAbidingPseudoElement(CSSSelector::PseudoElementType pseudoElementType)
+{
+    switch (pseudoElementType) {
+    // FIXME: This list should also include ::placeholder and ::file-selector-button
+    case CSSSelector::PseudoElementBefore:
+    case CSSSelector::PseudoElementAfter:
+    case CSSSelector::PseudoElementMarker:
+        return true;
+    default:
+        return false;
+    }
+}
+
 static bool isSimpleSelectorValidAfterPseudoElement(const CSSParserSelector& simpleSelector, CSSSelector::PseudoElementType compoundPseudoElement)
 {
     if (compoundPseudoElement == CSSSelector::PseudoElementUnknown)
@@ -369,6 +385,10 @@
         if (simpleSelector.match() == CSSSelector::PseudoElement && simpleSelector.pseudoElementType() != CSSSelector::PseudoElementPart)
             return true;
     }
+    if (compoundPseudoElement == CSSSelector::PseudoElementSlotted) {
+        if (simpleSelector.match() == CSSSelector::PseudoElement && isTreeAbidingPseudoElement(simpleSelector.pseudoElementType()))
+            return true;
+    }
     if (simpleSelector.match() != CSSSelector::PseudoClass)
         return false;
     CSSSelector::PseudoClassType pseudo = simpleSelector.pseudoClassType();
@@ -1059,6 +1079,9 @@
     // ::part() combines with other pseudo elements.
     bool isPart = splitAfter->tagHistory()->match() == CSSSelector::PseudoElement && splitAfter->tagHistory()->pseudoElementType() == CSSSelector::PseudoElementPart;
 
+    // ::slotted() combines with other pseudo elements.
+    bool isSlotted = splitAfter->tagHistory()->match() == CSSSelector::PseudoElement && splitAfter->tagHistory()->pseudoElementType() == CSSSelector::PseudoElementSlotted;
+
     std::unique_ptr<CSSParserSelector> secondCompound;
     if (context.mode == UASheetMode || isPart) {
         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=161747
@@ -1068,7 +1091,14 @@
     } else
         secondCompound = splitAfter->releaseTagHistory();
 
-    secondCompound->appendTagHistory(isPart ? CSSSelector::ShadowPartDescendant : CSSSelector::ShadowDescendant, WTFMove(compoundSelector));
+    auto relation = [&] {
+        if (isSlotted)
+            return CSSSelector::ShadowSlotted;
+        if (isPart)
+            return CSSSelector::ShadowPartDescendant;
+        return CSSSelector::ShadowDescendant;
+    }();
+    secondCompound->appendTagHistory(relation, WTFMove(compoundSelector));
     return secondCompound;
 }
 

Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (284972 => 284973)


--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -501,6 +501,7 @@
     case CSSSelector::Subselector:
     case CSSSelector::ShadowDescendant:
     case CSSSelector::ShadowPartDescendant:
+    case CSSSelector::ShadowSlotted:
         ASSERT_NOT_REACHED();
     }
     ASSERT_NOT_REACHED();
@@ -1326,6 +1327,9 @@
         if ((relation == CSSSelector::ShadowDescendant || relation == CSSSelector::ShadowPartDescendant) && !selector->isLastInTagHistory())
             return FunctionType::CannotCompile;
 
+        if (relation == CSSSelector::ShadowSlotted)
+            return FunctionType::CannotCompile;
+
         if (relation == CSSSelector::DirectAdjacent || relation == CSSSelector::IndirectAdjacent) {
             FunctionType relationFunctionType = FunctionType::SelectorCheckerWithCheckingContext;
             if (selectorContext == SelectorContext::QuerySelector)

Modified: trunk/Source/WebCore/style/ElementRuleCollector.cpp (284972 => 284973)


--- trunk/Source/WebCore/style/ElementRuleCollector.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/style/ElementRuleCollector.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -120,7 +120,6 @@
 void ElementRuleCollector::clearMatchedRules()
 {
     m_matchedRules.clear();
-    m_keepAliveSlottedPseudoElementRules.clear();
     m_matchedRuleTransferIndex = 0;
 }
 
@@ -283,19 +282,11 @@
         auto& styleScope = Scope::forNode(*slot);
         if (!styleScope.resolver().ruleSets().isAuthorStyleDefined())
             continue;
-        // Find out if there are any ::slotted rules in the shadow tree matching the current slot.
-        // FIXME: This is really part of the slot style and could be cached when resolving it.
-        ElementRuleCollector collector(*slot, styleScope.resolver().ruleSets().authorStyle(), nullptr);
-        auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot();
-        if (!slottedPseudoElementRules)
-            continue;
-        // Match in the current scope.
-        SetForScope<bool> change(m_isMatchingSlottedPseudoElements, true);
 
-        MatchRequest scopeMatchRequest(nullptr, styleScopeOrdinal);
-        collectMatchingRulesForList(slottedPseudoElementRules.get(), scopeMatchRequest);
+        auto& scopeAuthorRules = styleScope.resolver().ruleSets().authorStyle();
 
-        m_keepAliveSlottedPseudoElementRules.append(WTFMove(slottedPseudoElementRules));
+        MatchRequest scopeMatchRequest(&scopeAuthorRules, styleScopeOrdinal);
+        collectMatchingRulesForList(&scopeAuthorRules.slottedPseudoElementRules(), scopeMatchRequest);
     }
 }
 
@@ -347,29 +338,6 @@
         collectMatchingRulesForList(rules.shadowPseudoElementRules(pseudoId), matchRequest);
 }
 
-std::unique_ptr<RuleSet::RuleDataVector> ElementRuleCollector::collectSlottedPseudoElementRulesForSlot()
-{
-    ASSERT(is<HTMLSlotElement>(element()));
-
-    clearMatchedRules();
-
-    m_mode = SelectorChecker::Mode::CollectingRules;
-
-    // Match global author rules.
-    MatchRequest matchRequest(m_authorStyle.ptr());
-    collectMatchingRulesForList(&m_authorStyle->slottedPseudoElementRules(), matchRequest);
-
-    if (m_matchedRules.isEmpty())
-        return { };
-
-    auto ruleDataVector = makeUnique<RuleSet::RuleDataVector>();
-    ruleDataVector->reserveInitialCapacity(m_matchedRules.size());
-    for (auto& matchedRule : m_matchedRules)
-        ruleDataVector->uncheckedAppend(*matchedRule.ruleData);
-
-    return ruleDataVector;
-}
-
 void ElementRuleCollector::matchUserRules()
 {
     if (!m_userStyle)
@@ -407,20 +375,8 @@
     sortAndTransferMatchedRules(DeclarationOrigin::UserAgent);
 }
 
-static const CSSSelector* findSlottedPseudoElementSelector(const CSSSelector* selector)
+inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity, ScopeOrdinal styleScopeOrdinal)
 {
-    for (; selector; selector = selector->tagHistory()) {
-        if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
-            if (auto* list = selector->selectorList())
-                return list->first();
-            break;
-        }
-    };
-    return nullptr;
-}
-
-inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
-{
     // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet.
     // This is limited to HTML only so we don't need to check the namespace (because of tag name match).
     auto matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash();
@@ -475,6 +431,7 @@
     context.nameForHightlightPseudoElement = m_pseudoElementRequest.highlightName;
     context.isMatchingHostPseudoClass = m_isMatchingHostPseudoClass;
     context.shadowHostInPartRuleScope = m_shadowHostInPartRuleScope.get();
+    context.styleScopeOrdinal = styleScopeOrdinal;
 
     bool selectorMatches;
 #if ENABLE(CSS_SELECTOR_JIT)
@@ -485,15 +442,9 @@
 #endif // ENABLE(CSS_SELECTOR_JIT)
     {
         auto* selector = ruleData.selector();
-        auto* selectorForMatching = selector;
-        if (m_isMatchingSlottedPseudoElements) {
-            selectorForMatching = findSlottedPseudoElementSelector(ruleData.selector());
-            if (!selectorForMatching)
-                return false;
-        }
         // Slow path.
         SelectorChecker selectorChecker(element().document());
-        selectorMatches = selectorChecker.match(*selectorForMatching, element(), context);
+        selectorMatches = selectorChecker.match(*selector, element(), context);
         if (selectorMatches)
             specificity = selector->computeSpecificity();
     }
@@ -535,7 +486,7 @@
             continue;
 
         unsigned specificity;
-        if (ruleMatches(ruleData, specificity))
+        if (ruleMatches(ruleData, specificity, matchRequest.styleScopeOrdinal))
             addMatchedRule(ruleData, specificity, matchRequest);
     }
 }

Modified: trunk/Source/WebCore/style/ElementRuleCollector.h (284972 => 284973)


--- trunk/Source/WebCore/style/ElementRuleCollector.h	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/style/ElementRuleCollector.h	2021-10-28 08:59:03 UTC (rev 284973)
@@ -135,11 +135,10 @@
     void matchPartPseudoElementRulesForScope(const ShadowRoot& scopeShadowRoot);
 
     void collectMatchingShadowPseudoElementRules(const MatchRequest&);
-    std::unique_ptr<RuleSet::RuleDataVector> collectSlottedPseudoElementRulesForSlot();
 
     void collectMatchingRules(const MatchRequest&);
     void collectMatchingRulesForList(const RuleSet::RuleDataVector*, const MatchRequest&);
-    bool ruleMatches(const RuleData&, unsigned& specificity);
+    bool ruleMatches(const RuleData&, unsigned& specificity, ScopeOrdinal);
 
     void sortMatchedRules();
 
@@ -163,10 +162,8 @@
     bool m_isPrintStyle { false };
     PseudoElementRequest m_pseudoElementRequest { PseudoId::None };
     SelectorChecker::Mode m_mode { SelectorChecker::Mode::ResolvingStyle };
-    bool m_isMatchingSlottedPseudoElements { false };
     bool m_isMatchingHostPseudoClass { false };
     RefPtr<const Element> m_shadowHostInPartRuleScope;
-    Vector<std::unique_ptr<RuleSet::RuleDataVector>> m_keepAliveSlottedPseudoElementRules;
 
     Vector<MatchedRule, 64> m_matchedRules;
     size_t m_matchedRuleTransferIndex { 0 };

Modified: trunk/Source/WebCore/style/RuleFeature.cpp (284972 => 284973)


--- trunk/Source/WebCore/style/RuleFeature.cpp	2021-10-28 08:36:34 UTC (rev 284972)
+++ trunk/Source/WebCore/style/RuleFeature.cpp	2021-10-28 08:59:03 UTC (rev 284973)
@@ -86,6 +86,9 @@
         case CSSSelector::ShadowDescendant:
         case CSSSelector::ShadowPartDescendant:
             return MatchElement::Host;
+        case CSSSelector::ShadowSlotted:
+            // FIXME: Implement accurate invalidation.
+            return matchElement;
         };
     }
     switch (relation) {
@@ -100,6 +103,9 @@
     case CSSSelector::ShadowDescendant:
     case CSSSelector::ShadowPartDescendant:
         return MatchElement::Host;
+    case CSSSelector::ShadowSlotted:
+        // FIXME: Implement accurate invalidation.
+        return matchElement;
     };
     ASSERT_NOT_REACHED();
     return matchElement;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to