Changeset 201073 in webkit


Ignore:
Timestamp:
May 18, 2016 1:41:50 AM (8 years ago)
Author:
Antti Koivisto
Message:

Cascading order for !important properties in ::slotted and ::host rules is incorrect
https://bugs.webkit.org/show_bug.cgi?id=157789
<rdar://problem/26318781>

Reviewed by Andreas Kling.

LayoutTests/imported/w3c:

  • csswg-test/css-scoping-1/shadow-cascade-order-001-expected.txt: This now passes.

Source/WebCore:

https://drafts.csswg.org/css-scoping-1/#shadow-cascading

"When comparing two declarations that have different tree contexts, then for normal rules the declaration earlier
in the shadow-including tree order wins, and for important rules the declaration coming later in the shadow-including
tree order wins."

  • css/ElementRuleCollector.cpp:

(WebCore::MatchRequest::MatchRequest):
(WebCore::ElementRuleCollector::ElementRuleCollector):
(WebCore::ElementRuleCollector::matchedRuleList):
(WebCore::ElementRuleCollector::addMatchedRule):
(WebCore::ElementRuleCollector::clearMatchedRules):
(WebCore::ElementRuleCollector::addElementStyleProperties):
(WebCore::ElementRuleCollector::sortAndTransferMatchedRules):

Pass the tree context ordinal onwards so we can implement the order reversal semantics for !important properties.

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

Don't flush the matched rules immediately to get the right ordering. Instead compute tree context ordinal
that is then used as a sorting criteria.

(WebCore::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot):
(WebCore::ElementRuleCollector::collectMatchingRulesForList):
(WebCore::compareRules):

Sort regular rules so that earlier shadow trees win.

(WebCore::ElementRuleCollector::sortMatchedRules):

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

(WebCore::StyleResolver::State::clear):
(WebCore::StyleResolver::MatchResult::addMatchedProperties):
(WebCore::StyleResolver::CascadedProperties::addMatch): Added.

Add a helper.

(WebCore::StyleResolver::CascadedProperties::addNormalMatches):

Split normal and important to different functions for clarity.

(WebCore::StyleResolver::CascadedProperties::addImportantMatches):

For !important properties a later shadow tree wins. Do multiple passes to apply in correct order if needed.

  • css/StyleResolver.h:

(WebCore::StyleResolver::MatchResult::matchedProperties):

Location:
trunk
Files:
7 edited

