Title: [258321] trunk
Revision
258321
Author
an...@apple.com
Date
2020-03-12 06:30:10 -0700 (Thu, 12 Mar 2020)

Log Message

Accurate style invalidation for user action pseudo classes
https://bugs.webkit.org/show_bug.cgi?id=208859
<rdar://problem/55196888>

Reviewed by Zalan Bujtas.

Source/WebCore:

Currently :hover, :focus, :focus-within and :active lack fine grained invalidation using
rule sets like we do with class and attribute selectors.

This can be added easily following the same pattern.

Tests: fast/selectors/style-invalidation-hover-change-descendants.html
       fast/selectors/style-invalidation-hover-change-siblings.html
       fast/selectors/style-invalidation-focus-change-descendants.html
       fast/selectors/style-invalidation-focus-change-siblings.html
       fast/selectors/style-invalidation-focus-within-change-descendants.html
       fast/selectors/style-invalidation-focus-within-change-siblings.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* dom/Element.cpp:
(WebCore::Element::setActive):
(WebCore::Element::setFocus):
(WebCore::Element::setHasFocusWithin):
(WebCore::Element::setHovered):

Use PseudoClassChangeInvalidation.

* dom/Element.h:
(WebCore::Element::setHasFocusWithin): Deleted.
* page/FrameViewLayoutContext.cpp:
(WebCore::RenderTreeNeedsLayoutChecker::~RenderTreeNeedsLayoutChecker):
* style/PseudoClassChangeInvalidation.cpp: Added.
(WebCore::Style::PseudoClassChangeInvalidation::computeInvalidation):

Compute invalidation rule set for a pseudo class change.

