Changeset 197165 in webkit


Ignore:
Timestamp:
Feb 26, 2016 6:57:01 AM (8 years ago)
Author:
Antti Koivisto
Message:

Implement ::slotted pseudo element
https://bugs.webkit.org/show_bug.cgi?id=149441
<rdar://problem/22731987>

Reviewed by Andreas Kling.

Source/WebCore:

Based on latest in https://github.com/w3c/webcomponents/issues/331

  • css/CSSGrammar.y.in:

Parse ::slotted.

  • css/CSSParser.cpp:

(WebCore::CSSParser::detectFunctionTypeToken):

  • css/CSSParserValues.cpp:

(WebCore::CSSParserSelector::parsePseudoElementCueFunctionSelector):
(WebCore::CSSParserSelector::parsePseudoElementSlottedFunctionSelector):

Tokenize ::slotted.

(WebCore::CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector):

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

(WebCore::CSSSelector::pseudoId):

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

(WebCore::ElementRuleCollector::matchAuthorRules):
(WebCore::ElementRuleCollector::matchHostPseudoClassRules):
(WebCore::ElementRuleCollector::matchSlottedPseudoElementRules):

Match ::slotted selector.

(WebCore::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot):

Collect ::slotted rules that may apply to an element in a slot.

(WebCore::ElementRuleCollector::matchUserRules):
(WebCore::ElementRuleCollector::matchUARules):
(WebCore::findSlottedPseudoElementSelector):
(WebCore::ElementRuleCollector::ruleMatches):

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

(WebCore::RuleSet::addRule):

Collect ::slotted rules.

(WebCore::RuleSet::shrinkToFit):

  • css/RuleSet.h:

(WebCore::RuleSet::hostPseudoClassRules):
(WebCore::RuleSet::slottedPseudoElementRules):
(WebCore::RuleSet::focusPseudoClassRules):
(WebCore::RuleSet::universalRules):

  • css/SelectorChecker.cpp:

(WebCore::SelectorChecker::checkOne):

  • style/StyleSharingResolver.cpp:

(WebCore::Style::SharingResolver::resolve):

Disable style sharing for children of shadow host. They may be affected by the shadow tree style
which is not considered in style sharing checks.

LayoutTests:

  • fast/shadow-dom/css-scoping-shadow-slotted-rule.html:

Enable the test, fix it and update it to the current spec.

  • fast/shadow-dom/slotted-pseudo-element-css-text-expected.txt: Added.
  • fast/shadow-dom/slotted-pseudo-element-css-text.html: Added.

Add parsing/cssText test based on a Blink test.
There are a few failures due to * not roundtripping and the parser being too lenient with pseudo elements.

  • platform/mac/TestExpectations:
