Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Fix invalidation with scope breaking :is/not()
https://bugs.webkit.org/show_bug.cgi?id=241098 Reviewed by Alan Bujtas. Selector like :has(:is(foo bar)) can be affected by mutations outside the :has scope. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/child-indexed-pseudo-classes-in-has-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/child-indexed-pseudo-classes-in-has.html: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/empty-pseudo-in-has-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/empty-pseudo-in-has.html: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-in-adjacent-position.html: * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-in-ancestor-position.html: * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-in-parent-position.html: * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-in-sibling-position.html: * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/is-pseudo-containing-complex-in-has-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/is-pseudo-containing-complex-in-has.html: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/link-pseudo-in-has-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/link-pseudo-in-has.html: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/not-pseudo-containing-complex-in-has-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/not-pseudo-containing-complex-in-has.html: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/typed-child-indexed-pseudo-classes-in-has-expected.txt: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/typed-child-indexed-pseudo-classes-in-has.html: Added. * LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/w3c-import.log: Reimport selector invalidation tests. * Source/WebCore/style/ChildChangeInvalidation.cpp: (WebCore::Style::ChildChangeInvalidation::invalidateForChangedElement): (WebCore::Style::needsDescendantTraversal): * Source/WebCore/style/RuleFeature.cpp: (WebCore::Style::isSiblingOrSubject): (WebCore::Style::isHasPseudoClassMatchElement): (WebCore::Style::computeNextMatchElement): (WebCore::Style::computeHasPseudoClassMatchElement): (WebCore::Style::computeSubSelectorMatchElement): (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector): Detect the case and fall back to very wide invalidation (same a non-subject :has() for now). * Source/WebCore/style/RuleFeature.h: (WebCore::Style::RuleFeatureSet::usesHasPseudoClass const): * Source/WebCore/style/StyleInvalidator.cpp: (WebCore::Style::Invalidator::invalidateStyleWithMatchElement): Canonical link: https://commits.webkit.org/251130@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@295035 268f45cc-cd09-0410-ab3c-d52691b4dbfc
- Loading branch information
Showing
21 changed files
with
1,499 additions
and
282 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @@ -0,0 +1,68 @@ | ||
|
|
||
| PASS Initial colors: #only_child | ||
| PASS Initial colors: #first_child | ||
| PASS Initial colors: #last_child | ||
| PASS Initial colors: #nth_child_3n_1 | ||
| PASS Initial colors: #nth_child_3n_2 | ||
| PASS Initial colors: #nth_child_3n | ||
| PASS Prepend #div1.green: #only_child | ||
| PASS Prepend #div1.green: #first_child | ||
| PASS Prepend #div1.green: #last_child | ||
| PASS Prepend #div1.green: #nth_child_3n_1 | ||
| PASS Prepend #div1.green: #nth_child_3n_2 | ||
| PASS Prepend #div1.green: #nth_child_3n | ||
| FAIL Prepend #div2.yellow: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| PASS Prepend #div2.yellow: #first_child | ||
| PASS Prepend #div2.yellow: #last_child | ||
| PASS Prepend #div2.yellow: #nth_child_3n_1 | ||
| FAIL Prepend #div2.yellow: #nth_child_3n_2 assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" | ||
| PASS Prepend #div2.yellow: #nth_child_3n | ||
| FAIL Prepend #div3.orange: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| PASS Prepend #div3.orange: #first_child | ||
| PASS Prepend #div3.orange: #last_child | ||
| PASS Prepend #div3.orange: #nth_child_3n_1 | ||
| FAIL Prepend #div3.orange: #nth_child_3n_2 assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Prepend #div3.orange: #nth_child_3n assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Prepend #div4: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| FAIL Prepend #div4: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Prepend #div4: #last_child | ||
| FAIL Prepend #div4: #nth_child_3n_1 assert_equals: expected "rgb(0, 128, 0)" but got "rgb(255, 165, 0)" | ||
| FAIL Prepend #div4: #nth_child_3n_2 assert_equals: expected "rgb(255, 165, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Prepend #div4: #nth_child_3n assert_equals: expected "rgb(255, 255, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Prepend #div5: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| FAIL Prepend #div5: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Prepend #div5: #last_child | ||
| FAIL Prepend #div5: #nth_child_3n_1 assert_equals: expected "rgb(255, 255, 0)" but got "rgb(255, 165, 0)" | ||
| FAIL Prepend #div5: #nth_child_3n_2 assert_equals: expected "rgb(0, 128, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Prepend #div5: #nth_child_3n assert_equals: expected "rgb(255, 165, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Remove #div1: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| FAIL Remove #div1: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Remove #div1: #last_child | ||
| FAIL Remove #div1: #nth_child_3n_1 assert_equals: expected "rgb(255, 255, 0)" but got "rgb(255, 165, 0)" | ||
| PASS Remove #div1: #nth_child_3n_2 | ||
| FAIL Remove #div1: #nth_child_3n assert_equals: expected "rgb(255, 165, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Remove #div2: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| FAIL Remove #div2: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Remove #div2: #last_child | ||
| PASS Remove #div2: #nth_child_3n_1 | ||
| PASS Remove #div2: #nth_child_3n_2 | ||
| FAIL Remove #div2: #nth_child_3n assert_equals: expected "rgb(255, 165, 0)" but got "rgb(128, 128, 128)" | ||
| FAIL Remove #div3: #only_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 0, 0)" | ||
| FAIL Remove #div3: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Remove #div3: #last_child | ||
| PASS Remove #div3: #nth_child_3n_1 | ||
| PASS Remove #div3: #nth_child_3n_2 | ||
| PASS Remove #div3: #nth_child_3n | ||
| PASS Remove #div4: #only_child | ||
| FAIL Remove #div4: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Remove #div4: #last_child | ||
| PASS Remove #div4: #nth_child_3n_1 | ||
| PASS Remove #div4: #nth_child_3n_2 | ||
| PASS Remove #div4: #nth_child_3n | ||
| PASS Remove #div5: #only_child | ||
| FAIL Remove #div5: #first_child assert_equals: expected "rgb(128, 128, 128)" but got "rgb(255, 165, 0)" | ||
| PASS Remove #div5: #last_child | ||
| PASS Remove #div5: #nth_child_3n_1 | ||
| PASS Remove #div5: #nth_child_3n_2 | ||
| PASS Remove #div5: #nth_child_3n | ||
|
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @@ -0,0 +1,116 @@ | ||
| <!DOCTYPE html> | ||
| <meta charset="utf-8" /> | ||
| <title>CSS Selectors Invalidation: child-indexed pseudo classes in :has() argument</title> | ||
| <link rel="author" title="Byungwoo Lee" href="blee@igalia.com"> | ||
| <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> | ||
| <script src="/resources/testharness.js"></script> | ||
| <script src="/resources/testharnessreport.js"></script> | ||
| <style> | ||
| #container ~ div { color: grey } | ||
| #container:has(:only-child) ~ #only_child { color: red } | ||
| #container:has(.orange:first-child) ~ #first_child { color: orange } | ||
| #container:has(.yellow:first-child) ~ #first_child { color: yellow } | ||
| #container:has(.green:first-child) ~ #first_child { color: green } | ||
| #container:has(.orange:last-child) ~ #last_child { color: orange } | ||
| #container:has(.yellow:last-child) ~ #last_child { color: yellow } | ||
| #container:has(.green:last-child) ~ #last_child { color: green } | ||
| #container:has(.orange:nth-child(3n)) ~ #nth_child_3n { color: orange } | ||
| #container:has(.yellow:nth-child(3n)) ~ #nth_child_3n { color: yellow } | ||
| #container:has(.green:nth-child(3n)) ~ #nth_child_3n { color: green } | ||
| #container:has(.orange:nth-child(3n+1)) ~ #nth_child_3n_1 { color: orange } | ||
| #container:has(.yellow:nth-child(3n+1)) ~ #nth_child_3n_1 { color: yellow } | ||
| #container:has(.green:nth-child(3n+1)) ~ #nth_child_3n_1 { color: green } | ||
| #container:has(.orange:nth-child(3n+2)) ~ #nth_child_3n_2 { color: orange } | ||
| #container:has(.yellow:nth-child(3n+2)) ~ #nth_child_3n_2 { color: yellow } | ||
| #container:has(.green:nth-child(3n+2)) ~ #nth_child_3n_2 { color: green } | ||
| #container:has(.orange:nth-child(3n)) ~ #nth_child_3n { color: orange } | ||
| #container:has(.yellow:nth-child(3n)) ~ #nth_child_3n { color: yellow } | ||
| #container:has(.green:nth-child(3n)) ~ #nth_child_3n { color: green } | ||
| </style> | ||
| <div id="container"> | ||
| </div> | ||
| <div id="only_child"></div> | ||
| <div id="first_child"></div> | ||
| <div id="last_child"></div> | ||
| <div id="nth_child_3n_1"></div> | ||
| <div id="nth_child_3n_2"></div> | ||
| <div id="nth_child_3n"></div> | ||
| <script> | ||
| const grey = "rgb(128, 128, 128)"; | ||
| const red = "rgb(255, 0, 0)"; | ||
| const orange = "rgb(255, 165, 0)"; | ||
| const yellow = "rgb(255, 255, 0)"; | ||
| const green = "rgb(0, 128, 0)"; | ||
|
|
||
| function testColors(test_name, | ||
| only_child_color, | ||
| first_child_color, | ||
| last_child_color, | ||
| nth_child_3n_1_color, | ||
| nth_child_3n_2_color, | ||
| nth_child_3n_color) { | ||
| test(function() { | ||
| assert_equals(getComputedStyle(only_child).color, only_child_color); | ||
| }, test_name + ": #only_child"); | ||
| test(function() { | ||
| assert_equals(getComputedStyle(first_child).color, first_child_color); | ||
| }, test_name + ": #first_child"); | ||
| test(function() { | ||
| assert_equals(getComputedStyle(last_child).color, last_child_color); | ||
| }, test_name + ": #last_child"); | ||
| test(function() { | ||
| assert_equals(getComputedStyle(nth_child_3n_1).color, nth_child_3n_1_color); | ||
| }, test_name + ": #nth_child_3n_1"); | ||
| test(function() { | ||
| assert_equals(getComputedStyle(nth_child_3n_2).color, nth_child_3n_2_color); | ||
| }, test_name + ": #nth_child_3n_2"); | ||
| test(function() { | ||
| assert_equals(getComputedStyle(nth_child_3n).color, nth_child_3n_color); | ||
| }, test_name + ": #nth_child_3n"); | ||
| } | ||
|
|
||
| testColors("Initial colors", grey, grey, grey, grey, grey, grey); | ||
|
|
||
| let div1 = document.createElement("div"); | ||
| div1.id = "div1"; | ||
| div1.classList.add("green"); | ||
| container.insertBefore(div1, container.firstChild); | ||
| testColors("Prepend #div1.green", red, green, green, green, grey, grey); | ||
|
|
||
| let div2 = document.createElement("div"); | ||
| div2.id = "div2"; | ||
| div2.classList.add("yellow"); | ||
| container.insertBefore(div2, container.firstChild); | ||
| testColors("Prepend #div2.yellow", grey, yellow, green, yellow, green, grey); | ||
|
|
||
| let div3 = document.createElement("div"); | ||
| div3.id = "div3"; | ||
| div3.classList.add("orange"); | ||
| container.insertBefore(div3, container.firstChild); | ||
| testColors("Prepend #div3.orange", grey, orange, green, orange, yellow, green); | ||
|
|
||
| let div4 = document.createElement("div"); | ||
| div4.id = "div4"; | ||
| container.insertBefore(div4, container.firstChild); | ||
| testColors("Prepend #div4", grey, grey, green, green, orange, yellow); | ||
|
|
||
| let div5 = document.createElement("div"); | ||
| div5.id = "div5"; | ||
| container.insertBefore(div5, container.firstChild); | ||
| testColors("Prepend #div5", grey, grey, green, yellow, green, orange); | ||
|
|
||
| div1.remove(); | ||
| testColors("Remove #div1", grey, grey, yellow, yellow, grey, orange); | ||
|
|
||
| div2.remove(); | ||
| testColors("Remove #div2", grey, grey, orange, grey, grey, orange); | ||
|
|
||
| div3.remove(); | ||
| testColors("Remove #div3", grey, grey, grey, grey, grey, grey); | ||
|
|
||
| div4.remove(); | ||
| testColors("Remove #div4", red, grey, grey, grey, grey, grey); | ||
|
|
||
| div5.remove(); | ||
| testColors("Remove #div5", grey, grey, grey, grey, grey, grey); | ||
| </script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @@ -0,0 +1,5 @@ | ||
|
|
||
| PASS Empty #subject | ||
| PASS Insert div#child to #subject | ||
| PASS Insert div to div.#child | ||
|
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @@ -0,0 +1,37 @@ | ||
| <!DOCTYPE html> | ||
| <meta charset="utf-8" /> | ||
| <title>CSS Selectors Invalidation: :empty in :has() argument</title> | ||
| <link rel="author" title="Byungwoo Lee" href="blee@igalia.com"> | ||
| <link rel="help" href="https://drafts.csswg.org/selectors/#relational"> | ||
| <script src="/resources/testharness.js"></script> | ||
| <script src="/resources/testharnessreport.js"></script> | ||
| <style> | ||
| #subject { color: red } | ||
| #subject:has(:empty) { color: green } | ||
| #subject:has(:not(:empty)) { color: blue } | ||
| </style> | ||
| <div id="subject"></div> | ||
| <script> | ||
| const red = 'rgb(255, 0, 0)'; | ||
| const green = 'rgb(0, 128, 0)'; | ||
| const blue = 'rgb(0, 0, 255)'; | ||
|
|
||
| function testColor(test_name, color) { | ||
| test(function() { | ||
| assert_equals(getComputedStyle(subject).color, color); | ||
| }, test_name); | ||
| } | ||
|
|
||
| testColor("Empty #subject", red); | ||
|
|
||
| let child = document.createElement("div"); | ||
| child.id = "child"; | ||
| subject.appendChild(child); | ||
|
|
||
| testColor("Insert div#child to #subject", green); | ||
|
|
||
| child.appendChild(document.createElement("div")); | ||
|
|
||
| testColor("Insert div to div.#child", blue); | ||
|
|
||
| </script> |
Oops, something went wrong.