Changeset 199268 in webkit


Ignore:
Timestamp:
Apr 9, 2016 12:38:32 AM (8 years ago)
Author:
Antti Koivisto
Message:

Implement functional :host() pseudo class
https://bugs.webkit.org/show_bug.cgi?id=156397
<rdar://problem/25621445>

Reviewed by Darin Adler.

Source/WebCore:

We already support :host. Add functional syntax too.

  • css/CSSGrammar.y.in:

Parse functional :host().

  • css/CSSParser.cpp:

(WebCore::CSSParser::detectFunctionTypeToken):

  • css/CSSParserValues.cpp:

(WebCore::CSSParserSelector::parsePseudoClassHostFunctionSelector):

  • css/CSSParserValues.h:
  • css/ElementRuleCollector.cpp:

(WebCore::ElementRuleCollector::matchedRuleList):
(WebCore::ElementRuleCollector::addMatchedRule):

Factor some shared code here.

(WebCore::ElementRuleCollector::matchHostPseudoClassRules):

Instead of using the generic paths use a :host specific code path for matching.
This makes it easier to avoid :host matching when it shouldn't.

(WebCore::ElementRuleCollector::collectMatchingRulesForList):

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

(WebCore::computeMatchBasedOnRuleHash):

:host is always handled by the special matching path.

  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::match):
(WebCore::SelectorChecker::matchHostPseudoClass):

Add a function specifically for checking :host. In always fails on the normal code paths.
Check the argument selector if provided.

(WebCore::hasScrollbarPseudoElement):

  • css/SelectorChecker.h:

LayoutTests:

Enable, fix and expand the test.

  • fast/shadow-dom/css-scoping-shadow-host-functional-rule.html:
  • platform/mac/TestExpectations:
Location:
trunk
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r199265 r199268  
     12016-04-09  Antti Koivisto  <antti@apple.com>
     2
     3        Implement functional :host() pseudo class
     4        https://bugs.webkit.org/show_bug.cgi?id=156397
     5        <rdar://problem/25621445>
     6
     7        Reviewed by Darin Adler.
     8
     9        Enable, fix and expand the test.
     10
     11        * fast/shadow-dom/css-scoping-shadow-host-functional-rule.html:
     12        * platform/mac/TestExpectations:
     13
    1142016-04-07  Darin Adler  <darin@apple.com>
    215
  • trunk/LayoutTests/fast/shadow-dom/css-scoping-shadow-host-functional-rule.html

    r190098 r199268  
    99<body>
    1010    <style>
    11         my-host, good-host, other-host, other-good-host {
     11        host1, host2, host3, host4, host5 {
    1212            display: block;
    1313            width: 100px;
    14             height: 50px;
     14            height: 20px;
    1515            background: red;
    1616        }
    17         good-host, other-good-host {
     17        host3, host4, host5 {
    1818            background: green;
    1919        }
    2020    </style>
    21     <p>Test passes if you see a single 100px by 100px green box below.</p> 
    22     <my-host>
     21    <p>Test passes if you see a single 100px by 100px green box below.</p>
     22    <host1>
    2323        <div>FAIL</div>
    24     </my-host>
    25     <div class="container">
    26         <good-host>
    27             <div>FAIL</div>
    28         </good-host>
     24    </host1>
     25    <host2 id="bar" class="foo" name="baz">
     26        <div>FAIL</div>
     27    </host2>
     28    <div>
     29        <host3>
     30            FAIL
     31        </host3>
    2932    </div>
    30     <other-host id="bar" class="foo" name="baz">
     33    <host4>
     34        <div class="child">FAIL</div>
     35    </host4>
     36    <host5>
    3137        <div>FAIL</div>
    32     </other-host>
    33     <other-good-host>
    34         <div class="child">FAIL</div>
    35     </other-good-host>
     38    </host5>
    3639    <script>
    3740
    3841        try {
    39             var shadowHost = document.querySelector('other-host');
     42            var shadowHost = document.querySelector('host1');
    4043            shadowRoot = shadowHost.attachShadow({mode: 'open'});
    41             shadowRoot.innerHTML = '<style> :host(other-host.foo#bar[name=baz]) { background: green; } </style>';
     44            shadowRoot.innerHTML = '<style> :host(host1) { background: green !important; } </style>';
    4245
    43             shadowHost = document.querySelector('other-good-host');
     46            shadowHost = document.querySelector('host2');
    4447            shadowRoot = shadowHost.attachShadow({mode: 'open'});
    45             shadowRoot.innerHTML = '<style> :host(.child) { background: red; } </style>';
     48            shadowRoot.innerHTML = '<style> :host(host2.foo#bar[name=baz]) { background: green !important; } </style>';
     49
     50            shadowHost = document.querySelector('host3');
     51            shadowRoot = shadowHost.attachShadow({mode: 'open'});
     52            shadowRoot.innerHTML = '<style> :host(div host3) { background: red !important; } </style>';
     53
     54            shadowHost = document.querySelector('host4');
     55            shadowRoot = shadowHost.attachShadow({mode: 'open'});
     56            shadowRoot.innerHTML = '<style> :host(.child) { background: red !important; } </style>';
     57
     58            shadowHost = document.querySelector('host5');
     59            shadowRoot = shadowHost.attachShadow({mode: 'open'});
     60            shadowRoot.innerHTML = '<style> :host(host1) { background: red !important; } </style>';
    4661        } catch (exception) {
    4762            document.body.appendChild(document.createTextNode(exception));
  • trunk/LayoutTests/platform/mac/TestExpectations

    r199206 r199268  
    12251225
    12261226webkit.org/b/148695 fast/shadow-dom [ Pass ]
    1227 webkit.org/b/149440 fast/shadow-dom/css-scoping-shadow-host-functional-rule.html [ ImageOnlyFailure ]
    12281227
    12291228# Touch events is not enabled on Mac
  • trunk/Source/WebCore/ChangeLog

    r199265 r199268  
     12016-04-09  Antti Koivisto  <antti@apple.com>
     2
     3        Implement functional :host() pseudo class
     4        https://bugs.webkit.org/show_bug.cgi?id=156397
     5        <rdar://problem/25621445>
     6
     7        Reviewed by Darin Adler.
     8
     9        We already support :host. Add functional syntax too.
     10
     11        * css/CSSGrammar.y.in:
     12
     13            Parse functional :host().
     14
     15        * css/CSSParser.cpp:
     16        (WebCore::CSSParser::detectFunctionTypeToken):
     17        * css/CSSParserValues.cpp:
     18        (WebCore::CSSParserSelector::parsePseudoClassHostFunctionSelector):
     19        * css/CSSParserValues.h:
     20        * css/ElementRuleCollector.cpp:
     21        (WebCore::ElementRuleCollector::matchedRuleList):
     22        (WebCore::ElementRuleCollector::addMatchedRule):
     23
     24            Factor some shared code here.
     25
     26        (WebCore::ElementRuleCollector::matchHostPseudoClassRules):
     27
     28            Instead of using the generic paths use a :host specific code path for matching.
     29            This makes it easier to avoid :host matching when it shouldn't.
     30
     31        (WebCore::ElementRuleCollector::collectMatchingRulesForList):
     32        * css/ElementRuleCollector.h:
     33        * css/RuleSet.cpp:
     34        (WebCore::computeMatchBasedOnRuleHash):
     35
     36            :host is always handled by the special matching path.
     37
     38        * css/SelectorChecker.cpp:
     39        (WebCore::SelectorChecker::match):
     40        (WebCore::SelectorChecker::matchHostPseudoClass):
     41
     42            Add a function specifically for checking :host. In always fails on the normal code paths.
     43            Check the argument selector if provided.
     44
     45        (WebCore::hasScrollbarPseudoElement):
     46        * css/SelectorChecker.h:
     47
    1482016-04-07  Darin Adler  <darin@apple.com>
    249
  • trunk/Source/WebCore/css/CSSGrammar.y.in

    r197165 r199268  
    369369
    370370%token <string> SLOTTEDFUNCTION
     371%token <string> HOSTFUNCTION
    371372
    372373#endif
     
    13671368    | ':' ':' SLOTTEDFUNCTION maybe_space compound_selector maybe_space ')' {
    13681369        $$ = CSSParserSelector::parsePseudoElementSlottedFunctionSelector($3, $5);
     1370    }
     1371    | ':' HOSTFUNCTION maybe_space compound_selector maybe_space ')' {
     1372        $$ = CSSParserSelector::parsePseudoClassHostFunctionSelector($2, $4);
    13691373    }
    13701374#endif
  • trunk/Source/WebCore/css/CSSParser.cpp

    r199154 r199268  
    1189811898        }
    1189911899#endif
     11900#if ENABLE(SHADOW_DOM)
     11901        if (isEqualToCSSIdentifier(name, "host")) {
     11902            m_token = HOSTFUNCTION;
     11903            return true;
     11904        }
     11905#endif
    1190011906        return false;
    1190111907
  • trunk/Source/WebCore/css/CSSParserValues.cpp

    r197165 r199268  
    256256    return selector.release();
    257257}
     258
     259CSSParserSelector* CSSParserSelector::parsePseudoClassHostFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector* parsedSelector)
     260{
     261    ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "host(");
     262
     263    if (!parsedSelector)
     264        return nullptr;
     265
     266    std::unique_ptr<CSSParserSelector> ownedParsedSelector(parsedSelector);
     267
     268    for (auto* component = parsedSelector; component; component = component->tagHistory()) {
     269        if (component->matchesPseudoElement())
     270            return nullptr;
     271    }
     272
     273    auto selectorVector = std::make_unique<Vector<std::unique_ptr<CSSParserSelector>>>();
     274    selectorVector->append(WTFMove(ownedParsedSelector));
     275
     276    auto selector = std::make_unique<CSSParserSelector>();
     277    selector->m_selector->setMatch(CSSSelector::PseudoClass);
     278    selector->m_selector->setPseudoClassType(CSSSelector::PseudoClassHost);
     279    selector->adoptSelectorVector(*selectorVector);
     280    return selector.release();
     281}
    258282#endif
    259283
  • trunk/Source/WebCore/css/CSSParserValues.h

    r197165 r199268  
    207207#if ENABLE(SHADOW_DOM)
    208208    static CSSParserSelector* parsePseudoElementSlottedFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector*);
     209    static CSSParserSelector* parsePseudoClassHostFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector*);
    209210#endif
    210211    static CSSParserSelector* parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString);
  • trunk/Source/WebCore/css/ElementRuleCollector.cpp

    r197779 r199268  
    108108}
    109109
    110 inline void ElementRuleCollector::addMatchedRule(const MatchedRule& matchedRule)
    111 {
    112     m_matchedRules.append(matchedRule);
     110inline void ElementRuleCollector::addMatchedRule(const RuleData& ruleData, unsigned specificity, StyleResolver::RuleRange& ruleRange)
     111{
     112    // Update our first/last rule indices in the matched rules array.
     113    ++ruleRange.lastRuleIndex;
     114    if (ruleRange.firstRuleIndex == -1)
     115        ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
     116
     117    m_matchedRules.append({ &ruleData, specificity });
    113118}
    114119
     
    233238    m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
    234239
     240    SelectorChecker::CheckingContext context(m_mode);
     241    SelectorChecker selectorChecker(m_element.document());
     242
    235243    auto ruleRange = m_result.ranges.authorRuleRange();
    236     MatchRequest matchRequest(&shadowAuthorStyle, includeEmptyRules);
    237     collectMatchingRulesForList(&shadowHostRules, matchRequest, ruleRange);
     244    for (auto& ruleData : shadowHostRules) {
     245        if (ruleData.rule()->properties().isEmpty() && !includeEmptyRules)
     246            continue;
     247        auto& selector = *ruleData.selector();
     248        unsigned specificity = 0;
     249        if (!selectorChecker.matchHostPseudoClass(selector, m_element, context, specificity))
     250            continue;
     251        addMatchedRule(ruleData, specificity, ruleRange);
     252    }
    238253
    239254    // We just sort the host rules before other author rules. This matches the current vague spec language
     
    487502
    488503        unsigned specificity;
    489         if (ruleMatches(ruleData, specificity)) {
    490             // Update our first/last rule indices in the matched rules array.
    491             ++ruleRange.lastRuleIndex;
    492             if (ruleRange.firstRuleIndex == -1)
    493                 ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
    494 
    495             // Add this rule to our list of matched rules.
    496             addMatchedRule({&ruleData, specificity});
    497         }
     504        if (ruleMatches(ruleData, specificity))
     505            addMatchedRule(ruleData, specificity, ruleRange);
    498506    }
    499507}
  • trunk/Source/WebCore/css/ElementRuleCollector.h

    r197779 r199268  
    9090    void sortAndTransferMatchedRules();
    9191
    92     void addMatchedRule(const MatchedRule&);
     92    void addMatchedRule(const RuleData&, unsigned specificity, StyleResolver::RuleRange&);
    9393
    9494    const Element& m_element;
  • trunk/Source/WebCore/css/RuleSet.cpp

    r197165 r199268  
    7171    if (SelectorChecker::isCommonPseudoClassSelector(&selector))
    7272        return MatchBasedOnRuleHash::ClassB;
    73 #if ENABLE(SHADOW_DOM)
    74     if (selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost)
    75         return MatchBasedOnRuleHash::ClassB;
    76 #endif
    7773    if (selector.match() == CSSSelector::Id)
    7874        return MatchBasedOnRuleHash::ClassA;
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r197952 r199268  
    196196        // not cause a failure.
    197197        return checkingContext.resolvingMode == Mode::CollectingRulesIgnoringVirtualPseudoElements || result.matchType == MatchType::Element;
     198    }
     199    return true;
     200}
     201
     202
     203bool SelectorChecker::matchHostPseudoClass(const CSSSelector& selector, const Element& element, CheckingContext& checkingContext, unsigned& specificity) const
     204{
     205    ASSERT(element.shadowRoot());
     206    ASSERT(selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost);
     207    ASSERT(checkingContext.resolvingMode != SelectorChecker::Mode::QueryingRules);
     208    // :host doesn't combine with any other selectors.
     209    if (selector.tagHistory())
     210        return false;
     211    specificity = selector.simpleSelectorSpecificity();
     212    if (auto* selectorList = selector.selectorList()) {
     213        LocalContext context(selector, element, VisitedMatchType::Enabled, NOPSEUDO);
     214        unsigned ignoredSpecificity;
     215        if (!matchSelectorList(checkingContext, context, element, *selectorList, ignoredSpecificity))
     216            return false;
    198217    }
    199218    return true;
  • trunk/Source/WebCore/css/SelectorChecker.h

    r197764 r199268  
    9696    bool match(const CSSSelector&, const Element&, CheckingContext&, unsigned& specificity) const;
    9797
     98    bool matchHostPseudoClass(const CSSSelector&, const Element&, CheckingContext&, unsigned& specificity) const;
     99
    98100    static bool isCommonPseudoClassSelector(const CSSSelector*);
    99101    static bool matchesFocusPseudoClass(const Element&);
Note: See TracChangeset for help on using the changeset viewer.