Changeset 287445 in webkit


Ignore:
Timestamp:
Dec 26, 2021 10:45:32 AM (7 months ago)
Author:
Antti Koivisto
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):

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r287434 r287445  
     12021-12-26  Antti Koivisto  <antti@apple.com>
     2
     3        [:has() pseudo-class] Support :disabled and :enabled pseudo-class invalidation
     4        https://bugs.webkit.org/show_bug.cgi?id=234636
     5
     6        Reviewed by Simon Fraser.
     7
     8        * web-platform-tests/css/selectors/invalidation/has-pseudo-class.html:
     9
    1102021-12-24  Tim Nguyen  <ntim@apple.com>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class-expected.txt

    r287363 r287445  
    11
    22
    3 PASS Initial color
    4 PASS Set checked on checkbox
    5 PASS Unset checked on checkbox
    6 PASS Set selected on option
    7 PASS Unset selected on option
     3PASS Before set checked on checkbox, testing subject
     4PASS Set checked on checkbox, testing subject
     5PASS Unset checked on checkbox, testing subject
     6PASS Set select on option
     7PASS Reset select
     8PASS Before set disabled on checkbox, testing subject
     9PASS Set disabled on checkbox, testing subject
     10PASS Unset disabled on checkbox, testing subject
     11PASS Before set disabled on checkbox, testing subject3
     12PASS Set disabled on checkbox, testing subject3
     13PASS Unset disabled on checkbox, testing subject3
     14PASS Before set disabled on option, testing subject
     15PASS Set disabled on option, testing subject
     16PASS Unset disabled on option, testing subject
     17PASS Before set disabled on option, testing subject3
     18PASS Set disabled on option, testing subject3
     19PASS Unset disabled on option, testing subject3
     20PASS Before set disabled on optgroup, testing subject
     21PASS Set disabled on optgroup, testing subject
     22PASS Unset disabled on optgroup, testing subject
     23PASS Before set disabled on optgroup, testing subject2
     24PASS Set disabled on optgroup, testing subject2
     25PASS Unset disabled on optgroup, testing subject2
     26PASS Before set disabled on optgroup, testing subject3
     27PASS Set disabled on optgroup, testing subject3
     28PASS Unset disabled on optgroup, testing subject3
     29PASS Before set disabled on optgroup, testing subject4
     30PASS Set disabled on optgroup, testing subject4
     31PASS Unset disabled on optgroup, testing subject4
    832
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/selectors/invalidation/has-pseudo-class.html

    r287363 r287445  
    77<link rel="help" href="https://drafts.csswg.org/selectors/#relational">
    88<style>
    9 div, main { color: grey }
     9main:has(input) div { color: grey }
    1010main:has(#checkbox:checked) > #subject { color: red }
    11 main:has(#option:checked) > #subject { color: green }
     11main:has(#option:checked) > #subject { color: red }
     12main:has(#checkbox:disabled) > #subject { color: green }
     13main:has(#option:disabled) > :is(#subject, #subject2) { color: green }
     14main:has(#optgroup:disabled) > #subject { color: blue }
     15main:not(:has(#checkbox:enabled)) > #subject3 { color: green }
     16main:not(:has(#option:enabled)) :is(#subject3, #subject4) { color: green }
     17main:not(:has(#optgroup:enabled)) > #subject3 { color: blue }
    1218</style>
    1319
    1420<main id=main>
    1521    <input type=checkbox id=checkbox></input>
    16     <select><option>a</option><option id=option>b</option></select>
     22    <select id=select><optgroup id=optgroup><option>a</option><option id=option>b</option></optgroup></select>
    1723    <div id=subject></div>
     24    <div id=subject2></div>
     25    <div id=subject3></div>
     26    <div id=subject4></div>
    1827</main>
    1928
     
    2736const pink = 'rgb(255, 192, 203)';
    2837
    29 function testColor(test_name, color) {
     38function testColor(test_name, subject_element, color) {
    3039    test(function() {
    31         assert_equals(getComputedStyle(subject).color, color);
     40        assert_equals(getComputedStyle(subject_element).color, color);
    3241    }, test_name);
    3342}
    3443
    35 function testPseudoClassChange(element, property, expectedColor)
     44function testPseudoClassChange(element, property, subject_element, expectedColor)
    3645{
     46    testColor(`Before set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey);
     47
    3748    element[property] = true;
    38     testColor(`Set ${property} on ${element.id}`, expectedColor);
     49    testColor(`Set ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, expectedColor);
     50
    3951    element[property] = false;
    40     testColor(`Unset ${property} on ${element.id}`, grey);
     52    testColor(`Unset ${property} on ${element.id}, testing ${subject_element.id}`, subject_element, grey);
    4153}
    4254
    43 testColor('Initial color', grey);
     55function testSelectedChange(option, subject_element, expectedColor)
     56{
     57    const oldOption = select.selectedOptions[0];
     58    option.selected = true;
     59    testColor(`Set select on ${option.id}`, subject_element, expectedColor);
     60    oldOption.selected = true;
     61    testColor(`Reset select`, subject, grey);
     62}
    4463
    45 testPseudoClassChange(checkbox, "checked", red);
    46 testPseudoClassChange(option, "selected", green);
     64testPseudoClassChange(checkbox, "checked", subject, red);
     65testSelectedChange(option, subject, red);
     66
     67testPseudoClassChange(checkbox, "disabled", subject, green);
     68testPseudoClassChange(checkbox, "disabled", subject3, green);
     69testPseudoClassChange(option, "disabled", subject, green);
     70testPseudoClassChange(option, "disabled", subject3, green);
     71
     72testPseudoClassChange(optgroup, "disabled", subject, blue);
     73testPseudoClassChange(optgroup, "disabled", subject2, green);
     74testPseudoClassChange(optgroup, "disabled", subject3, blue);
     75testPseudoClassChange(optgroup, "disabled", subject4, green);
     76
    4777</script>
  • trunk/Source/WebCore/ChangeLog

    r287444 r287445  
     12021-12-26  Antti Koivisto  <antti@apple.com>
     2
     3        [:has() pseudo-class] Support :disabled and :enabled pseudo-class invalidation
     4        https://bugs.webkit.org/show_bug.cgi?id=234636
     5
     6        Reviewed by Simon Fraser.
     7
     8        Use Style::PseudoClassChangeInvalidation to support invalidation with :has(:disabled).
     9
     10        * html/HTMLFormControlElement.cpp:
     11        (WebCore::HTMLFormControlElement::setAncestorDisabled):
     12        (WebCore::HTMLFormControlElement::parseAttribute):
     13        (WebCore::HTMLFormControlElement::disabledStateChanged):
     14        * html/HTMLOptGroupElement.cpp:
     15        (WebCore::HTMLOptGroupElement::isDisabledFormControl const):
     16
     17        Use a member bit instead of checking the attribute directly. This allows invalidation to be scoped over the state change.
     18
     19        (WebCore::HTMLOptGroupElement::parseAttribute):
     20
     21        Optgroup can flip the disabled status of the associated option elements too so handle that specifically.
     22
     23        * html/HTMLOptGroupElement.h:
     24        * html/HTMLOptionElement.cpp:
     25        (WebCore::HTMLOptionElement::parseAttribute):
     26
    1272021-12-26  Alan Bujtas  <zalan@apple.com>
    228
  • trunk/Source/WebCore/html/HTMLFormControlElement.cpp

    r286855 r287445  
    4141#include "HTMLParserIdioms.h"
    4242#include "HTMLTextAreaElement.h"
     43#include "PseudoClassChangeInvalidation.h"
    4344#include "Quirks.h"
    4445#include "RenderBox.h"
     
    144145{
    145146    ASSERT(computeIsDisabledByFieldsetAncestor() == isDisabled);
    146     bool oldValue = m_disabledByAncestorFieldset;
     147    if (m_disabledByAncestorFieldset == isDisabled)
     148        return;
     149
     150    Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
     151    Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
     152
    147153    m_disabledByAncestorFieldset = isDisabled;
    148     if (oldValue != m_disabledByAncestorFieldset)
    149         disabledStateChanged();
     154    disabledStateChanged();
    150155}
    151156
     
    156161    else if (name == disabledAttr) {
    157162        if (canBeActuallyDisabled()) {
    158             bool oldDisabled = m_disabled;
    159             m_disabled = !value.isNull();
    160             if (oldDisabled != m_disabled)
     163            bool newDisabled = !value.isNull();
     164            if (m_disabled != newDisabled) {
     165                Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
     166                Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
     167                m_disabled = newDisabled;
    161168                disabledAttributeChanged();
     169            }
    162170        }
    163171    } else if (name == readonlyAttr) {
     
    183191{
    184192    updateWillValidateAndValidity();
    185     invalidateStyleForSubtree();
    186193    if (renderer() && renderer()->style().hasEffectiveAppearance())
    187194        renderer()->theme().stateChanged(*renderer(), ControlStates::States::Enabled);
  • trunk/Source/WebCore/html/HTMLOptGroupElement.cpp

    r282799 r287445  
    2828#include "Document.h"
    2929#include "ElementAncestorIterator.h"
     30#include "ElementIterator.h"
    3031#include "HTMLNames.h"
     32#include "HTMLOptionElement.h"
    3133#include "HTMLSelectElement.h"
     34#include "PseudoClassChangeInvalidation.h"
    3235#include "RenderMenuList.h"
    3336#include "NodeRenderStyle.h"
     
    5558bool HTMLOptGroupElement::isDisabledFormControl() const
    5659{
    57     return hasAttributeWithoutSynchronization(disabledAttr);
     60    return m_isDisabled;
    5861}
    5962
     
    8487    recalcSelectOptions();
    8588
    86     if (name == disabledAttr)
    87         invalidateStyleForSubtree();
     89    if (name == disabledAttr) {
     90        bool newDisabled = !value.isNull();
     91        if (m_isDisabled != newDisabled) {
     92            Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
     93            Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
     94
     95            Vector<Style::PseudoClassChangeInvalidation> optionInvalidation;
     96            for (auto& descendant : descendantsOfType<HTMLOptionElement>(*this)) {
     97                optionInvalidation.append({ descendant, CSSSelector::PseudoClassDisabled });
     98                optionInvalidation.append({ descendant, CSSSelector::PseudoClassEnabled });
     99            }
     100
     101            m_isDisabled = newDisabled;
     102        }
     103    }
    88104}
    89105
  • trunk/Source/WebCore/html/HTMLOptGroupElement.h

    r259687 r287445  
    5353
    5454    void recalcSelectOptions();
     55
     56    bool m_isDisabled { false };
    5557};
    5658
  • trunk/Source/WebCore/html/HTMLOptionElement.cpp

    r287363 r287445  
    177177#endif
    178178    if (name == disabledAttr) {
    179         bool oldDisabled = m_disabled;
    180         m_disabled = !value.isNull();
    181         if (oldDisabled != m_disabled) {
    182             invalidateStyleForSubtree();
     179        bool newDisabled = !value.isNull();
     180        if (m_disabled != newDisabled) {
     181            Style::PseudoClassChangeInvalidation disabledInvalidation(*this, CSSSelector::PseudoClassDisabled);
     182            Style::PseudoClassChangeInvalidation enabledInvalidation(*this, CSSSelector::PseudoClassEnabled);
     183            m_disabled = newDisabled;
    183184            if (renderer() && renderer()->style().hasEffectiveAppearance())
    184185                renderer()->theme().stateChanged(*renderer(), ControlStates::States::Enabled);
Note: See TracChangeset for help on using the changeset viewer.