Title: [287445] trunk
Revision
287445
Author
an...@apple.com
Date
2021-12-26 10:45:32 -0800 (Sun, 26 Dec 2021)

Log Message

[:has() pseudo-class] Support :disabled and :enabled pseudo-class invalidation
https://bugs.webkit.org/show_bug.cgi?id=234636

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

* web-platform-tests/css/selectors/invalidation/has-pseudo-class.html:

Source/WebCore:

Use Style::PseudoClassChangeInvalidation to support invalidation with :has(:disabled).

* html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::setAncestorDisabled):
(WebCore::HTMLFormControlElement::parseAttribute):
(WebCore::HTMLFormControlElement::disabledStateChanged):
* html/HTMLOptGroupElement.cpp:
(WebCore::HTMLOptGroupElement::isDisabledFormControl const):

Use a member bit instead of checking the attribute directly. This allows invalidation to be scoped over the state change.

(WebCore::HTMLOptGroupElement::parseAttribute):

Optgroup can flip the disabled status of the associated option elements too so handle that specifically.

* html/HTMLOptGroupElement.h:
* html/HTMLOptionElement.cpp:
(WebCore::HTMLOptionElement::parseAttribute):

Modified Paths

Diff

Modified: trunk/LayoutTests/imported/w3c/ChangeLog (287444 => 287445)


--- trunk/LayoutTests/imported/w3c/ChangeLog	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/LayoutTests/imported/w3c/ChangeLog	2021-12-26 18:45:32 UTC (rev 287445)
@@ -1,3 +1,12 @@
+2021-12-26  Antti Koivisto  <an...@apple.com>
+
+        [:has() pseudo-class] Support :disabled and :enabled pseudo-class invalidation
+        https://bugs.webkit.org/show_bug.cgi?id=234636
+
+        Reviewed by Simon Fraser.
+
+        * web-platform-tests/css/selectors/invalidation/has-pseudo-class.html:
+
 2021-12-24  Tim Nguyen  <n...@apple.com>
 
         Internally unprefix -webkit-font-kerning CSS property

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class-expected.txt (287444 => 287445)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class-expected.txt	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class-expected.txt	2021-12-26 18:45:32 UTC (rev 287445)
@@ -1,8 +1,32 @@
 
 
-PASS Initial color
-PASS Set checked on checkbox
-PASS Unset checked on checkbox
-PASS Set selected on option
-PASS Unset selected on option
+PASS Before set checked on checkbox, testing subject
+PASS Set checked on checkbox, testing subject
+PASS Unset checked on checkbox, testing subject
+PASS Set select on option
+PASS Reset select
+PASS Before set disabled on checkbox, testing subject
+PASS Set disabled on checkbox, testing subject
+PASS Unset disabled on checkbox, testing subject
+PASS Before set disabled on checkbox, testing subject3
+PASS Set disabled on checkbox, testing subject3
+PASS Unset disabled on checkbox, testing subject3
+PASS Before set disabled on option, testing subject
+PASS Set disabled on option, testing subject
+PASS Unset disabled on option, testing subject
+PASS Before set disabled on option, testing subject3
+PASS Set disabled on option, testing subject3
+PASS Unset disabled on option, testing subject3
+PASS Before set disabled on optgroup, testing subject
+PASS Set disabled on optgroup, testing subject
+PASS Unset disabled on optgroup, testing subject
+PASS Before set disabled on optgroup, testing subject2
+PASS Set disabled on optgroup, testing subject2
+PASS Unset disabled on optgroup, testing subject2
+PASS Before set disabled on optgroup, testing subject3
+PASS Set disabled on optgroup, testing subject3
+PASS Unset disabled on optgroup, testing subject3
+PASS Before set disabled on optgroup, testing subject4
+PASS Set disabled on optgroup, testing subject4
+PASS Unset disabled on optgroup, testing subject4
 

Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class.html (287444 => 287445)


--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class.html	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class.html	2021-12-26 18:45:32 UTC (rev 287445)
@@ -6,15 +6,24 @@
 <script src=""
 <link rel="help" href=""
 <style>