Location:
trunk
Files:
2 added
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r197162 r197165  
     12016-02-26  Antti Koivisto  <antti@apple.com>
     2
     3        Implement ::slotted pseudo element
     4        https://bugs.webkit.org/show_bug.cgi?id=149441
     5        <rdar://problem/22731987>
     6
     7        Reviewed by Andreas Kling.
     8
     9        * fast/shadow-dom/css-scoping-shadow-slotted-rule.html:
     10
     11            Enable the test, fix it and update it to the current spec.
     12
     13        * fast/shadow-dom/slotted-pseudo-element-css-text-expected.txt: Added.
     14        * fast/shadow-dom/slotted-pseudo-element-css-text.html: Added.
     15
     16            Add parsing/cssText test based on a Blink test.
     17            There are a few failures due to * not roundtripping and the parser being too lenient with pseudo elements.
     18
     19        * platform/mac/TestExpectations:
     20
    1212016-02-26  Youenn Fablet  <youenn.fablet@crf.canon.fr>
    222
  • trunk/LayoutTests/fast/shadow-dom/css-scoping-shadow-slotted-rule.html

    r190098 r197165  
    22<html>
    33<head>
    4     <title>CSS Scoping - :slotted pesudo element must allow selecting elements assigned to a slot element</title>
     4    <title>CSS Scoping - :slotted pseudo element must allow selecting elements assigned to a slot element</title>
    55    <link rel="author" title="Ryosuke Niwa" href="mailto:rniwa@webkit.org"/>
    66    <link rel="help" href="http://www.w3.org/TR/css-scoping-1/#selectors-data-model">
     
    1313            width: 100px;
    1414            height: 100px;
    15             background: red;
     15            color: red;
     16            background: green;
    1617        }
    1718        my-host > div, nested-host {
     
    2425    <my-host>
    2526        <div class="green">FAIL1</div>
    26         <div><span>FAIL2</span></div>
     27        <myelem><span>FAIL2</span></myelem>
    2728        <nested-host>
    2829            <span>FAIL3</span>
     
    3738            var shadowHost = document.querySelector('my-host');
    3839            shadowRoot = shadowHost.attachShadow({mode: 'open'});
    39             shadowRoot.innerHTML = '<slot></slot><style> ::slotted > .green, ::slotted span { color:green; } </style>';
     40            shadowRoot.innerHTML = '<slot></slot><style> ::slotted(.green), ::slotted(myelem) { color:green; } </style>';
    4041
    4142            shadowHost = document.querySelector('nested-host');
    4243            shadowRoot = shadowHost.attachShadow({mode: 'open'});
    43             shadowRoot.innerHTML = '<slot></slot>';
     44            shadowRoot.innerHTML = '<style> .mydiv ::slotted(*) { color:green; } </style><div class=mydiv><slot></slot></div>';
    4445
    4546            shadowHost = document.querySelector('another-host');
    4647            shadowRoot = shadowHost.attachShadow({mode: 'open'});
    47             shadowRoot.innerHTML = '<style> ::slotted { color:green; } </style><slot></slot>';
     48            shadowRoot.innerHTML = '<style> ::slotted(*) { color:green; } </style><slot></slot>';
    4849        } catch (exception) {
    4950            document.body.appendChild(document.createTextNode(exception));
  • trunk/LayoutTests/platform/mac/TestExpectations

    r197162 r197165  
    12501250webkit.org/b/148695 fast/shadow-dom [ Pass ]
    12511251webkit.org/b/149440 fast/shadow-dom/css-scoping-shadow-host-functional-rule.html [ ImageOnlyFailure ]
    1252 webkit.org/b/149441 fast/shadow-dom/css-scoping-shadow-slotted-rule.html [ ImageOnlyFailure ]
    12531252webkit.org/b/149441 fast/shadow-dom/css-scoping-shadow-slot-display-override.html [ ImageOnlyFailure ]
    12541253
  • trunk/Source/WebCore/ChangeLog

    r197160 r197165  
     12016-02-25  Antti Koivisto  <antti@apple.com>
     2
     3        Implement ::slotted pseudo element
     4        https://bugs.webkit.org/show_bug.cgi?id=149441
     5        <rdar://problem/22731987>
     6
     7        Reviewed by Andreas Kling.
     8
     9        Based on latest in https://github.com/w3c/webcomponents/issues/331
     10
     11        * css/CSSGrammar.y.in:
     12
     13            Parse ::slotted.
     14
     15        * css/CSSParser.cpp:
     16        (WebCore::CSSParser::detectFunctionTypeToken):
     17        * css/CSSParserValues.cpp:
     18        (WebCore::CSSParserSelector::parsePseudoElementCueFunctionSelector):
     19        (WebCore::CSSParserSelector::parsePseudoElementSlottedFunctionSelector):
     20
     21            Tokenize ::slotted.
     22
     23        (WebCore::CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector):
     24        * css/CSSParserValues.h:
     25        * css/CSSSelector.cpp:
     26        (WebCore::CSSSelector::pseudoId):
     27        * css/CSSSelector.h:
     28        * css/ElementRuleCollector.cpp:
     29        (WebCore::ElementRuleCollector::matchAuthorRules):
     30        (WebCore::ElementRuleCollector::matchHostPseudoClassRules):
     31        (WebCore::ElementRuleCollector::matchSlottedPseudoElementRules):
     32
     33            Match ::slotted selector.
     34
     35        (WebCore::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot):
     36
     37            Collect ::slotted rules that may apply to an element in a slot.
     38
     39        (WebCore::ElementRuleCollector::matchUserRules):
     40        (WebCore::ElementRuleCollector::matchUARules):
     41        (WebCore::findSlottedPseudoElementSelector):
     42        (WebCore::ElementRuleCollector::ruleMatches):
     43        * css/ElementRuleCollector.h:
     44        * css/RuleSet.cpp:
     45        (WebCore::RuleSet::addRule):
     46
     47            Collect ::slotted rules.
     48
     49        (WebCore::RuleSet::shrinkToFit):
     50        * css/RuleSet.h:
     51        (WebCore::RuleSet::hostPseudoClassRules):
     52        (WebCore::RuleSet::slottedPseudoElementRules):
     53        (WebCore::RuleSet::focusPseudoClassRules):
     54        (WebCore::RuleSet::universalRules):
     55        * css/SelectorChecker.cpp:
     56        (WebCore::SelectorChecker::checkOne):
     57        * style/StyleSharingResolver.cpp:
     58        (WebCore::Style::SharingResolver::resolve):
     59
     60            Disable style sharing for children of shadow host. They may be affected by the shadow tree style
     61            which is not considered in style sharing checks.
     62
    1632016-02-25  Myles C. Maxfield  <mmaxfield@apple.com>
    264
  • trunk/Source/WebCore/css/CSSGrammar.y.in

    r195951 r197165  
    366366#endif
    367367
     368#if ENABLE_SHADOW_DOM
     369
     370%token <string> SLOTTEDFUNCTION
     371
     372#endif
     373
    368374%%
    369375
     
    13561362    | ':' ':' CUEFUNCTION maybe_space simple_selector_list maybe_space ')' {
    13571363        $$ = CSSParserSelector::parsePseudoElementCueFunctionSelector($3, $5);
     1364    }
     1365#endif
     1366#if ENABLE_SHADOW_DOM
     1367    | ':' ':' SLOTTEDFUNCTION maybe_space compound_selector maybe_space ')' {
     1368        $$ = CSSParserSelector::parsePseudoElementSlottedFunctionSelector($3, $5);
    13581369    }
    13591370#endif
  • trunk/Source/WebCore/css/CSSParser.cpp

    r197022 r197165  
    1189511895            return true;
    1189611896        }
     11897#if ENABLE(SHADOW_DOM)
     11898        if (isEqualToCSSIdentifier(name, "slotted")) {
     11899            m_token = SLOTTEDFUNCTION;
     11900            return true;
     11901        }
     11902#endif
    1189711903        return false;
    1189811904
  • trunk/Source/WebCore/css/CSSParserValues.cpp

    r195951 r197165  
    232232#endif
    233233
     234#if ENABLE(SHADOW_DOM)
     235CSSParserSelector* CSSParserSelector::parsePseudoElementSlottedFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector* parsedSelector)
     236{
     237    ASSERT_UNUSED(functionIdentifier, String(functionIdentifier) == "slotted(");
     238
     239    if (!parsedSelector)
     240        return nullptr;
     241
     242    std::unique_ptr<CSSParserSelector> ownedParsedSelector(parsedSelector);
     243
     244    for (auto* component = parsedSelector; component; component = component->tagHistory()) {
     245        if (component->matchesPseudoElement())
     246            return nullptr;
     247    }
     248
     249    auto selectorVector = std::make_unique<Vector<std::unique_ptr<CSSParserSelector>>>();
     250    selectorVector->append(WTFMove(ownedParsedSelector));
     251
     252    auto selector = std::make_unique<CSSParserSelector>();
     253    selector->m_selector->setMatch(CSSSelector::PseudoElement);
     254    selector->m_selector->setPseudoElementType(CSSSelector::PseudoElementSlotted);
     255    selector->adoptSelectorVector(*selectorVector);
     256    return selector.release();
     257}
     258#endif
     259
    234260CSSParserSelector* CSSParserSelector::parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString)
    235261{
  • trunk/Source/WebCore/css/CSSParserValues.h

    r195951 r197165  
    204204    static CSSParserSelector* parsePagePseudoSelector(const CSSParserString& pseudoTypeString);
    205205    static CSSParserSelector* parsePseudoElementSelector(CSSParserString& pseudoTypeString);
    206     static CSSParserSelector* parsePseudoElementCueFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>* selectorVector);
     206    static CSSParserSelector* parsePseudoElementCueFunctionSelector(const CSSParserString& functionIdentifier, Vector<std::unique_ptr<CSSParserSelector>>*);
     207#if ENABLE(SHADOW_DOM)
     208    static CSSParserSelector* parsePseudoElementSlottedFunctionSelector(const CSSParserString& functionIdentifier, CSSParserSelector*);
     209#endif
    207210    static CSSParserSelector* parsePseudoClassAndCompatibilityElementSelector(CSSParserString& pseudoTypeString);
    208211
  • trunk/Source/WebCore/css/CSSSelector.cpp

    r195951 r197165  
    300300    case PseudoElementCue:
    301301#endif
     302#if ENABLE(SHADOW_DOM)
     303    case PseudoElementSlotted:
     304#endif
    302305    case PseudoElementUnknown:
    303306    case PseudoElementUserAgentCustom:
     
    645648            }
    646649        } else if (cs->match() == CSSSelector::PseudoElement) {
    647             str.appendLiteral("::");
    648             str.append(cs->value());
     650            switch (cs->pseudoElementType()) {
     651#if ENABLE(SHADOW_DOM)
     652            case CSSSelector::PseudoElementSlotted:
     653                str.appendLiteral("::slotted(");
     654                cs->selectorList()->buildSelectorsText(str);
     655                str.append(')');
     656                break;
     657#endif
     658            default:
     659                str.appendLiteral("::");
     660                str.append(cs->value());
     661            }
    649662        } else if (cs->isAttributeSelector()) {
    650663            str.append('[');
  • trunk/Source/WebCore/css/CSSSelector.h

    r192758 r197165  
    182182            PseudoElementScrollbarTrackPiece,
    183183            PseudoElementSelection,
     184#if ENABLE(SHADOW_DOM)
     185            PseudoElementSlotted,
     186#endif
    184187            PseudoElementUserAgentCustom,
    185188            PseudoElementWebKitCustom,
  • trunk/Source/WebCore/css/ElementRuleCollector.cpp

    r196383 r197165  
    3737#include "CSSValueKeywords.h"
    3838#include "HTMLElement.h"
     39#include "HTMLSlotElement.h"
    3940#include "InspectorInstrumentation.h"
    4041#include "NodeRenderStyle.h"
     
    207208    if (m_element.shadowRoot())
    208209        matchHostPseudoClassRules(includeEmptyRules);
     210
     211    auto* parent = m_element.parentNode();
     212    if (parent && parent->shadowRoot())
     213        matchSlottedPseudoElementRules(includeEmptyRules);
    209214#endif
    210215
     
    241246    // FIXME: Match the spec when it is finalized.
    242247    sortAndTransferMatchedRules();
     248}
     249
     250void ElementRuleCollector::matchSlottedPseudoElementRules(bool includeEmptyRules)
     251{
     252    auto* hostShadowRoot = m_element.parentNode()->shadowRoot();
     253    ASSERT(hostShadowRoot);
     254    auto* slot = hostShadowRoot->findAssignedSlot(m_element);
     255    if (!slot)
     256        return;
     257    auto* shadowAuthorStyle = hostShadowRoot->styleResolver().ruleSets().authorStyle();
     258    if (!shadowAuthorStyle)
     259        return;
     260    // Find out if there are any ::slotted rules in the shadow tree matching the current slot.
     261    // FIXME: This is really part of the slot style and could be cached when resolving it.
     262    ElementRuleCollector collector(*slot, *shadowAuthorStyle, nullptr);
     263    auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(includeEmptyRules);
     264    if (slottedPseudoElementRules.isEmpty())
     265        return;
     266
     267    clearMatchedRules();
     268    m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
     269
     270    {
     271        // Match in the current scope.
     272        TemporaryChange<bool> change(m_isMatchingSlottedPseudoElements, true);
     273
     274        MatchRequest matchRequest(nullptr, includeEmptyRules);
     275        auto ruleRange = m_result.ranges.authorRuleRange();
     276        collectMatchingRulesForList(&slottedPseudoElementRules, matchRequest, ruleRange);
     277    }
     278
     279    // FIXME: What is the correct order?
     280    sortAndTransferMatchedRules();
     281}
     282
     283RuleSet::RuleDataVector ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules)
     284{
     285    ASSERT(is<HTMLSlotElement>(m_element));
     286
     287    clearMatchedRules();
     288
     289    m_mode = SelectorChecker::Mode::CollectingRules;
     290
     291    // Match global author rules.
     292    MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
     293    StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
     294    collectMatchingRulesForList(&m_authorStyle.slottedPseudoElementRules(), matchRequest, ruleRange);
     295
     296    if (m_matchedRules.isEmpty())
     297        return { };
     298
     299    RuleSet::RuleDataVector ruleDataVector;
     300    ruleDataVector.reserveInitialCapacity(m_matchedRules.size());
     301    for (auto& matchedRule : m_matchedRules)
     302        ruleDataVector.uncheckedAppend(*matchedRule.ruleData);
     303    return ruleDataVector;
    243304}
    244305#endif
     
    284345    sortAndTransferMatchedRules();
    285346}
     347
     348#if ENABLE(SHADOW_DOM)
     349static const CSSSelector* findSlottedPseudoElementSelector(const CSSSelector* selector)
     350{
     351    for (; selector; selector = selector->tagHistory()) {
     352        if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
     353            if (auto* list = selector->selectorList())
     354                return list->first();
     355            break;
     356        }
     357    };
     358    return nullptr;
     359}
     360#endif
    286361
    287362inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity)
     
    357432#endif // ENABLE(CSS_SELECTOR_JIT)
    358433    {
     434        auto* selector = ruleData.selector();
     435#if ENABLE(SHADOW_DOM)
     436        if (m_isMatchingSlottedPseudoElements) {
     437            selector = findSlottedPseudoElementSelector(ruleData.selector());
     438            if (!selector)
     439                return false;
     440        }
     441#endif
    359442        // Slow path.
    360443        SelectorChecker selectorChecker(m_element.document());
    361         selectorMatches = selectorChecker.match(*ruleData.selector(), m_element, context, specificity);
     444        selectorMatches = selectorChecker.match(*selector, m_element, context, specificity);
    362445    }
    363446
  • trunk/Source/WebCore/css/ElementRuleCollector.h

    r196383 r197165  
    7474#if ENABLE(SHADOW_DOM)
    7575    void matchHostPseudoClassRules(bool includeEmptyRules);
     76    void matchSlottedPseudoElementRules(bool includeEmptyRules);
     77    RuleSet::RuleDataVector collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules);
    7678#endif
    7779
     
    99101    bool m_sameOriginOnly { false };
    100102    SelectorChecker::Mode m_mode { SelectorChecker::Mode::ResolvingStyle };
     103#if ENABLE(SHADOW_DOM)
     104    bool m_isMatchingSlottedPseudoElements { false };
     105#endif
    101106
    102107    Vector<MatchedRule, 64> m_matchedRules;
  • trunk/Source/WebCore/css/RuleSet.cpp

    r196383 r197165  
    267267            return;
    268268        }
     269        if (selector->match() == CSSSelector::PseudoElement && selector->pseudoElementType() == CSSSelector::PseudoElementSlotted) {
     270            // ::slotted pseudo elements work accross shadow boundary making filtering difficult.
     271            ruleData.disableSelectorFiltering();
     272            m_slottedPseudoElementRules.append(ruleData);
     273            return;
     274        }
    269275#endif
    270276        if (selector->relation() != CSSSelector::SubSelector)
     
    423429    m_cuePseudoRules.shrinkToFit();
    424430#endif
     431#if ENABLE(SHADOW_DOM)
     432    m_hostPseudoClassRules.shrinkToFit();
     433    m_slottedPseudoElementRules.shrinkToFit();
     434#endif
    425435    m_focusPseudoClassRules.shrinkToFit();
    426436    m_universalRules.shrinkToFit();
  • trunk/Source/WebCore/css/RuleSet.h

    r196383 r197165  
    185185#if ENABLE(SHADOW_DOM)
    186186    const RuleDataVector& hostPseudoClassRules() const { return m_hostPseudoClassRules; }
     187    const RuleDataVector& slottedPseudoElementRules() const { return m_slottedPseudoElementRules; }
    187188#endif
    188189    const RuleDataVector* focusPseudoClassRules() const { return &m_focusPseudoClassRules; }
     
    211212#if ENABLE(SHADOW_DOM)
    212213    RuleDataVector m_hostPseudoClassRules;
     214    RuleDataVector m_slottedPseudoElementRules;
    213215#endif
    214216    RuleDataVector m_focusPseudoClassRules;
  • trunk/Source/WebCore/css/SelectorChecker.cpp

    r196629 r197165  
    4545#include "HTMLParserIdioms.h"
    4646#include "HTMLProgressElement.h"
     47#include "HTMLSlotElement.h"
    4748#include "HTMLStyleElement.h"
    4849#include "InspectorInstrumentation.h"
     
    10391040    }
    10401041#endif
    1041     // ### add the rest of the checks...
     1042#if ENABLE(SHADOW_DOM)
     1043    if (selector.match() == CSSSelector::PseudoElement && selector.pseudoElementType() == CSSSelector::PseudoElementSlotted) {
     1044        // We see ::slotted() pseudo elements when collecting slotted rules from the slot shadow tree only.
     1045        ASSERT(checkingContext.resolvingMode == Mode::CollectingRules);
     1046        return is<HTMLSlotElement>(element);
     1047    }
     1048#endif
    10421049    return true;
    10431050}
  • trunk/Source/WebCore/style/StyleSharingResolver.cpp

    r196031 r197165  
    7777        return nullptr;
    7878    auto& parentElement = *element.parentElement();
     79    if (parentElement.shadowRoot())
     80        return nullptr;
    7981    if (!parentElement.renderStyle())
    8082        return nullptr;
Note: See TracChangeset for help on using the changeset viewer.