Title: [255059] trunk
Revision
255059
Author
[email protected]
Date
2020-01-24 00:37:08 -0800 (Fri, 24 Jan 2020)

Log Message

:matches() doesn't combine correctly with pseudo elements
https://bugs.webkit.org/show_bug.cgi?id=206654

Reviewed by Simon Fraser.

Source/WebCore:

:matches() has been renamed to :is() in the spec (https://www.w3.org/TR/selectors-4/#matches).
Update the :matches implementation to spec behavior regarding pseudo element handling.

"Pseudo-elements cannot be represented by the matches-any pseudo-class; they are not valid within :is()."

Selectors like

    ::matches(foo, .parent .child)::first-letter

should work while

    ::matches(:first-letter)

shoudn't match anything.

Test: fast/selectors/matches-with-pseudo-element.html

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

Don't provide pseudoId into ::matches subselectors. Pseudo elements are not suppported inside ::matches.
If one if found, fail that subselector.

* css/SelectorChecker.h:

LayoutTests:

* TestExpectations:

Unskip fast/css/first-letter-and-float-crash.html which no longer hits assert due to this.

* fast/selectors/matches-with-pseudo-element-expected.html: Added.
* fast/selectors/matches-with-pseudo-element.html: Added.
* fast/css/currentColor-on-before-after-pseudo-elements.html:
* fast/css/matches-specificity-5.html:
* fast/selectors/pseudo-element-inside-matches-expected.html:
* fast/selectors/pseudo-element-inside-matches.html:

Update the existing tests to match the behavior.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (255058 => 255059)


--- trunk/LayoutTests/ChangeLog	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/LayoutTests/ChangeLog	2020-01-24 08:37:08 UTC (rev 255059)
@@ -1,3 +1,23 @@
+2020-01-24  Antti Koivisto  <[email protected]>
+
+        :matches() doesn't combine correctly with pseudo elements
+        https://bugs.webkit.org/show_bug.cgi?id=206654
+
+        Reviewed by Simon Fraser.
+
+        * TestExpectations:
+
+        Unskip fast/css/first-letter-and-float-crash.html which no longer hits assert due to this.
+
+        * fast/selectors/matches-with-pseudo-element-expected.html: Added.
+        * fast/selectors/matches-with-pseudo-element.html: Added.
+        * fast/css/currentColor-on-before-after-pseudo-elements.html:
+        * fast/css/matches-specificity-5.html:
+        * fast/selectors/pseudo-element-inside-matches-expected.html:
+        * fast/selectors/pseudo-element-inside-matches.html:
+
+        Update the existing tests to match the behavior.
+
 2020-01-24  youenn fablet  <[email protected]>
 
         Make sure fetch tasks go to network if service worker never gets to activated

Modified: trunk/LayoutTests/TestExpectations (255058 => 255059)


--- trunk/LayoutTests/TestExpectations	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/LayoutTests/TestExpectations	2020-01-24 08:37:08 UTC (rev 255059)
@@ -2914,8 +2914,6 @@
 webkit.org/b/167729 imported/w3c/web-platform-tests/css/css-lists/list-style-type-string-007.html [ ImageOnlyFailure ]
 imported/w3c/web-platform-tests/css/css-lists/list-with-image-display-changed-001.html [ ImageOnlyFailure ]
 
-[ Debug ] fast/css/first-letter-and-float-crash.html [ Skip ]
-
 webkit.org/b/196274 imported/w3c/web-platform-tests/xhr/send-redirect-post-upload.htm [ Pass Failure ]
 
 # If requestAnimationFrame is invoked before ResizeObserver timer fired, it would pass, otherwise it would fail same as eventloop-expected.txt

Modified: trunk/LayoutTests/fast/css/currentColor-on-before-after-pseudo-elements.html (255058 => 255059)


--- trunk/LayoutTests/fast/css/currentColor-on-before-after-pseudo-elements.html	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/LayoutTests/fast/css/currentColor-on-before-after-pseudo-elements.html	2020-01-24 08:37:08 UTC (rev 255059)
@@ -1,4 +1,4 @@
 <!DOCTYPE html>
-<style>span:matches(::before, ::after) { content: 'FAIL'; background: currentColor; }</style>
+<style>span::before, span::after { content: 'FAIL'; background: currentColor; }</style>
 <p>There should be a blue block below:
-<p><span style="color:white"></span> <span style="color:navy"></span>
\ No newline at end of file
+<p><span style="color:white"></span> <span style="color:navy"></span>

Modified: trunk/LayoutTests/fast/css/matches-specificity-5.html (255058 => 255059)


--- trunk/LayoutTests/fast/css/matches-specificity-5.html	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/LayoutTests/fast/css/matches-specificity-5.html	2020-01-24 08:37:08 UTC (rev 255059)
@@ -7,28 +7,27 @@
     }
 
     /* This rule has two .target, making it higher specificity than the rules below. */