-div, main { color: grey }
+main:has(input) div { color: grey }
 main:has(#checkbox:checked) > #subject { color: red }
-main:has(#option:checked) > #subject { color: green }
+main:has(#option:checked) > #subject { color: red }
+main:has(#checkbox:disabled) > #subject { color: green }
+main:has(#option:disabled) > :is(#subject, #subject2) { color: green }
+main:has(#optgroup:disabled) > #subject { color: blue }
+main:not(:has(#checkbox:enabled)) > #subject3 { color: green }
+main:not(:has(#option:enabled)) :is(#subject3, #subject4) { color: green }
+main:not(:has(#optgroup:enabled)) > #subject3 { color: blue }
 </style>
 
 <main id=main>
     <input type=checkbox id=checkbox></input>
-    <select><option>a</option><option id=option>b</option></select>
+    <select id=select><optgroup id=optgroup><option>a</option><option id=option>b</option></optgroup></select>
     <div id=subject></div>
+    <div id=subject2></div>
+    <div id=subject3></div>
+    <div id=subject4></div>
 </main>
 
 <script>
@@ -26,22 +35,43 @@
 const purple = 'rgb(128, 0, 128)';
 const pink = 'rgb(255, 192, 203)';
 
-function testColor(test_name, color) {
+function testColor(test_name, subject_element, color) {
     test(function() {
-        assert_equals(getComputedStyle(subject).color, color);
+        assert_equals(getComputedStyle(subject_element).color, color);
     }, test_name);
 }
 
-function testPseudoClassChange(element, property, expectedColor)
+function testPseudoClassChange(element, property, subject_element, expectedColor)
 {
+    testColor(`Before set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey);
+
     element[property] = true;
-    testColor(`Set ${property} on ${element.id}`, expectedColor);
+    testColor(`Set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, expectedColor);
+
     element[property] = false;
-    testColor(`Unset ${property} on ${element.id}`, grey);
+    testColor(`Unset ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey);
 }
 
-testColor('Initial color', grey);
+function testSelectedChange(option, subject_element, expectedColor)
+{
+    const oldOption = select.selectedOptions[0];
+    option.selected = true;
+    testColor(`Set select on ${option.id}`, subject_element, expectedColor);
+    oldOption.selected = true;
+    testColor(`Reset select`, subject, grey);
+}
 
-testPseudoClassChange(checkbox, "checked", red);
-testPseudoClassChange(option, "selected", green);
+testPseudoClassChange(checkbox, "checked", subject, red);
+testSelectedChange(option, subject, red);
+
+testPseudoClassChange(checkbox, "disabled", subject, green);
+testPseudoClassChange(checkbox, "disabled", subject3, green);
+testPseudoClassChange(option, "disabled", subject, green);
+testPseudoClassChange(option, "disabled", subject3, green);
+
+testPseudoClassChange(optgroup, "disabled", subject, blue);
+testPseudoClassChange(optgroup, "disabled", subject2, green);
+testPseudoClassChange(optgroup, "disabled", subject3, blue);
+testPseudoClassChange(optgroup, "disabled", subject4, green);
+
 </script>

Modified: trunk/Source/WebCore/ChangeLog (287444 => 287445)


--- trunk/Source/WebCore/ChangeLog	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/Source/WebCore/ChangeLog	2021-12-26 18:45:32 UTC (rev 287445)
@@ -1,3 +1,29 @@
+2021-12-26  Antti Koivisto  <an...@apple.com>
+
+        [:has() pseudo-class] Support :disabled and :enabled pseudo-class invalidation
+        https://bugs.webkit.org/show_bug.cgi?id=234636
+
+        Reviewed by Simon Fraser.
+
+        Use Style::PseudoClassChangeInvalidation to support invalidation with :has(:disabled).
+
+        * html/HTMLFormControlElement.cpp:
+        (WebCore::HTMLFormControlElement::setAncestorDisabled):
+        (WebCore::HTMLFormControlElement::parseAttribute):
+        (WebCore::HTMLFormControlElement::disabledStateChanged):
+        * html/HTMLOptGroupElement.cpp:
+        (WebCore::HTMLOptGroupElement::isDisabledFormControl const):
+
+        Use a member bit instead of checking the attribute directly. This allows invalidation to be scoped over the state change.
+
+        (WebCore::HTMLOptGroupElement::parseAttribute):
+
+        Optgroup can flip the disabled status of the associated option elements too so handle that specifically.
+
+        * html/HTMLOptGroupElement.h:
+        * html/HTMLOptionElement.cpp:
+        (WebCore::HTMLOptionElement::parseAttribute):
+
 2021-12-26  Alan Bujtas  <za...@apple.com>
 
         makeTextLogicalOrderCacheIfNeeded is only interested in whether the content needs visual reordering

Modified: trunk/Source/WebCore/html/HTMLFormControlElement.cpp (287444 => 287445)


--- trunk/Source/WebCore/html/HTMLFormControlElement.cpp	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/Source/WebCore/html/HTMLFormControlElement.cpp	2021-12-26 18:45:32 UTC (rev 287445)
@@ -40,6 +40,7 @@
 #include "HTMLLegendElement.h"
 #include "HTMLParserIdioms.h"
 #include "HTMLTextAreaElement.h"
+#include "PseudoClassChangeInvalidation.h"
 #include "Quirks.h"
 #include "RenderBox.h"
 #include "RenderTheme.h"
@@ -143,10 +144,14 @@
 void HTMLFormControlElement::setAncestorDisabled(bool isDisabled)
 {
     ASSERT(computeIsDisabledByFieldsetAncestor() == isDisabled);
-    bool oldValue = m_disabledByAncestorFieldset;
+    if (m_disabledByAncestorFieldset == isDisabled)
+        return;
+
+    Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
+    Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
+
     m_disabledByAncestorFieldset = isDisabled;
-    if (oldValue != m_disabledByAncestorFieldset)
-        disabledStateChanged();
+    disabledStateChanged();
 }
 
 void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomString& value)
@@ -155,10 +160,13 @@
         formAttributeChanged();
     else if (name == disabledAttr) {
         if (canBeActuallyDisabled()) {
-            bool oldDisabled = m_disabled;
-            m_disabled = !value.isNull();
-            if (oldDisabled != m_disabled)
+            bool newDisabled = !value.isNull();
+            if (m_disabled != newDisabled) {
+                Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
+                Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
+                m_disabled = newDisabled;
                 disabledAttributeChanged();
+            }
         }
     } else if (name == readonlyAttr) {
         bool wasReadOnly = m_isReadOnly;
@@ -182,7 +190,6 @@
 void HTMLFormControlElement::disabledStateChanged()
 {
     updateWillValidateAndValidity();
-    invalidateStyleForSubtree();
     if (renderer() && renderer()->style().hasEffectiveAppearance())
         renderer()->theme().stateChanged(*renderer(), ControlStates::States::Enabled);
 }

Modified: trunk/Source/WebCore/html/HTMLOptGroupElement.cpp (287444 => 287445)


--- trunk/Source/WebCore/html/HTMLOptGroupElement.cpp	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/Source/WebCore/html/HTMLOptGroupElement.cpp	2021-12-26 18:45:32 UTC (rev 287445)
@@ -27,8 +27,11 @@
 
 #include "Document.h"
 #include "ElementAncestorIterator.h"
+#include "ElementIterator.h"
 #include "HTMLNames.h"
+#include "HTMLOptionElement.h"
 #include "HTMLSelectElement.h"
+#include "PseudoClassChangeInvalidation.h"
 #include "RenderMenuList.h"
 #include "NodeRenderStyle.h"
 #include "StyleResolver.h"
@@ -54,7 +57,7 @@
 
 bool HTMLOptGroupElement::isDisabledFormControl() const
 {
-    return hasAttributeWithoutSynchronization(disabledAttr);
+    return m_isDisabled;
 }
 
 bool HTMLOptGroupElement::isFocusable() const
@@ -83,8 +86,21 @@
     HTMLElement::parseAttribute(name, value);
     recalcSelectOptions();
 
-    if (name == disabledAttr)
-        invalidateStyleForSubtree();
+    if (name == disabledAttr) {
+        bool newDisabled = !value.isNull();
+        if (m_isDisabled != newDisabled) {
+            Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
+            Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
+
+            Vector<Style::PseudoClassChangeInvalidation> optionInvalidation;
+            for (auto& descendant : descendantsOfType<HTMLOptionElement>(*this)) {
+                optionInvalidation.append({ descendant, CSSSelector::PseudoClassDisabled });
+                optionInvalidation.append({ descendant, CSSSelector::PseudoClassEnabled });
+            }
+
+            m_isDisabled = newDisabled;
+        }
+    }
 }
 
 void HTMLOptGroupElement::recalcSelectOptions()

Modified: trunk/Source/WebCore/html/HTMLOptGroupElement.h (287444 => 287445)


--- trunk/Source/WebCore/html/HTMLOptGroupElement.h	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/Source/WebCore/html/HTMLOptGroupElement.h	2021-12-26 18:45:32 UTC (rev 287445)
@@ -52,6 +52,8 @@
     bool accessKeyAction(bool sendMouseEvents) final;
 
     void recalcSelectOptions();
+
+    bool m_isDisabled { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/html/HTMLOptionElement.cpp (287444 => 287445)


--- trunk/Source/WebCore/html/HTMLOptionElement.cpp	2021-12-26 17:21:44 UTC (rev 287444)
+++ trunk/Source/WebCore/html/HTMLOptionElement.cpp	2021-12-26 18:45:32 UTC (rev 287445)
@@ -176,10 +176,11 @@
     } else
 #endif
     if (name == disabledAttr) {
-        bool oldDisabled = m_disabled;
-        m_disabled = !value.isNull();
-        if (oldDisabled != m_disabled) {
-            invalidateStyleForSubtree();
+        bool newDisabled = !value.isNull();
+        if (m_disabled != newDisabled) {
+            Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
+            Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
+            m_disabled = newDisabled;
             if (renderer() && renderer()->style().hasEffectiveAppearance())
                 renderer()->theme().stateChanged(*renderer(), ControlStates::States::Enabled);
         }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to