(WebCore::Style::PseudoClassChangeInvalidation::invalidateStyleWithRuleSets):
* style/PseudoClassChangeInvalidation.h: Added.
(WebCore::Style::PseudoClassChangeInvalidation::PseudoClassChangeInvalidation):
(WebCore::Style::PseudoClassChangeInvalidation::~PseudoClassChangeInvalidation):
* style/RuleFeature.cpp:
(WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
(WebCore::Style::RuleFeatureSet::collectFeatures):

Collect pseudo class features, similar to classes/attributes.

(WebCore::Style::RuleFeatureSet::add):
(WebCore::Style::RuleFeatureSet::clear):
(WebCore::Style::RuleFeatureSet::shrinkToFit):
* style/RuleFeature.h:
* style/StyleScopeRuleSets.cpp:
(WebCore::Style::ScopeRuleSets::collectFeatures const):
(WebCore::Style::ensureInvalidationRuleSets):

Make more generic to allow enum key.

(WebCore::Style::ScopeRuleSets::pseudoClassInvalidationRuleSets const):

Create pseudo class invalidation ruleset.

* style/StyleScopeRuleSets.h:

LayoutTests:

* fast/selectors/style-invalidation-focus-change-descendants-expected.txt: Added.
* fast/selectors/style-invalidation-focus-change-descendants.html: Added.
* fast/selectors/style-invalidation-focus-change-siblings-expected.txt: Added.
* fast/selectors/style-invalidation-focus-change-siblings.html: Added.
* fast/selectors/style-invalidation-focus-within-change-descendants-expected.txt: Added.
* fast/selectors/style-invalidation-focus-within-change-descendants.html: Added.
* fast/selectors/style-invalidation-focus-within-change-siblings-expected.txt: Added.
* fast/selectors/style-invalidation-focus-within-change-siblings.html: Added.
* fast/selectors/style-invalidation-hover-change-descendants-expected.txt: Added.
* fast/selectors/style-invalidation-hover-change-descendants.html: Added.
* fast/selectors/style-invalidation-hover-change-siblings-expected.txt: Added.
* fast/selectors/style-invalidation-hover-change-siblings.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (258320 => 258321)


--- trunk/LayoutTests/ChangeLog	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/LayoutTests/ChangeLog	2020-03-12 13:30:10 UTC (rev 258321)
@@ -1,3 +1,24 @@
+2020-03-12  Antti Koivisto  <an...@apple.com>
+
+        Accurate style invalidation for user action pseudo classes
+        https://bugs.webkit.org/show_bug.cgi?id=208859
+        <rdar://problem/55196888>
+
+        Reviewed by Zalan Bujtas.
+
+        * fast/selectors/style-invalidation-focus-change-descendants-expected.txt: Added.
+        * fast/selectors/style-invalidation-focus-change-descendants.html: Added.
+        * fast/selectors/style-invalidation-focus-change-siblings-expected.txt: Added.
+        * fast/selectors/style-invalidation-focus-change-siblings.html: Added.
+        * fast/selectors/style-invalidation-focus-within-change-descendants-expected.txt: Added.
+        * fast/selectors/style-invalidation-focus-within-change-descendants.html: Added.
+        * fast/selectors/style-invalidation-focus-within-change-siblings-expected.txt: Added.
+        * fast/selectors/style-invalidation-focus-within-change-siblings.html: Added.
+        * fast/selectors/style-invalidation-hover-change-descendants-expected.txt: Added.
+        * fast/selectors/style-invalidation-hover-change-descendants.html: Added.
+        * fast/selectors/style-invalidation-hover-change-siblings-expected.txt: Added.
+        * fast/selectors/style-invalidation-hover-change-siblings.html: Added.
+
 2020-03-12  Diego Pino Garcia  <dp...@igalia.com>
 
         [WPE] Gardening, expected to fail but passed

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-descendants-expected.txt (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-descendants-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-descendants-expected.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,7 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-descendants.html (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-descendants.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-descendants.html	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,82 @@
+<html>
+<style>
+.container {
+    background-color: blue;
+    width: 200px;
+    height: 600px;
+    position: absolute;
+}
+.inert {
+    background-color: yellow;
+        width: 100px;
+    height: 100px;
+    position: relative;
+}
+.target {
+    background-color: red;
+    width: 100px;
+    height: 100px;
+    position: relative;
+}
+.container:focus .target {
+    background-color: green;
+}
+.child {
+    width: 50px;
+    height: 50px;
+}
+</style>
+<div class=container tabindex=1 id=focusTarget>
+    <div class=inert>
+    </div>
+    <div class=target>
+    </div>
+    <div class=inert>
+    </div>
+    <div class=target>
+        <div class="inert child">
+        </div>
+    </div>
+    <div class=inert>
+        <div class="target child">
+        </div>
+    </div>
+</div>
+<pre id=log></pre>
+
+<script>
+function testStyleChangeType(selector, expectedType)
+{
+    let pass = true;
+    const elements = document.querySelectorAll(selector);
+    for (var i = 0; i < elements.length; ++i) {
+        const type = window.internals.styleChangeType(elements[i]);
+        if (type != expectedType) {
+            log.textContent += `FAIL ${selector} styleChangeType was ${type} expected ${expectedType}\n`;
+            pass = false;
+        }
+    }
+    if (pass)
+        log.textContent += "PASS\n";
+}
+
+window._onload_ = function () {
+    if (!window.testRunner)
+        return;
+    testRunner.dumpAsText();
+
+    document.body.offsetLeft;
+    focusTarget.focus();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "InlineStyleChange"); // Style change due to to UA style sheet.
+    testStyleChangeType(".inert", "NoStyleChange");
+
+    document.body.offsetLeft;
+    focusTarget.blur();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "InlineStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+};
+</script>

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-siblings-expected.txt (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-siblings-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-siblings-expected.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,7 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-siblings.html (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-siblings.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-change-siblings.html	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,86 @@
+<html>
+<style>
+.container {
+    background-color: blue;
+    width: 200px;
+    height: 600px;
+    position: absolute;
+}
+.inert {
+    background-color: yellow;
+        width: 100px;
+    height: 100px;
+    position: relative;
+}
+.target {
+    background-color: red;
+    width: 100px;
+    height: 100px;
+    position: relative;
+}
+:focus ~ .target {
+    background-color: green;
+}
+:focus ~ .inert > .target {
+    background-color: green;
+}
+.child {
+    width: 50px;
+    height: 50px;
+}
+</style>
+<div class=container>
+    <!--Style change due to to UA style sheet.-->
+    <div class=target tabindex=1 id=focusTarget>
+    </div>
+    <div class=target>
+    </div>
+    <div class=inert>
+    </div>
+    <div class=target>
+        <div class="inert child">
+        </div>
+    </div>
+    <div class=inert>
+        <div class="target child">
+        </div>
+    </div>
+</div>
+<pre id=log></pre>
+
+<script>
+function testStyleChangeType(selector, expectedType)
+{
+    let pass = true;
+    const elements = document.querySelectorAll(selector);
+    for (var i = 0; i < elements.length; ++i) {
+        const type = window.internals.styleChangeType(elements[i]);
+        if (type != expectedType) {
+            log.textContent += `FAIL ${selector} styleChangeType was ${type} expected ${expectedType}\n`;
+            pass = false;
+        }
+    }
+    if (pass)
+        log.textContent += "PASS\n";
+}
+
+window._onload_ = function () {
+    if (!window.testRunner)
+        return;
+    testRunner.dumpAsText();
+
+    document.body.offsetLeft;
+    focusTarget.focus();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+
+    document.body.offsetLeft;
+    focusTarget.blur();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+};
+</script>

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-descendants-expected.txt (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-descendants-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-descendants-expected.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,7 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-descendants.html (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-descendants.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-descendants.html	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,82 @@
+<html>
+<style>
+.container {
+    background-color: blue;
+    width: 200px;
+    height: 600px;
+    position: absolute;
+}
+.inert {
+    background-color: yellow;
+        width: 100px;
+    height: 100px;
+    position: relative;
+}
+.target {
+    background-color: red;
+    width: 100px;
+    height: 100px;
+    position: relative;
+}
+.container:focus-within .target {
+    background-color: green;
+}
+.child {
+    width: 50px;
+    height: 50px;
+}
+</style>
+<div class=container>
+    <div class=target tabindex=1 id=focusTarget>
+    </div>
+    <div class=target>
+    </div>
+    <div class=inert>
+    </div>
+    <div class=target>
+        <div class="inert child">
+        </div>
+    </div>
+    <div class=inert>
+        <div class="target child">
+        </div>
+    </div>
+</div>
+<pre id=log></pre>
+
+<script>
+function testStyleChangeType(selector, expectedType)
+{
+    let pass = true;
+    const elements = document.querySelectorAll(selector);
+    for (var i = 0; i < elements.length; ++i) {
+        const type = window.internals.styleChangeType(elements[i]);
+        if (type != expectedType) {
+            log.textContent += `FAIL ${selector} styleChangeType was ${type} expected ${expectedType}\n`;
+            pass = false;
+        }
+    }
+    if (pass)
+        log.textContent += "PASS\n";
+}
+
+window._onload_ = function () {
+    if (!window.testRunner)
+        return;
+    testRunner.dumpAsText();
+
+    document.body.offsetLeft;
+    focusTarget.focus();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+
+    document.body.offsetLeft;
+    focusTarget.blur();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+};
+</script>

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-siblings-expected.txt (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-siblings-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-siblings-expected.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,7 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-siblings.html (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-siblings.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-focus-within-change-siblings.html	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,88 @@
+<html>
+<style>
+.container {
+    background-color: blue;
+    width: 200px;
+    height: 600px;
+    position: absolute;
+}
+.inert {
+    background-color: yellow;
+        width: 100px;
+    height: 100px;
+    position: relative;
+}
+.target {
+    background-color: red;
+    width: 100px;
+    height: 100px;
+    position: relative;
+}
+.inert:focus-within ~ .target {
+    background-color: green;
+}
+.inert:focus-within ~ .inert > .target {
+    background-color: green;
+}
+.child {
+    width: 50px;
+    height: 50px;
+}
+</style>
+<div class=container>
+    <div class=inert>
+        <!--Style change due to to UA style sheet.-->
+        <div class="target child" tabindex=1 id=focusTarget>
+        </div>
+    </div>
+    <div class=target>
+    </div>
+    <div class=inert>
+    </div>
+    <div class=target>
+        <div class="inert child">
+        </div>
+    </div>
+    <div class=inert>
+        <div class="target child">
+        </div>
+    </div>
+</div>
+<pre id=log></pre>
+
+<script>
+function testStyleChangeType(selector, expectedType)
+{
+    let pass = true;
+    const elements = document.querySelectorAll(selector);
+    for (var i = 0; i < elements.length; ++i) {
+        const type = window.internals.styleChangeType(elements[i]);
+        if (type != expectedType) {
+            log.textContent += `FAIL ${selector} styleChangeType was ${type} expected ${expectedType}\n`;
+            pass = false;
+        }
+    }
+    if (pass)
+        log.textContent += "PASS\n";
+}
+
+window._onload_ = function () {
+    if (!window.testRunner)
+        return;
+    testRunner.dumpAsText();
+
+    document.body.offsetLeft;
+    focusTarget.focus();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+
+    document.body.offsetLeft;
+    focusTarget.blur();
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+};
+</script>

Added: trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-descendants-expected.txt (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-descendants-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-descendants-expected.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,7 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-descendants.html (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-descendants.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-descendants.html	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,82 @@
+<html>
+<style>
+.container {
+    background-color: blue;
+    width: 200px;
+    height: 600px;
+    position: absolute;
+}
+.inert {
+    background-color: yellow;
+        width: 100px;
+    height: 100px;
+    position: relative;
+}
+.target {
+    background-color: red;
+    width: 100px;
+    height: 100px;
+    position: relative;
+}
+.container:hover .target {
+    background-color: green;
+}
+.child {
+    width: 50px;
+    height: 50px;
+}
+</style>
+<div class=container>
+    <div class=inert>
+    </div>
+    <div class=target>
+    </div>
+    <div class=inert>
+    </div>
+    <div class=target>
+        <div class="inert child">
+        </div>
+    </div>
+    <div class=inert>
+        <div class="target child">
+        </div>
+    </div>
+</div>
+<pre id=log></pre>
+
+<script>
+function testStyleChangeType(selector, expectedType)
+{
+    let pass = true;
+    const elements = document.querySelectorAll(selector);
+    for (var i = 0; i < elements.length; ++i) {
+        const type = window.internals.styleChangeType(elements[i]);
+        if (type != expectedType) {
+            log.textContent += `FAIL ${selector} styleChangeType was ${type} expected ${expectedType}\n`;
+            pass = false;
+        }
+    }
+    if (pass)
+        log.textContent += "PASS\n";
+}
+
+window._onload_ = function () {
+    if (!window.testRunner)
+        return;
+    testRunner.dumpAsText();
+
+    document.body.offsetLeft;
+    eventSender.mouseMoveTo(50,50);
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+
+    document.body.offsetLeft;
+    eventSender.mouseMoveTo(300,50);
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+};
+</script>

Added: trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-siblings-expected.txt (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-siblings-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-siblings-expected.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,7 @@
+PASS
+PASS
+PASS
+PASS
+PASS
+PASS
+

Added: trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-siblings.html (0 => 258321)


--- trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-siblings.html	                        (rev 0)
+++ trunk/LayoutTests/fast/selectors/style-invalidation-hover-change-siblings.html	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,85 @@
+<html>
+<style>
+.container {
+    background-color: blue;
+    width: 200px;
+    height: 600px;
+    position: absolute;
+}
+.inert {
+    background-color: yellow;
+        width: 100px;
+    height: 100px;
+    position: relative;
+}
+.target {
+    background-color: red;
+    width: 100px;
+    height: 100px;
+    position: relative;
+}
+.inert:hover ~ .target {
+    background-color: green;
+}
+.inert:hover ~ .inert > .target {
+    background-color: green;
+}
+.child {
+    width: 50px;
+    height: 50px;
+}
+</style>
+<div class=container>
+    <div class=inert>
+    </div>
+    <div class=target>
+    </div>
+    <div class=inert>
+    </div>
+    <div class=target>
+        <div class="inert child">
+        </div>
+    </div>
+    <div class=inert>
+        <div class="target child">
+        </div>
+    </div>
+</div>
+<pre id=log></pre>
+
+<script>
+function testStyleChangeType(selector, expectedType)
+{
+    let pass = true;
+    const elements = document.querySelectorAll(selector);
+    for (var i = 0; i < elements.length; ++i) {
+        const type = window.internals.styleChangeType(elements[i]);
+        if (type != expectedType) {
+            log.textContent += `FAIL ${selector} styleChangeType was ${type} expected ${expectedType}\n`;
+            pass = false;
+        }
+    }
+    if (pass)
+        log.textContent += "PASS\n";
+}
+
+window._onload_ = function () {
+    if (!window.testRunner)
+        return;
+    testRunner.dumpAsText();
+
+    document.body.offsetLeft;
+    eventSender.mouseMoveTo(50,50);
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+
+    document.body.offsetLeft;
+    eventSender.mouseMoveTo(300,50);
+
+    testStyleChangeType(".target", "InlineStyleChange");
+    testStyleChangeType(".container", "NoStyleChange");
+    testStyleChangeType(".inert", "NoStyleChange");
+};
+</script>

Modified: trunk/LayoutTests/platform/ios/TestExpectations (258320 => 258321)


--- trunk/LayoutTests/platform/ios/TestExpectations	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/LayoutTests/platform/ios/TestExpectations	2020-03-12 13:30:10 UTC (rev 258321)
@@ -693,6 +693,8 @@
 fast/selectors/hover-strict.html [ Skip ]
 fast/selectors/not-active-hover-quirks.html [ Skip ]
 fast/selectors/not-active-hover-strict.html [ Skip ]
+fast/selectors/style-invalidation-hover-change-descendants.html [ Skip ]
+fast/selectors/style-invalidation-hover-change-siblings.html [ Skip ]
 fast/shapes/shape-outside-floats/shape-outside-clip-path-selection.html [ Skip ]
 fast/shadow-dom/mouseenter-mouseleave-across-shadow-boundary.html [ Skip ]
 fast/shadow-dom/mouseenter-mouseleave-inside-shadow-tree.html [ Skip ]

Modified: trunk/LayoutTests/platform/win/TestExpectations (258320 => 258321)


--- trunk/LayoutTests/platform/win/TestExpectations	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/LayoutTests/platform/win/TestExpectations	2020-03-12 13:30:10 UTC (rev 258321)
@@ -2863,6 +2863,14 @@
 fast/selectors/querySelector-window-inactive.html [ Failure ]
 fast/selectors/read-only-read-write-input-basics.html [ Failure ]
 
+# Win port sometimes forces synchronous style recalc on focus/hover making these unreliable.
+fast/selectors/style-invalidation-focus-change-descendants.html [ Pass Failure ]
+fast/selectors/style-invalidation-focus-change-siblings.html [ Pass Failure ]
+fast/selectors/style-invalidation-focus-within-change-descendants.html [ Pass Failure ]
+fast/selectors/style-invalidation-focus-within-change-siblings.html [ Pass Failure ]
+fast/selectors/style-invalidation-hover-change-descendants.html [ Pass Failure ]
+fast/selectors/style-invalidation-hover-change-siblings.html [ Pass Failure ]
+
 fast/shapes/shape-outside-floats/shape-outside-image-fit-002.html [ Pass ImageOnlyFailure ]
 
 fast/table/border-collapsing/cached-change-tbody-border-width.html [ Pass Failure ]

Modified: trunk/Source/WebCore/ChangeLog (258320 => 258321)


--- trunk/Source/WebCore/ChangeLog	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/ChangeLog	2020-03-12 13:30:10 UTC (rev 258321)
@@ -1,3 +1,68 @@
+2020-03-12  Antti Koivisto  <an...@apple.com>
+
+        Accurate style invalidation for user action pseudo classes
+        https://bugs.webkit.org/show_bug.cgi?id=208859
+        <rdar://problem/55196888>
+
+        Reviewed by Zalan Bujtas.
+
+        Currently :hover, :focus, :focus-within and :active lack fine grained invalidation using
+        rule sets like we do with class and attribute selectors.
+
+        This can be added easily following the same pattern.
+
+        Tests: fast/selectors/style-invalidation-hover-change-descendants.html
+               fast/selectors/style-invalidation-hover-change-siblings.html
+               fast/selectors/style-invalidation-focus-change-descendants.html
+               fast/selectors/style-invalidation-focus-change-siblings.html
+               fast/selectors/style-invalidation-focus-within-change-descendants.html
+               fast/selectors/style-invalidation-focus-within-change-siblings.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/Element.cpp:
+        (WebCore::Element::setActive):
+        (WebCore::Element::setFocus):
+        (WebCore::Element::setHasFocusWithin):
+        (WebCore::Element::setHovered):
+
+        Use PseudoClassChangeInvalidation.
+
+        * dom/Element.h:
+        (WebCore::Element::setHasFocusWithin): Deleted.
+        * page/FrameViewLayoutContext.cpp:
+        (WebCore::RenderTreeNeedsLayoutChecker::~RenderTreeNeedsLayoutChecker):
+        * style/PseudoClassChangeInvalidation.cpp: Added.
+        (WebCore::Style::PseudoClassChangeInvalidation::computeInvalidation):
+
+        Compute invalidation rule set for a pseudo class change.
+
+        (WebCore::Style::PseudoClassChangeInvalidation::invalidateStyleWithRuleSets):
+        * style/PseudoClassChangeInvalidation.h: Added.
+        (WebCore::Style::PseudoClassChangeInvalidation::PseudoClassChangeInvalidation):
+        (WebCore::Style::PseudoClassChangeInvalidation::~PseudoClassChangeInvalidation):
+        * style/RuleFeature.cpp:
+        (WebCore::Style::RuleFeatureSet::recursivelyCollectFeaturesFromSelector):
+        (WebCore::Style::RuleFeatureSet::collectFeatures):
+
+        Collect pseudo class features, similar to classes/attributes.
+
+        (WebCore::Style::RuleFeatureSet::add):
+        (WebCore::Style::RuleFeatureSet::clear):
+        (WebCore::Style::RuleFeatureSet::shrinkToFit):
+        * style/RuleFeature.h:
+        * style/StyleScopeRuleSets.cpp:
+        (WebCore::Style::ScopeRuleSets::collectFeatures const):
+        (WebCore::Style::ensureInvalidationRuleSets):
+
+        Make more generic to allow enum key.
+
+        (WebCore::Style::ScopeRuleSets::pseudoClassInvalidationRuleSets const):
+
+        Create pseudo class invalidation ruleset.
+
+        * style/StyleScopeRuleSets.h:
+
 2020-03-12  Said Abou-Hallawa  <sabouhall...@apple.com>
 
         [GPU Process] GraphicsContextStateChange must accumulate fill and stroke fields as single properties

Modified: trunk/Source/WebCore/Sources.txt (258320 => 258321)


--- trunk/Source/WebCore/Sources.txt	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/Sources.txt	2020-03-12 13:30:10 UTC (rev 258321)
@@ -2374,6 +2374,7 @@
 style/MatchedDeclarationsCache.cpp
 style/PageRuleCollector.cpp
 style/PropertyCascade.cpp
+style/PseudoClassChangeInvalidation.cpp
 style/RuleData.cpp
 style/RuleFeature.cpp
 style/RuleSet.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (258320 => 258321)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-03-12 13:30:10 UTC (rev 258321)
@@ -4890,6 +4890,7 @@
 		E451C6322394031A00993190 /* MarginTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 6FE7AA2621C37B6300296DCD /* MarginTypes.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E451C6342394058F00993190 /* DisplayInlineContent.h in Headers */ = {isa = PBXBuildFile; fileRef = E451C6332394058E00993190 /* DisplayInlineContent.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E45322AC140CE267005A0F92 /* SelectorQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = E45322AA140CE267005A0F92 /* SelectorQuery.h */; };
+		E45A6C772417BA59006E4CD5 /* PseudoClassChangeInvalidation.h in Headers */ = {isa = PBXBuildFile; fileRef = E45A6C762417BA59006E4CD5 /* PseudoClassChangeInvalidation.h */; };
 		E45BA6AA2374926C004DFC07 /* MatchedDeclarationsCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E45BA6A82374926B004DFC07 /* MatchedDeclarationsCache.h */; };
 		E45BA6B6237622A3004DFC07 /* StyleAdjuster.h in Headers */ = {isa = PBXBuildFile; fileRef = E45BA6B52376229F004DFC07 /* StyleAdjuster.h */; };
 		E4605FEC2166480900E53046 /* PrewarmInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = E4605FEA2166480800E53046 /* PrewarmInformation.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -15298,6 +15299,8 @@
 		E45390340EAFD637003695C8 /* ScrollViewIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewIOS.mm; sourceTree = "<group>"; };
 		E453903C0EAFD637003695C8 /* WidgetIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WidgetIOS.mm; sourceTree = "<group>"; };
 		E45390AD0EAFF4B5003695C8 /* SystemMemoryIOS.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SystemMemoryIOS.cpp; sourceTree = "<group>"; };
+		E45A6C732417BA4C006E4CD5 /* PseudoClassChangeInvalidation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoClassChangeInvalidation.cpp; sourceTree = "<group>"; };
+		E45A6C762417BA59006E4CD5 /* PseudoClassChangeInvalidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoClassChangeInvalidation.h; sourceTree = "<group>"; };
 		E45BA6A82374926B004DFC07 /* MatchedDeclarationsCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MatchedDeclarationsCache.h; sourceTree = "<group>"; };
 		E45BA6AB2374927B004DFC07 /* MatchedDeclarationsCache.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MatchedDeclarationsCache.cpp; sourceTree = "<group>"; };
 		E45BA6B22376227E004DFC07 /* StyleAdjuster.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StyleAdjuster.cpp; sourceTree = "<group>"; };
@@ -27273,6 +27276,8 @@
 				FBDB61A016D6037E00BB3394 /* PageRuleCollector.h */,
 				E4ABABE52361A34200FA4345 /* PropertyCascade.cpp */,
 				E4ABABE22361A32900FA4345 /* PropertyCascade.h */,
+				E45A6C732417BA4C006E4CD5 /* PseudoClassChangeInvalidation.cpp */,
+				E45A6C762417BA59006E4CD5 /* PseudoClassChangeInvalidation.h */,
 				E4863CFA23842E8700972158 /* RuleData.cpp */,
 				E4863CFD23842E9E00972158 /* RuleData.h */,
 				A79BAD9D161E7F3F00C2E652 /* RuleFeature.cpp */,
@@ -31173,6 +31178,7 @@
 				B2FA3D570AB75A6F000E5AC4 /* JSSVGAnimationElement.h in Headers */,
 				B2FA3D590AB75A6F000E5AC4 /* JSSVGCircleElement.h in Headers */,
 				B2FA3D5B0AB75A6F000E5AC4 /* JSSVGClipPathElement.h in Headers */,
+				E45A6C772417BA59006E4CD5 /* PseudoClassChangeInvalidation.h in Headers */,
 				B2FA3D5F0AB75A6F000E5AC4 /* JSSVGComponentTransferFunctionElement.h in Headers */,
 				B2FA3D610AB75A6F000E5AC4 /* JSSVGCursorElement.h in Headers */,
 				B2FA3D630AB75A6F000E5AC4 /* JSSVGDefsElement.h in Headers */,

Modified: trunk/Source/WebCore/dom/Element.cpp (258320 => 258321)


--- trunk/Source/WebCore/dom/Element.cpp	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/dom/Element.cpp	2020-03-12 13:30:10 UTC (rev 258321)
@@ -86,6 +86,7 @@
 #include "PointerCaptureController.h"
 #include "PointerEvent.h"
 #include "PointerLockController.h"
+#include "PseudoClassChangeInvalidation.h"
 #include "RenderFragmentedFlow.h"
 #include "RenderLayer.h"
 #include "RenderLayerBacking.h"
@@ -632,17 +633,15 @@
 {
     if (flag == active())
         return;
+    {
+        Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassActive);
+        document().userActionElements().setActive(*this, flag);
+    }
 
-    document().userActionElements().setActive(*this, flag);
-
-    auto* renderStyle = renderOrDisplayContentsStyle();
-    bool reactsToPress = (renderStyle && renderStyle->affectedByActive()) || styleAffectedByActive();
-    if (reactsToPress)
-        invalidateStyleForSubtree();
-
     if (!renderer())
         return;
 
+    bool reactsToPress = false;
     if (renderer()->style().hasAppearance() && renderer()->theme().stateChanged(*renderer(), ControlStates::PressedState))
         reactsToPress = true;
 
@@ -681,10 +680,12 @@
 {
     if (flag == focused())
         return;
+    {
+        Style::PseudoClassChangeInvalidation focusStyleInvalidation(*this, CSSSelector::PseudoClassFocus);
+        Style::PseudoClassChangeInvalidation directFocusStyleInvalidation(*this, CSSSelector::PseudoClassDirectFocus);
+        document().userActionElements().setFocused(*this, flag);
+    }
 
-    document().userActionElements().setFocused(*this, flag);
-    invalidateStyleForSubtree();
-
     // Shadow host with a slot that contain focused element is not considered focused.
     for (auto* root = containingShadowRoot(); root; root = root->host()->containingShadowRoot()) {
         root->setContainsFocusedElement(flag);
@@ -691,34 +692,30 @@
         root->host()->invalidateStyle();
     }
 
-    for (Element* element = this; element; element = element->parentElementInComposedTree())
+    for (auto* element = this; element; element = element->parentElementInComposedTree())
         element->setHasFocusWithin(flag);
 }
 
+void Element::setHasFocusWithin(bool flag)
+{
+    if (hasFocusWithin() == flag)
+        return;
+    {
+        Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassFocusWithin);
+        setFlag(flag, HasFocusWithin);
+    }
+}
+
 void Element::setHovered(bool flag)
 {
     if (flag == hovered())
         return;
-
-    document().userActionElements().setHovered(*this, flag);
-
-    auto* style = renderOrDisplayContentsStyle();
-    if (style && (style->affectedByHover() || childrenAffectedByHover()))
-        invalidateStyleForSubtree();
-
-    if (!renderer()) {
-        // When setting hover to false, the style needs to be recalc'd even when
-        // there's no renderer (imagine setting display:none in the :hover class,
-        // if a nil renderer would prevent this element from recalculating its
-        // style, it would never go back to its normal style and remain
-        // stuck in its hovered style).
-        if (!flag && !style)
-            invalidateStyleForSubtree();
-
-        return;
+    {
+        Style::PseudoClassChangeInvalidation styleInvalidation(*this, CSSSelector::PseudoClassHover);
+        document().userActionElements().setHovered(*this, flag);
     }
 
-    if (style->hasAppearance())
+    if (auto* style = renderStyle(); style && style->hasAppearance())
         renderer()->theme().stateChanged(*renderer(), ControlStates::HoverState);
 }
 

Modified: trunk/Source/WebCore/dom/Element.h (258320 => 258321)


--- trunk/Source/WebCore/dom/Element.h	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/dom/Element.h	2020-03-12 13:30:10 UTC (rev 258321)
@@ -859,15 +859,6 @@
     return element.isHTMLElement() && element.document().isHTMLDocument();
 }
 
-inline void Element::setHasFocusWithin(bool flag)
-{
-    if (hasFocusWithin() == flag)
-        return;
-    setFlag(flag, HasFocusWithin);
-    if (styleAffectedByFocusWithin())
-        invalidateStyleForSubtree();
-}
-
 template<typename... QualifiedNames>
 inline const AtomString& Element::getAttribute(const QualifiedName& name, const QualifiedNames&... names) const
 {

Added: trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp (0 => 258321)


--- trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp	                        (rev 0)
+++ trunk/Source/WebCore/style/PseudoClassChangeInvalidation.cpp	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "PseudoClassChangeInvalidation.h"
+
+#include "ElementChildIterator.h"
+#include "StyleInvalidationFunctions.h"
+
+namespace WebCore {
+namespace Style {
+
+void PseudoClassChangeInvalidation::computeInvalidation(CSSSelector::PseudoClassType pseudoClass)
+{
+    bool shouldInvalidateCurrent = false;
+    bool mayAffectStyleInShadowTree = false;
+
+    traverseRuleFeatures(m_element, [&] (const RuleFeatureSet& features, bool mayAffectShadowTree) {
+        if (mayAffectShadowTree && features.pseudoClassRules.contains(pseudoClass))
+            mayAffectStyleInShadowTree = true;
+        if (m_element.shadowRoot() && features.pseudoClassesAffectingHost.contains(pseudoClass))
+            shouldInvalidateCurrent = true;
+    });
+
+    if (mayAffectStyleInShadowTree) {
+        // FIXME: We should do fine-grained invalidation for shadow tree.
+        m_element.invalidateStyleForSubtree();
+    }
+
+    if (shouldInvalidateCurrent)
+        m_element.invalidateStyle();
+
+    auto& ruleSets = m_element.styleResolver().ruleSets();
+    if (auto* invalidationRuleSets = ruleSets.pseudoClassInvalidationRuleSets(pseudoClass)) {
+        for (auto& invalidationRuleSet : *invalidationRuleSets)
+            Invalidator::addToMatchElementRuleSets(m_matchElementRuleSets, invalidationRuleSet);
+    }
+}
+
+void PseudoClassChangeInvalidation::invalidateStyleWithRuleSets()
+{
+    Invalidator::invalidateWithMatchElementRuleSets(m_element, m_matchElementRuleSets);
+}
+
+}
+}

Added: trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h (0 => 258321)


--- trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h	                        (rev 0)
+++ trunk/Source/WebCore/style/PseudoClassChangeInvalidation.h	2020-03-12 13:30:10 UTC (rev 258321)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "CSSSelector.h"
+#include "Element.h"
+#include "StyleInvalidator.h"
+#include <wtf/Vector.h>
+
+namespace WebCore {
+namespace Style {
+
+class PseudoClassChangeInvalidation {
+public:
+    PseudoClassChangeInvalidation(Element&, CSSSelector::PseudoClassType);
+    ~PseudoClassChangeInvalidation();
+
+private:
+    void computeInvalidation(CSSSelector::PseudoClassType);
+    void invalidateStyleWithRuleSets();
+
+    const bool m_isEnabled;
+    Element& m_element;
+
+    Invalidator::MatchElementRuleSets m_matchElementRuleSets;
+};
+
+inline PseudoClassChangeInvalidation::PseudoClassChangeInvalidation(Element& element, CSSSelector::PseudoClassType pseudoClassType)
+    : m_isEnabled(element.needsStyleInvalidation())
+    , m_element(element)
+
+{
+    if (!m_isEnabled)
+        return;
+    computeInvalidation(pseudoClassType);
+    invalidateStyleWithRuleSets();
+}
+
+inline PseudoClassChangeInvalidation::~PseudoClassChangeInvalidation()
+{
+    if (!m_isEnabled)
+        return;
+    invalidateStyleWithRuleSets();
+}
+
+}
+}

Modified: trunk/Source/WebCore/style/RuleFeature.cpp (258320 => 258321)


--- trunk/Source/WebCore/style/RuleFeature.cpp	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/style/RuleFeature.cpp	2020-03-12 13:30:10 UTC (rev 258321)
@@ -153,7 +153,8 @@
             default:
                 break;
             }
-        }
+        } else if (selector->match() == CSSSelector::PseudoClass)
+            selectorFeatures.pseudoClasses.append(std::make_pair(selector->pseudoClassType(), matchElement));
 
         if (!selectorFeatures.hasSiblingSelector && selector->isSiblingSelector())
             selectorFeatures.hasSiblingSelector = true;
@@ -199,6 +200,13 @@
         if (matchElement == MatchElement::Host)
             attributesAffectingHost.add(selector->attribute().localName().convertToASCIILowercase());
     }
+    for (auto& keyAndMatch : selectorFeatures.pseudoClasses) {
+        pseudoClassRules.ensure(keyAndMatch.first, [] {
+            return makeUnique<Vector<RuleFeature>>();
+        }).iterator->value->append({ ruleData, keyAndMatch.second });
+        if (keyAndMatch.second == MatchElement::Host)
+            pseudoClassesAffectingHost.add(keyAndMatch.first);
+    }
 }
 
 void RuleFeatureSet::add(const RuleFeatureSet& other)
@@ -224,6 +232,13 @@
     }
     attributesAffectingHost.add(other.attributesAffectingHost.begin(), other.attributesAffectingHost.end());
 
+    for (auto& keyValuePair : other.pseudoClassRules) {
+        pseudoClassRules.ensure(keyValuePair.key, [] {
+            return makeUnique<Vector<RuleFeature>>();
+        }).iterator->value->appendVector(*keyValuePair.value);
+    }
+    pseudoClassesAffectingHost.add(other.pseudoClassesAffectingHost.begin(), other.pseudoClassesAffectingHost.end());
+
     usesFirstLineRules = usesFirstLineRules || other.usesFirstLineRules;
     usesFirstLetterRules = usesFirstLetterRules || other.usesFirstLetterRules;
 }
@@ -248,6 +263,8 @@
     classesAffectingHost.clear();
     attributeRules.clear();
     attributesAffectingHost.clear();
+    pseudoClassRules.clear();
+    pseudoClassesAffectingHost.clear();
     usesFirstLineRules = false;
     usesFirstLetterRules = false;
 }
@@ -260,6 +277,8 @@
         rules->shrinkToFit();
     for (auto& rules : attributeRules.values())
         rules->shrinkToFit();
+    for (auto& rules : pseudoClassRules.values())
+        rules->shrinkToFit();
 }
 
 } // namespace Style

Modified: trunk/Source/WebCore/style/RuleFeature.h (258320 => 258321)


--- trunk/Source/WebCore/style/RuleFeature.h	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/style/RuleFeature.h	2020-03-12 13:30:10 UTC (rev 258321)
@@ -75,8 +75,10 @@
     
     HashMap<AtomString, std::unique_ptr<Vector<RuleFeature>>> classRules;
     HashMap<AtomString, std::unique_ptr<Vector<RuleFeatureWithInvalidationSelector>>> attributeRules;
+    HashMap<CSSSelector::PseudoClassType, std::unique_ptr<Vector<RuleFeature>>, WTF::IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> pseudoClassRules;
     HashSet<AtomString> classesAffectingHost;
     HashSet<AtomString> attributesAffectingHost;
+    HashSet<CSSSelector::PseudoClassType, WTF::IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> pseudoClassesAffectingHost;
 
     bool usesFirstLineRules { false };
     bool usesFirstLetterRules { false };
@@ -90,6 +92,7 @@
 
         Vector<std::pair<AtomString, MatchElement>, 32> classes;
         Vector<std::pair<const CSSSelector*, MatchElement>, 32> attributes;
+        Vector<std::pair<CSSSelector::PseudoClassType, MatchElement>, 32> pseudoClasses;
     };
     void recursivelyCollectFeaturesFromSelector(SelectorFeatures&, const CSSSelector&, MatchElement = MatchElement::Subject);
 };