-    .target:matches(::before, target::before, .target::before, ::before, target::before) {
+    .target:matches(*, target, .target, *, target)::before {
         background-color: green;
     }
 
-    /* This rule has a tagname and a class name, making it higher specificity than ".target:matches(::before)". */
-    target:matches(::before, target::before, .target::before, ::before, target::before) {
+    /* This rule has a tagname and a class name, making it higher specificity than ".target:matches(*)::before". */
+    target:matches(*, target, .target, *, target)::before {
         color: white;
     }
 
-    .target:matches(::before) {
+    .target:matches(*)::before {
         background-color: red;
         color: blue;
         border: none;
     }
-
     /* This rule only has (0, 0, 3) and it superseded by the rule above. */
-    target:matches(::before, target::before, ::before) {
+    target:matches(*, target, *)::before {
         border: 25px solid purple;
     }
 
     /* This rule has lower specificity than all the rules above and its property never applies. */
-    :matches(#target::before, target::before) {
+    :matches(#target, target)::before {
         content: "Not Target";
     }
 </style>

Added: trunk/LayoutTests/fast/selectors/matches-with-pseudo-element-expected.html (0 => 255059)


--- trunk/LayoutTests/fast/selectors/matches-with-pseudo-element-expected.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/matches-with-pseudo-element-expected.html	2020-01-24 08:37:08 UTC (rev 255059)
@@ -0,0 +1,7 @@
+<style>
+span {
+    font-weight: bold;
+}
+</style>
+
+<div><div><span>T</span>he first letter should be bold</div></div>

Added: trunk/LayoutTests/fast/selectors/matches-with-pseudo-element.html (0 => 255059)


--- trunk/LayoutTests/fast/selectors/matches-with-pseudo-element.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/matches-with-pseudo-element.html	2020-01-24 08:37:08 UTC (rev 255059)
@@ -0,0 +1,7 @@
+<style>
+:matches(foobar, .outer .inner)::first-letter {
+    font-weight: bold;
+}
+</style>
+
+<div class=outer><div class=inner>The first letter should be bold</div></div>

Modified: trunk/LayoutTests/fast/selectors/pseudo-element-inside-matches-expected.html (255058 => 255059)


--- trunk/LayoutTests/fast/selectors/pseudo-element-inside-matches-expected.html	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/LayoutTests/fast/selectors/pseudo-element-inside-matches-expected.html	2020-01-24 08:37:08 UTC (rev 255059)
@@ -6,51 +6,20 @@
     background-color: lime;
 }
 
-#target2::after {
+#target5 {
     background-color: lime;
-    content: "cocoa";
 }
 
-#target3::before {
-    background-color: lime;
-    content: "cappuccino";
-}
 
-#target4::before,
-#target4::after {
+#target7 {
     background-color: lime;
-    content: "around";
 }
 
-#target5,
-#target5::first-letter {
-    background-color: lime;
-}
-
-#target6,
-#target6::first-letter {
-    background-color: lime;
-}
-
-#target7,
-#target7::before,
-#target7::after {
-    background-color: lime;
-    content: "around";
-}
-
-/* first letter of before content is colored blue. */
-#target12::after,
-#target12::before {
-    background-color: lime;
-    content: "around";
-}
-
 #target12::first-letter {
