Changeset 250788 in webkit


Ignore:
Timestamp:
Oct 7, 2019, 1:58:04 PM (6 years ago)
Author:
rniwa@webkit.org
Message:

focus pseudo class should match a shadow host whose shadow tree contains the focused element
https://bugs.webkit.org/show_bug.cgi?id=202432

Reviewed by Antti Koivisto.

Source/WebCore:

Note that focus pseudo class does not match a shadow host when its shadow tree contains a slot element
with a focused element or its ancestor assigned since such a shadow host has the actual focused element
in the same tree as the shadow host. (e.g. the focused element can be a direct child of the host).

In order to preserve the behavior of focus ring, which should be only drawn on the currently focused
element and not any shadow host which contains such an element, this patch introduces a new pseudo class,
-webkit-direct-focus, which is only available in the user agent stylesheet. Putting :host(:focus) rule
isn't sufficient because style rules inside shadow trees always has a lower precendence than rules
outside the shadow tree (the tree of its shadow host).

[1] Also see https://github.com/whatwg/html/pull/4731

Tests: fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html

fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html
fast/shadow-dom/focus-pseudo-on-shadow-host-1.html
fast/shadow-dom/focus-pseudo-on-shadow-host-2.html
fast/shadow-dom/focus-pseudo-on-shadow-host-3.html

  • css/CSSSelector.cpp:

(WebCore::CSSSelector::selectorText const): Added the support for -webkit-direct-focus.

  • css/CSSSelector.h:
  • css/RuleSet.cpp:

(WebCore::RuleSet::addRule): Ditto.

  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::checkOne const):: Ditto.
(WebCore::doesShadowTreeContainFocusedElement):: Ditto.
(WebCore::SelectorChecker::matchesFocusPseudoClass): Implemented the new behavior.
(WebCore::SelectorChecker::matchesDirectFocusPseudoClass): Added. Implements the old behavior for
the focus ring via -webkit-direct-focus pseudo class.

  • css/SelectorChecker.h:
  • css/SelectorPseudoClassAndCompatibilityElementMap.in: Added -webkit-direct-focus.
  • css/html.css: Use -webkit-direct-focus pseudo class to preserve the existing behavior of focus ring.
  • css/parser/CSSSelectorParser.cpp:

(WebCore::CSSSelectorParser::consumePseudo): Ignore -webkit-direct-focus in author and user stylesheets.

  • cssjit/SelectorCompiler.cpp:

(WebCore::SelectorCompiler::addPseudoClassType): Added the support for -webkit-direct-focus.

  • dom/Element.cpp:

(WebCore::Element::setFocus): Invoke setContainsFocusedElement on each shadow ancestor root of
the newly focused element. Note that we can't use :focus-within pseudo class since that would also match
the host of a shadow root which contains a slotted focused element, causing both the shadow host and
the slotted element to match :focus pseudo class in the host's tree.

  • dom/ShadowRoot.h:

LayoutTests:

Added W3C style testharness tests and ref tests.

  • fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet-expected.txt: Added.
  • fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html: Added.
  • fast/shadow-dom/focus-pseudo-matches-on-shadow-host-expected.txt: Added.
  • fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html: Added.
  • fast/shadow-dom/focus-pseudo-on-shadow-host-1-expected.html: Added.
  • fast/shadow-dom/focus-pseudo-on-shadow-host-1.html: Added.
  • fast/shadow-dom/focus-pseudo-on-shadow-host-2-expected.html: Added.
  • fast/shadow-dom/focus-pseudo-on-shadow-host-2.html: Added.
  • fast/shadow-dom/focus-pseudo-on-shadow-host-3-expected.html: Added.
  • fast/shadow-dom/focus-pseudo-on-shadow-host-3.html: Added.