Legend:

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

    r200697 r201073  
     12016-05-18  Antti Koivisto  <antti@apple.com>
     2
     3        Cascading order for !important properties in ::slotted and ::host rules is incorrect
     4        https://bugs.webkit.org/show_bug.cgi?id=157789
     5        <rdar://problem/26318781>
     6
     7        Reviewed by Andreas Kling.
     8
     9        * csswg-test/css-scoping-1/shadow-cascade-order-001-expected.txt: This now passes.
     10
    1112016-05-11  Brady Eidson  <beidson@apple.com>
    212
  • trunk/LayoutTests/imported/w3c/csswg-test/css-scoping-1/shadow-cascade-order-001-expected.txt

    r200234 r201073  
    1818PASS C5. ::slotted with !important vs inline, ::slotted rule should win for open mode.
    1919PASS C6. :host with !important vs inline, :host rule should win for open mode.
    20 FAIL D1. document vs ::slotted both with !important, ::slotted rule should win for open mode. assert_equals: D1. document vs ::slotted both with !important, ::slotted rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
    21 FAIL D2. document vs :host both with !important, :host rule should win for open mode. assert_equals: D2. document vs :host both with !important, :host rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     20PASS D1. document vs ::slotted both with !important, ::slotted rule should win for open mode.
     21PASS D2. document vs :host both with !important, :host rule should win for open mode.
    2222PASS D3. document vs inline both with !important, inline rule should win for open mode.
    23 FAIL D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win for open mode. assert_equals: D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
    24 FAIL D5. ::slotted vs inline both with !important, ::slotted rule should win for open mode. assert_equals: D5. ::slotted vs inline both with !important, ::slotted rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
    25 FAIL D6. :host vs inline both with !important, :host rule should win for open mode. assert_equals: D6. :host vs inline both with !important, :host rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     23PASS D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win for open mode.
     24PASS D5. ::slotted vs inline both with !important, ::slotted rule should win for open mode.
     25PASS D6. :host vs inline both with !important, :host rule should win for open mode.
    2626PASS E1. all style applied, inline rule should win for open mode.
    27 FAIL E2. all styles with !important applied, rule in the last tree-of-trees should win for open mode. assert_equals: E2. all styles with !important applied, rule in the last tree-of-trees should win expected "rgb(0, 128, 0)" but got "rgb(255, 255, 0)"
     27PASS E2. all styles with !important applied, rule in the last tree-of-trees should win for open mode.
    2828PASS A1. document vs ::slotted, document rule should win for closed mode.
    2929PASS A2. document vs :host, document rule should win for closed mode.
     
    4444PASS C5. ::slotted with !important vs inline, ::slotted rule should win for closed mode.
    4545PASS C6. :host with !important vs inline, :host rule should win for closed mode.
    46 FAIL D1. document vs ::slotted both with !important, ::slotted rule should win for closed mode. assert_equals: D1. document vs ::slotted both with !important, ::slotted rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
    47 FAIL D2. document vs :host both with !important, :host rule should win for closed mode. assert_equals: D2. document vs :host both with !important, :host rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     46PASS D1. document vs ::slotted both with !important, ::slotted rule should win for closed mode.
     47PASS D2. document vs :host both with !important, :host rule should win for closed mode.
    4848PASS D3. document vs inline both with !important, inline rule should win for closed mode.
    49 FAIL D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win for closed mode. assert_equals: D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
    50 FAIL D5. ::slotted vs inline both with !important, ::slotted rule should win for closed mode. assert_equals: D5. ::slotted vs inline both with !important, ::slotted rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
    51 FAIL D6. :host vs inline both with !important, :host rule should win for closed mode. assert_equals: D6. :host vs inline both with !important, :host rule should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     49PASS D4. ::slotted vs :host both with !important, later in tree-of-trees rule should win for closed mode.
     50PASS D5. ::slotted vs inline both with !important, ::slotted rule should win for closed mode.
     51PASS D6. :host vs inline both with !important, :host rule should win for closed mode.
    5252PASS E1. all style applied, inline rule should win for closed mode.
    53 FAIL E2. all styles with !important applied, rule in the last tree-of-trees should win for closed mode. assert_equals: E2. all styles with !important applied, rule in the last tree-of-trees should win expected "rgb(0, 128, 0)" but got "rgb(255, 255, 0)"
     53PASS E2. all styles with !important applied, rule in the last tree-of-trees should win for closed mode.
    5454PASS F1. document vs others, document (the first rule in tree-of-trees order) rule should win for open mode.
    5555PASS F2. document with !important vs others, document rule should win for open mode.
     
    5757PASS F4. document vs ::slotted with !important, important rule should win for open mode.
    5858PASS F5. document vs :host with !important, important rule should win for open mode.
    59 FAIL F6. all rules with !important, the last rule in tree-of-trees should win for open mode. assert_equals: F6. all rules with !important, the last rule in tree-of-trees should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     59PASS F6. all rules with !important, the last rule in tree-of-trees should win for open mode.
    6060PASS F1. document vs others, document (the first rule in tree-of-trees order) rule should win for closed mode.
    6161PASS F2. document with !important vs others, document rule should win for closed mode.
     
    6363PASS F4. document vs ::slotted with !important, important rule should win for closed mode.
    6464PASS F5. document vs :host with !important, important rule should win for closed mode.
    65 FAIL F6. all rules with !important, the last rule in tree-of-trees should win for closed mode. assert_equals: F6. all rules with !important, the last rule in tree-of-trees should win expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     65PASS F6. all rules with !important, the last rule in tree-of-trees should win for closed mode.
    6666
  • trunk/Source/WebCore/ChangeLog

    r201072 r201073  
     12016-05-17  Antti Koivisto  <antti@apple.com>
     2
     3        Cascading order for !important properties in ::slotted and ::host rules is incorrect
     4        https://bugs.webkit.org/show_bug.cgi?id=157789
     5        <rdar://problem/26318781>
     6
     7        Reviewed by Andreas Kling.
     8
     9        https://drafts.csswg.org/css-scoping-1/#shadow-cascading
     10
     11        "When comparing two declarations that have different tree contexts, then for normal rules the declaration earlier
     12        in the shadow-including tree order wins, and for important rules the declaration coming later in the shadow-including
     13        tree order wins."
     14
     15        * css/ElementRuleCollector.cpp:
     16        (WebCore::MatchRequest::MatchRequest):
     17        (WebCore::ElementRuleCollector::ElementRuleCollector):
     18        (WebCore::ElementRuleCollector::matchedRuleList):
     19        (WebCore::ElementRuleCollector::addMatchedRule):
     20        (WebCore::ElementRuleCollector::clearMatchedRules):
     21        (WebCore::ElementRuleCollector::addElementStyleProperties):
     22        (WebCore::ElementRuleCollector::sortAndTransferMatchedRules):
     23
     24            Pass the tree context ordinal onwards so we can implement the order reversal semantics for !important properties.
     25
     26        (WebCore::ElementRuleCollector::matchAuthorRules):
     27        (WebCore::ElementRuleCollector::matchHostPseudoClassRules):
     28        (WebCore::ElementRuleCollector::matchSlottedPseudoElementRules):
     29
     30            Don't flush the matched rules immediately to get the right ordering. Instead compute tree context ordinal
     31            that is then used as a sorting criteria.
     32
     33        (WebCore::ElementRuleCollector::collectSlottedPseudoElementRulesForSlot):
     34        (WebCore::ElementRuleCollector::collectMatchingRulesForList):
     35        (WebCore::compareRules):
     36
     37            Sort regular rules so that earlier shadow trees win.
     38
     39        (WebCore::ElementRuleCollector::sortMatchedRules):
     40        * css/ElementRuleCollector.h:
     41        * css/StyleResolver.cpp:
     42        (WebCore::StyleResolver::State::clear):
     43        (WebCore::StyleResolver::MatchResult::addMatchedProperties):
     44        (WebCore::StyleResolver::CascadedProperties::addMatch): Added.
     45
     46            Add a helper.
     47
     48        (WebCore::StyleResolver::CascadedProperties::addNormalMatches):
     49
     50            Split normal and important to different functions for clarity.
     51
     52        (WebCore::StyleResolver::CascadedProperties::addImportantMatches):
     53
     54            For !important properties a later shadow tree wins. Do multiple passes to apply in correct order if needed.
     55
     56        * css/StyleResolver.h:
     57        (WebCore::StyleResolver::MatchResult::matchedProperties):
     58
    1592016-05-18  Joanmarie Diggs  <jdiggs@igalia.com>
    260
  • trunk/Source/WebCore/css/ElementRuleCollector.cpp

    r199844 r201073  
    7070class MatchRequest {
    7171public:
    72     MatchRequest(const RuleSet* ruleSet, bool includeEmptyRules = false)
     72    MatchRequest(const RuleSet* ruleSet, bool includeEmptyRules = false, unsigned treeContextOrdinal = 0)
    7373        : ruleSet(ruleSet)
    7474        , includeEmptyRules(includeEmptyRules)
     75        , treeContextOrdinal(treeContextOrdinal)
    7576    {
    7677    }
    7778    const RuleSet* ruleSet;
    7879    const bool includeEmptyRules;
     80    unsigned treeContextOrdinal;
    7981};
    8082
     
    108110}
    109111
    110 inline void ElementRuleCollector::addMatchedRule(const RuleData& ruleData, unsigned specificity, StyleResolver::RuleRange& ruleRange)
     112inline void ElementRuleCollector::addMatchedRule(const RuleData& ruleData, unsigned specificity, unsigned treeContextOrdinal, StyleResolver::RuleRange& ruleRange)
    111113{
    112114    // Update our first/last rule indices in the matched rules array.
     
    115117        ruleRange.firstRuleIndex = ruleRange.lastRuleIndex;
    116118
    117     m_matchedRules.append({ &ruleData, specificity });
     119    m_matchedRules.append({ &ruleData, specificity, treeContextOrdinal });
    118120}
    119121
     
    121123{
    122124    m_matchedRules.clear();
     125#if ENABLE(SHADOW_DOM)
     126    m_keepAliveSlottedPseudoElementRules.clear();
     127#endif
     128
    123129}
    124130
     
    200206
    201207    for (const MatchedRule& matchedRule : m_matchedRules) {
    202         m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType());
     208        m_result.addMatchedProperties(matchedRule.ruleData->rule()->properties(), matchedRule.ruleData->rule(), matchedRule.ruleData->linkMatchType(), matchedRule.ruleData->propertyWhitelistType(), matchedRule.treeContextOrdinal);
    203209    }
    204210}
     
    206212void ElementRuleCollector::matchAuthorRules(bool includeEmptyRules)
    207213{
    208 #if ENABLE(SHADOW_DOM)
    209     if (m_element.shadowRoot())
    210         matchHostPseudoClassRules(includeEmptyRules);
    211 
    212     auto* parent = m_element.parentNode();
    213     if (parent && parent->shadowRoot())
    214         matchSlottedPseudoElementRules(includeEmptyRules);
    215 #endif
    216 
    217214    clearMatchedRules();
     215
    218216    m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
     217    StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
    219218
    220219    // Match global author rules.
    221220    MatchRequest matchRequest(&m_authorStyle, includeEmptyRules);
    222     StyleResolver::RuleRange ruleRange = m_result.ranges.authorRuleRange();
    223221    collectMatchingRules(matchRequest, ruleRange);
    224222    collectMatchingRulesForRegion(matchRequest, ruleRange);
    225223
     224#if ENABLE(SHADOW_DOM)
     225    auto* parent = m_element.parentElement();
     226    if (parent && parent->shadowRoot())
     227        matchSlottedPseudoElementRules(matchRequest, ruleRange);
     228
     229    if (m_element.shadowRoot())
     230        matchHostPseudoClassRules(matchRequest, ruleRange);
     231#endif
     232
    226233    sortAndTransferMatchedRules();
    227234}
    228235
    229236#if ENABLE(SHADOW_DOM)
    230 void ElementRuleCollector::matchHostPseudoClassRules(bool includeEmptyRules)
     237void ElementRuleCollector::matchHostPseudoClassRules(MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
    231238{
    232239    ASSERT(m_element.shadowRoot());
     240
     241    matchRequest.treeContextOrdinal++;
     242
    233243    auto& shadowAuthorStyle = *m_element.shadowRoot()->styleResolver().ruleSets().authorStyle();
    234244    auto& shadowHostRules = shadowAuthorStyle.hostPseudoClassRules();
     
    236246        return;
    237247
    238     clearMatchedRules();
    239     m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
    240 
    241248    SelectorChecker::CheckingContext context(m_mode);
    242249    SelectorChecker selectorChecker(m_element.document());
    243250
    244     auto ruleRange = m_result.ranges.authorRuleRange();
    245251    for (auto& ruleData : shadowHostRules) {
    246         if (ruleData.rule()->properties().isEmpty() && !includeEmptyRules)
     252        if (ruleData.rule()->properties().isEmpty() && !matchRequest.includeEmptyRules)
    247253            continue;
    248254        auto& selector = *ruleData.selector();
     
    250256        if (!selectorChecker.matchHostPseudoClass(selector, m_element, context, specificity))
    251257            continue;
    252         addMatchedRule(ruleData, specificity, ruleRange);
    253     }
    254 
    255     // We just sort the host rules before other author rules. This matches the current vague spec language
    256     // but is not necessarily exactly what is needed.
    257     // FIXME: Match the spec when it is finalized.
    258     sortAndTransferMatchedRules();
    259 }
    260 
    261 void ElementRuleCollector::matchSlottedPseudoElementRules(bool includeEmptyRules)
    262 {
    263     RuleSet::RuleDataVector slottedPseudoElementRules;
    264 
     258        addMatchedRule(ruleData, specificity, matchRequest.treeContextOrdinal, ruleRange);
     259    }
     260}
     261
     262void ElementRuleCollector::matchSlottedPseudoElementRules(MatchRequest& matchRequest, StyleResolver::RuleRange& ruleRange)
     263{
    265264    auto* maybeSlotted = &m_element;
    266265    for (auto* hostShadowRoot = m_element.parentNode()->shadowRoot(); hostShadowRoot; hostShadowRoot = maybeSlotted->parentNode()->shadowRoot()) {
    267266        auto* slot = hostShadowRoot->findAssignedSlot(*maybeSlotted);
    268267        if (!slot)
    269             break;
     268            return;
     269
     270        matchRequest.treeContextOrdinal++;
     271
    270272        // In nested case the slot may itself be assigned to a slot. Collect ::slotted rules from all the nested trees.
    271273        maybeSlotted = slot;
     
    276278        // FIXME: This is really part of the slot style and could be cached when resolving it.
    277279        ElementRuleCollector collector(*slot, *shadowAuthorStyle, nullptr);
    278         slottedPseudoElementRules.appendVector(collector.collectSlottedPseudoElementRulesForSlot(includeEmptyRules));
    279     }
    280 
    281     if (slottedPseudoElementRules.isEmpty())
    282         return;
    283 
    284     clearMatchedRules();
    285     m_result.ranges.lastAuthorRule = m_result.matchedProperties().size() - 1;
    286 
    287     {
     280        auto slottedPseudoElementRules = collector.collectSlottedPseudoElementRulesForSlot(matchRequest.includeEmptyRules);
     281        if (!slottedPseudoElementRules)
     282            continue;
    288283        // Match in the current scope.
    289284        TemporaryChange<bool> change(m_isMatchingSlottedPseudoElements, true);
    290285
    291         MatchRequest matchRequest(nullptr, includeEmptyRules);
    292         auto ruleRange = m_result.ranges.authorRuleRange();
    293         collectMatchingRulesForList(&slottedPseudoElementRules, matchRequest, ruleRange);
    294     }
    295 
    296     // FIXME: What is the correct order?
    297     sortAndTransferMatchedRules();
    298 }
    299 
    300 RuleSet::RuleDataVector ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules)
     286        MatchRequest scopeMatchRequest(nullptr, matchRequest.includeEmptyRules, matchRequest.treeContextOrdinal);
     287        collectMatchingRulesForList(slottedPseudoElementRules.get(), scopeMatchRequest, ruleRange);
     288
     289        m_keepAliveSlottedPseudoElementRules.append(WTFMove(slottedPseudoElementRules));
     290    }
     291}
     292
     293std::unique_ptr<RuleSet::RuleDataVector> ElementRuleCollector::collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules)
    301294{
    302295    ASSERT(is<HTMLSlotElement>(m_element));
     
    314307        return { };
    315308
    316     RuleSet::RuleDataVector ruleDataVector;
    317     ruleDataVector.reserveInitialCapacity(m_matchedRules.size());
     309    auto ruleDataVector = std::make_unique<RuleSet::RuleDataVector>();
     310    ruleDataVector->reserveInitialCapacity(m_matchedRules.size());
    318311    for (auto& matchedRule : m_matchedRules)
    319         ruleDataVector.uncheckedAppend(*matchedRule.ruleData);
     312        ruleDataVector->uncheckedAppend(*matchedRule.ruleData);
     313
    320314    return ruleDataVector;
    321315}
     
    504498        unsigned specificity;
    505499        if (ruleMatches(ruleData, specificity))
    506             addMatchedRule(ruleData, specificity, ruleRange);
     500            addMatchedRule(ruleData, specificity, matchRequest.treeContextOrdinal, ruleRange);
    507501    }
    508502}
     
    510504static inline bool compareRules(MatchedRule r1, MatchedRule r2)
    511505{
    512     unsigned specificity1 = r1.specificity;
    513     unsigned specificity2 = r2.specificity;
    514     return (specificity1 == specificity2) ? r1.ruleData->position() < r2.ruleData->position() : specificity1 < specificity2;
     506    // For normal properties the earlier tree wins. This may be reversed by !important which is handled when resolving cascade.
     507    if (r1.treeContextOrdinal != r2.treeContextOrdinal)
     508        return r1.treeContextOrdinal > r2.treeContextOrdinal;
     509
     510    if (r1.specificity != r2.specificity)
     511        return r1.specificity < r2.specificity;
     512
     513    return r1.ruleData->position() < r2.ruleData->position();
    515514}
    516515
  • trunk/Source/WebCore/css/ElementRuleCollector.h

    r199291 r201073  
    4141struct MatchedRule {
    4242    const RuleData* ruleData;
    43     unsigned specificity;
     43    unsigned specificity;   
     44    unsigned treeContextOrdinal;
    4445};
    4546
     
    7778    void matchUARules(RuleSet*);
    7879#if ENABLE(SHADOW_DOM)
    79     void matchHostPseudoClassRules(bool includeEmptyRules);
    80     void matchSlottedPseudoElementRules(bool includeEmptyRules);
    81     RuleSet::RuleDataVector collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules);
     80    void matchHostPseudoClassRules(MatchRequest&, StyleResolver::RuleRange&);
     81    void matchSlottedPseudoElementRules(MatchRequest&, StyleResolver::RuleRange&);
     82    std::unique_ptr<RuleSet::RuleDataVector> collectSlottedPseudoElementRulesForSlot(bool includeEmptyRules);
    8283#endif
    8384
     
    9091    void sortAndTransferMatchedRules();
    9192
    92     void addMatchedRule(const RuleData&, unsigned specificity, StyleResolver::RuleRange&);
     93    void addMatchedRule(const RuleData&, unsigned specificity, unsigned treeContextOrdinal, StyleResolver::RuleRange&);
    9394
    9495    const Element& m_element;
     
    104105#if ENABLE(SHADOW_DOM)
    105106    bool m_isMatchingSlottedPseudoElements { false };
     107    Vector<std::unique_ptr<RuleSet::RuleDataVector>> m_keepAliveSlottedPseudoElementRules;
    106108#endif
    107109
  • trunk/Source/WebCore/css/StyleResolver.cpp

    r200626 r201073  
    198198}
    199199
    200 void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType)
     200void StyleResolver::MatchResult::addMatchedProperties(const StyleProperties& properties, StyleRule* rule, unsigned linkMatchType, PropertyWhitelistType propertyWhitelistType, unsigned treeContextOrdinal)
    201201{
    202202    m_matchedProperties.grow(m_matchedProperties.size() + 1);
     
    205205    newProperties.linkMatchType = linkMatchType;
    206206    newProperties.whitelistType = propertyWhitelistType;
     207    newProperties.treeContextOrdinal = treeContextOrdinal;
    207208    matchedRules.append(rule);
     209
     210    // Ordinal is relative to the currently matched element
     211    if (treeContextOrdinal)
     212        isCacheable = false;
    208213
    209214    if (isCacheable) {
     
    464469    // decl, there's nothing to override. So just add the first properties.
    465470    CascadedProperties cascade(direction, writingMode);
    466     cascade.addMatches(result, false, 0, result.matchedProperties().size() - 1);
     471    cascade.addNormalMatches(result, 0, result.matchedProperties().size() - 1);
    467472   
    468473    // Resolve custom properties first.
     
    632637
    633638    CascadedProperties cascade(direction, writingMode);
    634     cascade.addMatches(result, false, 0, result.matchedProperties().size() - 1);
     639    cascade.addNormalMatches(result, 0, result.matchedProperties().size() - 1);
    635640
    636641    // Resolve custom properties first.
     
    13251330        // can look at them later to figure out if this is a styled form control or not.
    13261331        CascadedProperties cascade(direction, writingMode);
    1327         cascade.addMatches(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
    1328         cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
     1332        cascade.addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
     1333        cascade.addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
    13291334
    13301335        applyCascadedProperties(cascade, CSSPropertyWebkitRubyPosition, CSSPropertyWebkitRubyPosition, &matchResult);
     
    13441349
    13451350    CascadedProperties cascade(direction, writingMode);
    1346     cascade.addMatches(matchResult, false, 0, matchResult.matchedProperties().size() - 1, applyInheritedOnly);
    1347     cascade.addMatches(matchResult, true, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
    1348     cascade.addMatches(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
    1349     cascade.addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
     1351    cascade.addNormalMatches(matchResult, 0, matchResult.matchedProperties().size() - 1, applyInheritedOnly);
     1352    cascade.addImportantMatches(matchResult, matchResult.ranges.firstAuthorRule, matchResult.ranges.lastAuthorRule, applyInheritedOnly);
     1353    cascade.addImportantMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, applyInheritedOnly);
     1354    cascade.addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, applyInheritedOnly);
    13501355   
    13511356    // Resolve custom properties first.
     
    15231528       
    15241529        // This special rollback cascade contains UA rules and user rules but no author rules.
    1525         newAuthorRollback->addMatches(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
    1526         newAuthorRollback->addMatches(matchResult, false, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
    1527         newAuthorRollback->addMatches(matchResult, true, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
    1528         newAuthorRollback->addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
     1530        newAuthorRollback->addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
     1531        newAuthorRollback->addNormalMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
     1532        newAuthorRollback->addImportantMatches(matchResult, matchResult.ranges.firstUserRule, matchResult.ranges.lastUserRule, false);
     1533        newAuthorRollback->addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
    15291534   
    15301535        state().setAuthorRollback(newAuthorRollback);
     
    15401545       
    15411546        // This special rollback cascade contains only UA rules.
    1542         newUserRollback->addMatches(matchResult, false, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
    1543         newUserRollback->addMatches(matchResult, true, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
     1547        newUserRollback->addNormalMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
     1548        newUserRollback->addImportantMatches(matchResult, matchResult.ranges.firstUARule, matchResult.ranges.lastUARule, false);
    15441549   
    15451550        state().setUserRollback(newUserRollback);
     
    23812386}
    23822387
    2383 void StyleResolver::CascadedProperties::addMatches(const MatchResult& matchResult, bool important, int startIndex, int endIndex, bool inheritedOnly)
     2388void StyleResolver::CascadedProperties::addMatch(const MatchResult& matchResult, unsigned index, bool isImportant, bool inheritedOnly)
     2389{
     2390    const MatchedProperties& matchedProperties = matchResult.matchedProperties()[index];
     2391
     2392    auto propertyWhitelistType = static_cast<PropertyWhitelistType>(matchedProperties.whitelistType);
     2393    auto cascadeLevel = cascadeLevelForIndex(matchResult, index);
     2394
     2395    addStyleProperties(*matchedProperties.properties, *matchResult.matchedRules[index], isImportant, inheritedOnly, propertyWhitelistType, matchedProperties.linkMatchType, cascadeLevel);
     2396}
     2397
     2398void StyleResolver::CascadedProperties::addNormalMatches(const MatchResult& matchResult, int startIndex, int endIndex, bool inheritedOnly)
    23842399{
    23852400    if (startIndex == -1)
    23862401        return;
    23872402
    2388     for (int i = startIndex; i <= endIndex; ++i) {
    2389         const MatchedProperties& matchedProperties = matchResult.matchedProperties()[i];
    2390         addStyleProperties(*matchedProperties.properties, *matchResult.matchedRules[i], important, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.whitelistType), matchedProperties.linkMatchType,
    2391             cascadeLevelForIndex(matchResult, i));
     2403    for (int i = startIndex; i <= endIndex; ++i)
     2404        addMatch(matchResult, i, false, inheritedOnly);
     2405}
     2406
     2407static bool hasImportantProperties(const StyleProperties& properties)
     2408{
     2409    for (unsigned i = 0, count = properties.propertyCount(); i < count; ++i) {
     2410        if (properties.propertyAt(i).isImportant())
     2411            return true;
     2412    }
     2413    return false;
     2414}
     2415
     2416void StyleResolver::CascadedProperties::addImportantMatches(const MatchResult& matchResult, int startIndex, int endIndex, bool inheritedOnly)
     2417{
     2418    if (startIndex == -1)
     2419        return;
     2420
     2421    unsigned highestTreeContextOrdinal = 0;
     2422    for (unsigned treeContextPass = 0; treeContextPass <= highestTreeContextOrdinal; ++treeContextPass) {
     2423        for (int i = startIndex; i <= endIndex; ++i) {
     2424            const MatchedProperties& matchedProperties = matchResult.matchedProperties()[i];
     2425
     2426            if (!hasImportantProperties(*matchedProperties.properties))
     2427                continue;
     2428
     2429            // For !important properties a later shadow tree wins. Do multiple passes to apply in correct order if needed.
     2430            // Matched properties are sorted in reverse tree context order so this is not needed for normal properties.
     2431            if (matchedProperties.treeContextOrdinal != treeContextPass) {
     2432                highestTreeContextOrdinal = std::max(matchedProperties.treeContextOrdinal, highestTreeContextOrdinal);
     2433                continue;
     2434            }
     2435
     2436            addMatch(matchResult, i, true, inheritedOnly);
     2437        }
    23922438    }
    23932439}
  • trunk/Source/WebCore/css/StyleResolver.h

    r200977 r201073  
    258258                unsigned linkMatchType : 2;
    259259                unsigned whitelistType : 2;
     260                unsigned treeContextOrdinal : 28;
    260261            };
    261262            // Used to make sure all memory is zero-initialized since we compute the hash over the bytes of this object.
     
    272273        const Vector<MatchedProperties, 64>& matchedProperties() const { return m_matchedProperties; }
    273274
    274         void addMatchedProperties(const StyleProperties&, StyleRule* = nullptr, unsigned linkMatchType = SelectorChecker::MatchAll, PropertyWhitelistType = PropertyWhitelistNone);
     275        void addMatchedProperties(const StyleProperties&, StyleRule* = nullptr, unsigned linkMatchType = SelectorChecker::MatchAll, PropertyWhitelistType = PropertyWhitelistNone, unsigned treeContextOrdinal = 0);
    275276    private:
    276277        Vector<MatchedProperties, 64> m_matchedProperties;
     
    292293        bool hasProperty(CSSPropertyID) const;
    293294        Property& property(CSSPropertyID);
    294         void addMatches(const MatchResult&, bool important, int startIndex, int endIndex, bool inheritedOnly = false);
     295
     296        void addNormalMatches(const MatchResult&, int startIndex, int endIndex, bool inheritedOnly = false);
     297        void addImportantMatches(const MatchResult&, int startIndex, int endIndex, bool inheritedOnly = false);
    295298
    296299        void set(CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel);
     
    304307       
    305308    private:
     309        void addMatch(const MatchResult&, unsigned index, bool isImportant, bool inheritedOnly);
    306310        void addStyleProperties(const StyleProperties&, StyleRule&, bool isImportant, bool inheritedOnly, PropertyWhitelistType, unsigned linkMatchType, CascadeLevel);
    307311        static void setPropertyInternal(Property&, CSSPropertyID, CSSValue&, unsigned linkMatchType, CascadeLevel);
Note: See TracChangeset for help on using the changeset viewer.