-    background-color: blue;
+    background-color: blue !important;
 }
 
-#target16 > p {
+#target16 > span {
     background-color: lime;
 }
 
@@ -58,22 +27,22 @@
 </head>
 <body>
 <div>
-    <p id="target1">pseudo element inside :matches has effect.</p>
-    <p id="target2">pseudo element inside :matches has effect.</p>
-    <p id="target3">pseudo element inside :matches has effect.</p>
-    <p id="target4">pseudo element inside :matches has effect.</p>
-    <p id="target5">pseudo element inside :matches has effect, so all selectors should be checked.</p>
-    <p id="target6">pseudo element inside nested :matches should have effect.</p>
-    <p id="target7">both line itself and before/after should be colored.</p>
+    <p id="target1">pseudo element outside :matches has effect.</p>
+    <p id="target2">pseudo element inside :matches has no effect.</p>
+    <p id="target3">pseudo element inside :matches has no effect.</p>
+    <p id="target4">pseudo element inside :matches has no effect.</p>
+    <p id="target5">pseudo element inside :matches has no effect, so the rest of the selectors should be checked.</p>
+    <p id="target6">pseudo element inside nested :matches should have no effect.</p>
+    <p id="target7">::before/after have no effect.</p>
     <p id="target8">pseudo element inside :not doesn't have effect.</p>
     <p id="target9">::first-line in non-rightmost fragment always unmatch.</p>
     <p id="target10">:matches(::first-line) in non-rightmost fragment always unmatches.</p>
     <p id="target11">pseudo element in non-rightmost fragment inside :matches always unmatches.</p>
-    <p id="target12">before/after contents are colored lime and first-letter of before content is colored blue.</p>
+    <p id="target12">first-letter is colored blue.</p>
     <p id="target13">non-rightmost pseudo element has no effect.</p>
-    <p id="target14"><p>non-rightmost pseudo element has no effect.</p></p>
-    <p id="target15"><p>non-rightmost pseudo element has no effect.</p></p>
-    <p id="target16"><p>matchType should be effective for normal element.</p></p>
+    <p id="target14"><span>non-rightmost pseudo element has no effect.</span></p>
+    <p id="target15"><span>non-rightmost pseudo element has no effect.</span></p>
+    <p id="target16"><span>matchType should be effective for normal element.</span></p>
 </div>
 </body>
 </html>

Modified: trunk/LayoutTests/fast/selectors/pseudo-element-inside-matches.html (255058 => 255059)


--- trunk/LayoutTests/fast/selectors/pseudo-element-inside-matches.html	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/LayoutTests/fast/selectors/pseudo-element-inside-matches.html	2020-01-24 08:37:08 UTC (rev 255059)
@@ -2,22 +2,22 @@
 <html>
 <head>
 <style>
-#target1:matches(::first-letter) {
+#target1:matches(*)::first-letter {
     background-color: lime;
 }
 
-#target2:matches(::after) {
-    background-color: lime;
+#target2:matches(::first-letter) {
+    background-color: red;
     content: "cocoa";
 }
 
 #target3:matches(::before) {
-    background-color: lime;
+    background-color: red;
     content: "cappuccino";
 }
 
 #target4:matches(::before, ::after) {
-    background-color: lime;
+    background-color: red;
     content: "around";
 }
 
@@ -25,8 +25,8 @@
     background-color: lime;
 }
 
-#target6:matches(p, :matches(p, ::first-letter)) {
-    background-color: lime;
+#target6:matches(nonexistents, :matches(nonexistents, ::first-letter)) {
+    background-color: red;
 }
 
 #target7:matches(::before, ::after, *) {