Modified: trunk/Source/WebCore/style/StyleScopeRuleSets.cpp (258320 => 258321)


--- trunk/Source/WebCore/style/StyleScopeRuleSets.cpp	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/style/StyleScopeRuleSets.cpp	2020-03-12 13:30:10 UTC (rev 258321)
@@ -196,13 +196,15 @@
 
     m_classInvalidationRuleSets.clear();
     m_attributeInvalidationRuleSets.clear();
+    m_pseudoClassInvalidationRuleSets.clear();
+
     m_cachedHasComplexSelectorsForStyleAttribute = WTF::nullopt;
 
     m_features.shrinkToFit();
 }
 
-template<typename RuleFeatureType>
-static Vector<InvalidationRuleSet>* ensureInvalidationRuleSets(const AtomString& key, HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>>& ruleSetMap, const HashMap<AtomString, std::unique_ptr<Vector<RuleFeatureType>>>& ruleFeatures)
+template<typename KeyType, typename RuleFeatureType, typename Hash, typename HashTraits>
+static Vector<InvalidationRuleSet>* ensureInvalidationRuleSets(const KeyType& key, HashMap<KeyType, std::unique_ptr<Vector<InvalidationRuleSet>>, Hash, HashTraits>& ruleSetMap, const HashMap<KeyType, std::unique_ptr<Vector<RuleFeatureType>>, Hash, HashTraits>& ruleFeatures)
 {
     return ruleSetMap.ensure(key, [&] () -> std::unique_ptr<Vector<InvalidationRuleSet>> {
         auto* features = ruleFeatures.get(key);
@@ -241,6 +243,11 @@
     return ensureInvalidationRuleSets(attributeName, m_attributeInvalidationRuleSets, m_features.attributeRules);
 }
 
+const Vector<InvalidationRuleSet>* ScopeRuleSets::pseudoClassInvalidationRuleSets(CSSSelector::PseudoClassType pseudoClass) const
+{
+    return ensureInvalidationRuleSets(pseudoClass, m_pseudoClassInvalidationRuleSets, m_features.pseudoClassRules);
+}
+
 bool ScopeRuleSets::hasComplexSelectorsForStyleAttribute() const
 {
     auto compute = [&] {

Modified: trunk/Source/WebCore/style/StyleScopeRuleSets.h (258320 => 258321)


--- trunk/Source/WebCore/style/StyleScopeRuleSets.h	2020-03-12 10:39:05 UTC (rev 258320)
+++ trunk/Source/WebCore/style/StyleScopeRuleSets.h	2020-03-12 13:30:10 UTC (rev 258321)
@@ -65,6 +65,7 @@
 
     const Vector<InvalidationRuleSet>* classInvalidationRuleSets(const AtomString& className) const;
     const Vector<InvalidationRuleSet>* attributeInvalidationRuleSets(const AtomString& attributeName) const;
+    const Vector<InvalidationRuleSet>* pseudoClassInvalidationRuleSets(CSSSelector::PseudoClassType) const;
 
     bool hasComplexSelectorsForStyleAttribute() const;
 
@@ -101,6 +102,7 @@
     mutable RefPtr<RuleSet> m_uncommonAttributeRuleSet;
     mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_classInvalidationRuleSets;
     mutable HashMap<AtomString, std::unique_ptr<Vector<InvalidationRuleSet>>> m_attributeInvalidationRuleSets;
+    mutable HashMap<CSSSelector::PseudoClassType, std::unique_ptr<Vector<InvalidationRuleSet>>, WTF::IntHash<CSSSelector::PseudoClassType>, WTF::StrongEnumHashTraits<CSSSelector::PseudoClassType>> m_pseudoClassInvalidationRuleSets;
 
     mutable Optional<bool> m_cachedHasComplexSelectorsForStyleAttribute;
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to