Location:
trunk
Files:
10 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r250786 r250788  
     12019-10-07  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        focus pseudo class should match a shadow host whose shadow tree contains the focused element
     4        https://bugs.webkit.org/show_bug.cgi?id=202432
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Added W3C style testharness tests and ref tests.
     9
     10        * fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet-expected.txt: Added.
     11        * fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html: Added.
     12        * fast/shadow-dom/focus-pseudo-matches-on-shadow-host-expected.txt: Added.
     13        * fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html: Added.
     14        * fast/shadow-dom/focus-pseudo-on-shadow-host-1-expected.html: Added.
     15        * fast/shadow-dom/focus-pseudo-on-shadow-host-1.html: Added.
     16        * fast/shadow-dom/focus-pseudo-on-shadow-host-2-expected.html: Added.
     17        * fast/shadow-dom/focus-pseudo-on-shadow-host-2.html: Added.
     18        * fast/shadow-dom/focus-pseudo-on-shadow-host-3-expected.html: Added.
     19        * fast/shadow-dom/focus-pseudo-on-shadow-host-3.html: Added.
     20
    1212019-10-07  Chris Dumez  <cdumez@apple.com>
    222
  • trunk/LayoutTests/imported/w3c/web-platform-tests/shadow-dom/focus/focus-selector-delegatesFocus-expected.txt

    r250696 r250788  
    22foo
    33
    4 FAIL :focus applies to host with delegatesFocus=true when the shadow root's descendant has focus assert_true: host matches :focus expected true got false
     4PASS :focus applies to host with delegatesFocus=true when the shadow root's descendant has focus
    55FAIL :focus applies to host with delegatesFocus=true when slotted element has focus assert_true: host matches :focus expected true got false
    6 FAIL :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused assert_true: host of nested shadow tree matches focus expected true got false
    7 FAIL :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused assert_true: host of nested shadow tree matches focus expected true got false
    8 FAIL :focus applies to host with delegatesFocus=false when the shadow root's descendant has focus assert_true: host matches :focus expected true got false
     6PASS :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=true is focused
     7PASS :focus applies to host with delegatesFocus=true when an element in a nested shadow tree with delegatesFocus=false is focused
     8PASS :focus applies to host with delegatesFocus=false when the shadow root's descendant has focus
    99FAIL :focus applies to host with delegatesFocus=false when slotted element has focus assert_true: host matches :focus expected true got false
    10 FAIL :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused assert_true: host of nested shadow tree matches focus expected true got false
    11 FAIL :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused assert_true: host of nested shadow tree matches focus expected true got false
     10PASS :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=true is focused
     11PASS :focus applies to host with delegatesFocus=false when an element in a nested shadow tree with delegatesFocus=false is focused
    1212
  • trunk/Source/WebCore/ChangeLog

    r250787 r250788  
     12019-10-07  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        focus pseudo class should match a shadow host whose shadow tree contains the focused element
     4        https://bugs.webkit.org/show_bug.cgi?id=202432
     5
     6        Reviewed by Antti Koivisto.
     7
     8        Note that focus pseudo class does not match a shadow host when its shadow tree contains a slot element
     9        with a focused element or its ancestor assigned since such a shadow host has the actual focused element
     10        in the same tree as the shadow host. (e.g. the focused element can be a direct child of the host).
     11
     12        In order to preserve the behavior of focus ring, which should be only drawn on the currently focused
     13        element and not any shadow host which contains such an element, this patch introduces a new pseudo class,
     14        -webkit-direct-focus, which is only available in the user agent stylesheet. Putting :host(:focus) rule
     15        isn't sufficient because style rules inside shadow trees always has a lower precendence than rules
     16        outside the shadow tree (the tree of its shadow host).
     17
     18        [1] Also see https://github.com/whatwg/html/pull/4731
     19
     20        Tests: fast/shadow-dom/direct-focus-pseudo-does-not-match-in-author-stylesheet.html
     21               fast/shadow-dom/focus-pseudo-matches-on-shadow-host.html
     22               fast/shadow-dom/focus-pseudo-on-shadow-host-1.html
     23               fast/shadow-dom/focus-pseudo-on-shadow-host-2.html
     24               fast/shadow-dom/focus-pseudo-on-shadow-host-3.html
     25
     26        * css/CSSSelector.cpp:
     27        (WebCore::CSSSelector::selectorText const): Added the support for -webkit-direct-focus.
     28        * css/CSSSelector.h:
     29        * css/RuleSet.cpp:
     30        (WebCore::RuleSet::addRule): Ditto.
     31        * css/SelectorChecker.cpp:
     32        (WebCore::SelectorChecker::checkOne const):: Ditto.
     33        (WebCore::doesShadowTreeContainFocusedElement):: Ditto.
     34        (WebCore::SelectorChecker::matchesFocusPseudoClass): Implemented the new behavior.
     35        (WebCore::SelectorChecker::matchesDirectFocusPseudoClass): Added. Implements the old behavior for
     36        the focus ring via -webkit-direct-focus pseudo class.
     37        * css/SelectorChecker.h:
     38        * css/SelectorPseudoClassAndCompatibilityElementMap.in: Added -webkit-direct-focus.
     39        * css/html.css: Use -webkit-direct-focus pseudo class to preserve the existing behavior of focus ring.
     40        * css/parser/CSSSelectorParser.cpp:
     41        (WebCore::CSSSelectorParser::consumePseudo): Ignore -webkit-direct-focus in author and user stylesheets.
     42        * cssjit/SelectorCompiler.cpp:
     43        (WebCore::SelectorCompiler::addPseudoClassType): Added the support for -webkit-direct-focus.
     44        * dom/Element.cpp:
     45        (WebCore::Element::setFocus): Invoke setContainsFocusedElement on each shadow ancestor root of
     46        the newly focused element. Note that we can't use :focus-within pseudo class since that would also match
     47        the host of a shadow root which contains a slotted focused element, causing both the shadow host and
     48        the slotted element to match :focus pseudo class in the host's tree.
     49        * dom/ShadowRoot.h:
     50
    1512019-10-07  Rob Buis  <rbuis@igalia.com>
    252
  • trunk/Source/WebCore/css/CSSSelector.cpp

    r250643 r250788  
    439439                str.appendLiteral(":-webkit-autofill-strong-password-viewable");
    440440                break;
     441            case CSSSelector::PseudoClassDirectFocus:
     442                str.appendLiteral(":-webkit-direct-focus");
     443                break;
    441444            case CSSSelector::PseudoClassDrag:
    442445                str.appendLiteral(":-webkit-drag");
  • trunk/Source/WebCore/css/CSSSelector.h

    r250701 r250788  
    111111            PseudoClassAutofillStrongPasswordViewable,
    112112            PseudoClassHover,
     113            PseudoClassDirectFocus,
    113114            PseudoClassDrag,
    114115            PseudoClassFocus,
  • trunk/Source/WebCore/css/RuleSet.cpp

    r250628 r250788  
    279279                linkSelector = selector;
    280280                break;
     281            case CSSSelector::PseudoClassDirectFocus:
    281282            case CSSSelector::PseudoClassFocus:
    282283                focusSelector = selector;
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r250712 r250788  
    986986                return false;
    987987            return element.isLink() && context.visitedMatchType == VisitedMatchType::Enabled;
     988        case CSSSelector::PseudoClassDirectFocus:
     989            return matchesDirectFocusPseudoClass(element);
    988990        case CSSSelector::PseudoClassDrag:
    989991            addStyleRelation(checkingContext, element, Style::Relation::AffectedByDrag);
     
    12831285}
    12841286
     1287static bool doesShadowTreeContainFocusedElement(const Element& element)
     1288{
     1289    auto* shadowRoot = element.shadowRoot();
     1290    return shadowRoot && shadowRoot->containsFocusedElement();
     1291}
     1292
    12851293bool SelectorChecker::matchesFocusPseudoClass(const Element& element)
    12861294{
    12871295    if (InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocus))
    12881296        return true;
     1297
     1298    return (element.focused() || doesShadowTreeContainFocusedElement(element)) && isFrameFocused(element);
     1299}
     1300
     1301// This needs to match a subset of elements matchesFocusPseudoClass match since direct focus is treated
     1302// as a part of focus pseudo class selectors in ElementRuleCollector::collectMatchingRules.
     1303bool SelectorChecker::matchesDirectFocusPseudoClass(const Element& element)
     1304{
     1305    if (InspectorInstrumentation::forcePseudoState(element, CSSSelector::PseudoClassFocus))
     1306        return true;
     1307
    12891308    return element.focused() && isFrameFocused(element);
    12901309}
  • trunk/Source/WebCore/css/SelectorChecker.h

    r250712 r250788  
    9898    static bool isCommonPseudoClassSelector(const CSSSelector*);
    9999    static bool matchesFocusPseudoClass(const Element&);
     100    static bool matchesDirectFocusPseudoClass(const Element&);
    100101    static bool attributeSelectorMatches(const Element&, const QualifiedName&, const AtomString& attributeValue, const CSSSelector&);
    101102
  • trunk/Source/WebCore/css/SelectorPseudoClassAndCompatibilityElementMap.in

    r248373 r250788  
    55-webkit-autofill-strong-password
    66-webkit-autofill-strong-password-viewable
     7-webkit-direct-focus
    78-webkit-drag
    89-webkit-full-page-media
  • trunk/Source/WebCore/css/html.css

    r248373 r250788  
    11661166/* states */
    11671167
    1168 :focus {
     1168:-webkit-direct-focus {
    11691169#if defined(WTF_PLATFORM_IOS_FAMILY) && WTF_PLATFORM_IOS_FAMILY
    11701170    outline: auto 3px -webkit-focus-ring-color;
  • trunk/Source/WebCore/css/parser/CSSSelectorParser.cpp

    r250701 r250788  
    495495    if (colons == 1) {
    496496        selector = CSSParserSelector::parsePseudoClassSelector(token.value());
     497        if (!selector)
     498            return nullptr;
     499        if (selector->match() == CSSSelector::PseudoClass) {
     500            if (m_context.mode != UASheetMode && selector->pseudoClassType() == CSSSelector::PseudoClassDirectFocus)
     501                return nullptr;
    497502#if ENABLE(ATTACHMENT_ELEMENT)
    498         if (!m_context.attachmentEnabled && selector && selector->match() == CSSSelector::PseudoClass && selector->pseudoClassType() == CSSSelector::PseudoClassHasAttachment)
    499             return nullptr;
     503            if (!m_context.attachmentEnabled && selector->pseudoClassType() == CSSSelector::PseudoClassHasAttachment)
     504                return nullptr;
    500505#endif
     506        }
    501507    } else {
    502508        selector = CSSParserSelector::parsePseudoElementSelector(token.value());
  • trunk/Source/WebCore/cssjit/SelectorCompiler.cpp

    r250643 r250788  
    559559        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<CSSOperationPtrTag>(isDefinedElement));
    560560        return FunctionType::SimpleSelectorChecker;
     561    case CSSSelector::PseudoClassDirectFocus:
     562        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<CSSOperationPtrTag>(SelectorChecker::matchesDirectFocusPseudoClass));
     563        return FunctionType::SimpleSelectorChecker;
    561564    case CSSSelector::PseudoClassFocus:
    562565        fragment.unoptimizedPseudoClasses.append(JSC::FunctionPtr<CSSOperationPtrTag>(SelectorChecker::matchesFocusPseudoClass));
  • trunk/Source/WebCore/dom/Element.cpp

    r250770 r250788  
    678678    invalidateStyleForSubtree();
    679679
     680    // Shadow host with a slot that contain focused element is not considered focused.
     681    for (auto* root = containingShadowRoot(); root; root = root->host()->containingShadowRoot()) {
     682        root->setContainsFocusedElement(flag);
     683        root->host()->invalidateStyle();
     684    }
     685
    680686    for (Element* element = this; element; element = element->parentElementInComposedTree())
    681687        element->setHasFocusWithin(flag);
  • trunk/Source/WebCore/dom/ShadowRoot.h

    r250712 r250788  
    6262    void setResetStyleInheritance(bool);
    6363
     64    bool containsFocusedElement() const { return m_containsFocusedElement; }
     65    void setContainsFocusedElement(bool flag) { m_containsFocusedElement = flag; }
     66
    6467    Element* host() const { return m_host; }
    6568    void setHost(Element* host) { m_host = host; }
     
    114117    bool m_resetStyleInheritance { false };
    115118    bool m_hasBegunDeletingDetachedChildren { false };
     119    bool m_containsFocusedElement { false };
    116120    ShadowRootMode m_type { ShadowRootMode::UserAgent };
    117121
Note: See TracChangeset for help on using the changeset viewer.