@@ -50,9 +50,8 @@
     background-color: red;
 }
 
-/* first letter of before content is colored blue. */
 #target12:matches(::first-letter, ::after, ::before) {
-    background-color: lime;
+    background-color: red;
     content: "around";
 }
 
@@ -60,20 +59,20 @@
     background-color: blue !important;
 }
 
-#target13:matches(::after > p) {
+#target13:matches(::after > span) {
     background-color: red;
     content: "bug";
 }
 
-#target14:matches(::after) > p {
+#target14:matches(::after) > span {
     background-color: red;
 }
 
-#target15:matches(::after > p) > p {
+#target15:matches(::after > span) > span {
     background-color: red;
 }
 
-#target16:matches(*) > p {
+#target16:matches(*) > span {
     background-color: lime;
 }
 
@@ -81,22 +80,22 @@
 </head>
 <body>
 <div>
-    <p id="target1">pseudo element inside :matches has effect.</p>
-    <p id="target2">pseudo element inside :matches has effect.</p>
-    <p id="target3">pseudo element inside :matches has effect.</p>
-    <p id="target4">pseudo element inside :matches has effect.</p>
-    <p id="target5">pseudo element inside :matches has effect, so all selectors should be checked.</p>
-    <p id="target6">pseudo element inside nested :matches should have effect.</p>
-    <p id="target7">both line itself and before/after should be colored.</p>
+    <p id="target1">pseudo element outside :matches has effect.</p>
+    <p id="target2">pseudo element inside :matches has no effect.</p>
+    <p id="target3">pseudo element inside :matches has no effect.</p>
+    <p id="target4">pseudo element inside :matches has no effect.</p>
+    <p id="target5">pseudo element inside :matches has no effect, so the rest of the selectors should be checked.</p>
+    <p id="target6">pseudo element inside nested :matches should have no effect.</p>
+    <p id="target7">::before/after have no effect.</p>
     <p id="target8">pseudo element inside :not doesn't have effect.</p>
     <p id="target9">::first-line in non-rightmost fragment always unmatch.</p>
     <p id="target10">:matches(::first-line) in non-rightmost fragment always unmatches.</p>
     <p id="target11">pseudo element in non-rightmost fragment inside :matches always unmatches.</p>
-    <p id="target12">before/after contents are colored lime and first-letter of before content is colored blue.</p>
+    <p id="target12">first-letter is colored blue.</p>
     <p id="target13">non-rightmost pseudo element has no effect.</p>
-    <p id="target14"><p>non-rightmost pseudo element has no effect.</p></p>
-    <p id="target15"><p>non-rightmost pseudo element has no effect.</p></p>
-    <p id="target16"><p>matchType should be effective for normal element.</p></p>
+    <p id="target14"><span>non-rightmost pseudo element has no effect.</span></p>
+    <p id="target15"><span>non-rightmost pseudo element has no effect.</span></p>
+    <p id="target16"><span>matchType should be effective for normal element.</span></p>
 </div>
 </body>
 </html>

Modified: trunk/Source/WebCore/ChangeLog (255058 => 255059)


--- trunk/Source/WebCore/ChangeLog	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/Source/WebCore/ChangeLog	2020-01-24 08:37:08 UTC (rev 255059)
@@ -1,3 +1,36 @@
+2020-01-24  Antti Koivisto  <[email protected]>
+
+        :matches() doesn't combine correctly with pseudo elements
+        https://bugs.webkit.org/show_bug.cgi?id=206654
+
+        Reviewed by Simon Fraser.
+
+        :matches() has been renamed to :is() in the spec (https://www.w3.org/TR/selectors-4/#matches).
+        Update the :matches implementation to spec behavior regarding pseudo element handling.
+
+        "Pseudo-elements cannot be represented by the matches-any pseudo-class; they are not valid within :is()."
+
+        Selectors like
+
+            ::matches(foo, .parent .child)::first-letter
+
+        should work while
+
+            ::matches(:first-letter)
+
+        shoudn't match anything.
+
+        Test: fast/selectors/matches-with-pseudo-element.html
+
+        * css/SelectorChecker.cpp:
+        (WebCore::SelectorChecker::matchRecursively const):
+        (WebCore::SelectorChecker::checkOne const):
+
+        Don't provide pseudoId into ::matches subselectors. Pseudo elements are not suppported inside ::matches.
+        If one if found, fail that subselector.
+
+        * css/SelectorChecker.h:
+
 2020-01-24  youenn fablet  <[email protected]>
 
         Make sure fetch tasks go to network if service worker never gets to activated

Modified: trunk/Source/WebCore/css/SelectorChecker.cpp (255058 => 255059)


--- trunk/Source/WebCore/css/SelectorChecker.cpp	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/Source/WebCore/css/SelectorChecker.cpp	2020-01-24 08:37:08 UTC (rev 255059)
@@ -268,7 +268,7 @@
     MatchType matchType = MatchType::Element;
 
     // The first selector has to match.
-    if (!checkOne(checkingContext, context, dynamicPseudoIdSet, matchType, specificity))
+    if (!checkOne(checkingContext, context, matchType, specificity))
         return MatchResult::fails(Match::SelectorFailsLocally);
 
     if (context.selector->match() == CSSSelector::PseudoElement) {
@@ -651,7 +651,7 @@
     return namespaceURI == starAtom() || namespaceURI == element.namespaceURI();
 }
 
-bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalContext& context, PseudoIdSet& dynamicPseudoIdSet, MatchType& matchType, unsigned& specificity) const
+bool SelectorChecker::checkOne(CheckingContext& checkingContext, const LocalContext& context, MatchType& matchType, unsigned& specificity) const
 {
     const Element& element = *context.element;
     const CSSSelector& selector = *context.selector;
@@ -841,9 +841,15 @@
                     subcontext.pseudoElementEffective = context.pseudoElementEffective;
                     subcontext.selector = subselector;
                     subcontext.firstSelectorOfTheFragment = subselector;
+                    subcontext.pseudoId = PseudoId::None;
                     PseudoIdSet localDynamicPseudoIdSet;
                     unsigned localSpecificity = 0;
                     MatchResult result = matchRecursively(checkingContext, subcontext, localDynamicPseudoIdSet, localSpecificity);
+
+                    // Pseudo elements are not valid inside :matches
+                    if (localDynamicPseudoIdSet)
+                        continue;
+
                     if (result.match == Match::SelectorMatches) {
                         maxSpecificity = std::max(maxSpecificity, localSpecificity);
 
@@ -850,7 +856,6 @@
                         if (result.matchType == MatchType::Element)
                             localMatchType = MatchType::Element;
 
-                        dynamicPseudoIdSet.merge(localDynamicPseudoIdSet);
                         hasMatchedAnything = true;
                     }
                 }

Modified: trunk/Source/WebCore/css/SelectorChecker.h (255058 => 255059)


--- trunk/Source/WebCore/css/SelectorChecker.h	2020-01-24 08:23:07 UTC (rev 255058)
+++ trunk/Source/WebCore/css/SelectorChecker.h	2020-01-24 08:37:08 UTC (rev 255059)
@@ -117,7 +117,7 @@
     
 private:
     MatchResult matchRecursively(CheckingContext&, const LocalContext&, PseudoIdSet&, unsigned& specificity) const;
-    bool checkOne(CheckingContext&, const LocalContext&, PseudoIdSet&, MatchType&, unsigned& specificity) const;
+    bool checkOne(CheckingContext&, const LocalContext&, MatchType&, unsigned& specificity) const;
     bool matchSelectorList(CheckingContext&, const LocalContext&, const Element&, const CSSSelectorList&, unsigned& specificity) const;
 
     bool checkScrollbarPseudoClass(const CheckingContext&, const Element&, const CSSSelector&) const;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to