Changeset 281798 in webkit


Ignore:
Timestamp:
Aug 31, 2021 4:48:10 AM (11 months ago)
Author:
Antti Koivisto
Message:

[CSS Cascade Layers] Compute order correctly for late added sublayers
https://bugs.webkit.org/show_bug.cgi?id=229666

Reviewed by Simon Fraser.

LayoutTests/imported/w3c:

  • web-platform-tests/css/css-cascade/layer-basic-expected.txt:

Source/WebCore:

In cases like

@layer a.b { ... }
@layer c { ... }
@layer a.d { ... }

'c' should have higher priority than 'a.d'.

Replace the per-RuleData layer order vector with references (indexes) to layer entry vector.
These entries have order field that can be recomputed.

  • style/RuleSet.cpp:

(WebCore::Style::RuleSet::addRule):
(WebCore::Style::RuleSet::Builder::addStyleRule):
(WebCore::Style::RuleSet::Builder::pushCascadeLayer):

Instead of computing order directly we just give each layer an identifier and add an entry for it to the layer vector.

(WebCore::Style::RuleSet::Builder::popCascadeLayer):
(WebCore::Style::RuleSet::Builder::~Builder):

Compute layer order after building for all layers.

(WebCore::Style::RuleSet::shrinkToFit):

  • style/RuleSet.h:

(WebCore::Style::RuleSet::cascadeLayerForIdentifier):
(WebCore::Style::RuleSet::cascadeLayerForIdentifier const):
(WebCore::Style::RuleSet::cascadeLayerOrderFor const):

Location:
trunk
Files:
5 edited

Legend:

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

    r281796 r281798  
     12021-08-31  Antti Koivisto  <antti@apple.com>
     2
     3        [CSS Cascade Layers] Compute order correctly for late added sublayers
     4        https://bugs.webkit.org/show_bug.cgi?id=229666
     5
     6        Reviewed by Simon Fraser.
     7
     8        * web-platform-tests/css/css-cascade/layer-basic-expected.txt:
     9
    1102021-08-31  Youenn Fablet  <youenn@apple.com>
    211
  • trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt

    r281701 r281798  
    1818PASS B8 Named layers
    1919PASS B9 Named layers
    20 FAIL B10 Named layers assert_equals: B10 Named layers, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     20PASS B10 Named layers
    2121PASS C1 Named layers shorthand
    2222PASS C2 Named layers shorthand
    23 FAIL C3 Named layers shorthand assert_equals: C3 Named layers shorthand, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     23PASS C3 Named layers shorthand
    2424PASS C4 Named layers shorthand
    25 FAIL C5 Named layers shorthand assert_equals: C5 Named layers shorthand, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     25PASS C5 Named layers shorthand
    2626PASS D1 Mixed named and anonymous layers
    2727PASS D2 Mixed named and anonymous layers
    2828PASS D3 Mixed named and anonymous layers
    29 FAIL D4 Mixed named and anonymous layers assert_equals: D4 Mixed named and anonymous layers, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     29PASS D4 Mixed named and anonymous layers
    3030PASS D5 Mixed named and anonymous layers
    3131PASS E1 Statement syntax
     
    3333PASS E3 Statement syntax
    3434PASS E4 Statement syntax
    35 FAIL E5 Statement syntax assert_equals: E5 Statement syntax, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
     35PASS E5 Statement syntax
    3636
  • trunk/Source/WebCore/ChangeLog

    r281797 r281798  
     12021-08-31  Antti Koivisto  <antti@apple.com>
     2
     3        [CSS Cascade Layers] Compute order correctly for late added sublayers
     4        https://bugs.webkit.org/show_bug.cgi?id=229666
     5
     6        Reviewed by Simon Fraser.
     7
     8        In cases like
     9
     10            @layer a.b { ... }
     11            @layer c { ... }
     12            @layer a.d { ... }
     13
     14        'c' should have higher priority than 'a.d'.
     15
     16        Replace the per-RuleData layer order vector with references (indexes) to layer entry vector.
     17        These entries have order field that can be recomputed.
     18
     19        * style/RuleSet.cpp:
     20        (WebCore::Style::RuleSet::addRule):
     21        (WebCore::Style::RuleSet::Builder::addStyleRule):
     22        (WebCore::Style::RuleSet::Builder::pushCascadeLayer):
     23
     24        Instead of computing order directly we just give each layer an identifier and add an entry for it to the layer vector.
     25
     26        (WebCore::Style::RuleSet::Builder::popCascadeLayer):
     27        (WebCore::Style::RuleSet::Builder::~Builder):
     28
     29        Compute layer order after building for all layers.
     30
     31        (WebCore::Style::RuleSet::shrinkToFit):
     32        * style/RuleSet.h:
     33        (WebCore::Style::RuleSet::cascadeLayerForIdentifier):
     34        (WebCore::Style::RuleSet::cascadeLayerForIdentifier const):
     35        (WebCore::Style::RuleSet::cascadeLayerOrderFor const):
     36
    1372021-08-31  Philippe Normand  <pnormand@igalia.com>
    238
  • trunk/Source/WebCore/style/RuleSet.cpp

    r281742 r281798  
    8484}
    8585
    86 void RuleSet::addRule(const StyleRule& rule, unsigned selectorIndex, unsigned selectorListIndex, unsigned cascadeLayerOrder, MediaQueryCollector* mediaQueryCollector)
     86void RuleSet::addRule(const StyleRule& rule, unsigned selectorIndex, unsigned selectorListIndex, unsigned cascadeLayerIdentifier, MediaQueryCollector* mediaQueryCollector)
    8787{
    8888    RuleData ruleData(rule, selectorIndex, selectorListIndex, m_ruleCount++);
    8989
    90     if (cascadeLayerOrder) {
    91         auto oldSize = m_cascadeLayerOrderForPosition.size();
    92         m_cascadeLayerOrderForPosition.grow(m_ruleCount);
    93         std::fill(m_cascadeLayerOrderForPosition.begin() + oldSize, m_cascadeLayerOrderForPosition.end(), 0);
    94         m_cascadeLayerOrderForPosition.last() = cascadeLayerOrder;
     90    if (cascadeLayerIdentifier) {
     91        auto oldSize = m_cascadeLayerIdentifierForRulePosition.size();
     92        m_cascadeLayerIdentifierForRulePosition.grow(m_ruleCount);
     93        std::fill(m_cascadeLayerIdentifierForRulePosition.begin() + oldSize, m_cascadeLayerIdentifierForRulePosition.end(), 0);
     94        m_cascadeLayerIdentifierForRulePosition.last() = cascadeLayerIdentifier;
    9595    }
    9696
     
    386386}
    387387
     388RuleSet::Builder::~Builder()
     389{
     390    if (mode == Mode::Normal && !cascadeLayerIdentifierMap.isEmpty())
     391        updateCascadeLayerOrder();
     392}
     393
    388394void RuleSet::Builder::addStyleRule(const StyleRule& rule)
    389395{
     
    393399    unsigned selectorListIndex = 0;
    394400    for (size_t selectorIndex = 0; selectorIndex != notFound; selectorIndex = selectorList.indexOfNextSelectorAfter(selectorIndex))
    395         ruleSet->addRule(rule, selectorIndex, selectorListIndex++, cascadeLayerOrder, &mediaQueryCollector);
     401        ruleSet->addRule(rule, selectorIndex, selectorListIndex++, currentCascadeLayerIdentifier, &mediaQueryCollector);
    396402}
    397403
     
    400406    if (mode != Mode::Normal)
    401407        return;
     408
     409    if (cascadeLayerIdentifierMap.isEmpty() && !ruleSet->m_cascadeLayers.isEmpty()) {
     410        // For incremental build, reconstruct the name->identifier map.
     411        CascadeLayerIdentifier identifier = 0;
     412        for (auto& layer : ruleSet->m_cascadeLayers)
     413            cascadeLayerIdentifierMap.add(layer.resolvedName, ++identifier);
     414    }
     415
    402416    auto nameResolvingAnonymous = [&] {
    403417        if (name.isEmpty()) {
     
    412426    for (auto& nameSegment : nameResolvingAnonymous()) {
    413427        resolvedCascadeLayerName.append(nameSegment);
    414         cascadeLayerOrder = ruleSet->m_cascadeLayerOrderMap.ensure(resolvedCascadeLayerName, [&] {
    415             // FIXME: This is not correct when adding a sublayer to an already registered layer after it has gained siblings.
    416             return ruleSet->m_cascadeLayerOrderMap.size() + 1;
     428        currentCascadeLayerIdentifier = cascadeLayerIdentifierMap.ensure(resolvedCascadeLayerName, [&] {
     429            // Previously unseen layer.
     430            ruleSet->m_cascadeLayers.append({ resolvedCascadeLayerName, currentCascadeLayerIdentifier });
     431            return ruleSet->m_cascadeLayers.size();
    417432        }).iterator->value;
    418433    }
     
    423438    if (mode != Mode::Normal)
    424439        return;
    425     auto size = name.isEmpty() ? 1 : name.size();
    426     resolvedCascadeLayerName.shrink(resolvedCascadeLayerName.size() - size);
    427     cascadeLayerOrder = resolvedCascadeLayerName.isEmpty() ? 0 : ruleSet->m_cascadeLayerOrderMap.get(resolvedCascadeLayerName);
     440
     441    for (auto size = name.isEmpty() ? 1 : name.size(); size--;) {
     442        resolvedCascadeLayerName.removeLast();
     443        currentCascadeLayerIdentifier = ruleSet->cascadeLayerForIdentifier(currentCascadeLayerIdentifier).parentIdentifier;
     444    }
     445}
     446
     447void RuleSet::Builder::updateCascadeLayerOrder()
     448{
     449    auto compare = [&](CascadeLayerIdentifier a, CascadeLayerIdentifier b) {
     450        while (a && b) {
     451            // Identifiers are in parse order which almost corresponds to the layer priority order.
     452            // The only exception is when a sublayer gets added to a layer after adding other non-sublayers.
     453            // To resolve this we need look for a shared ancestor layer.
     454            auto aParent = ruleSet->cascadeLayerForIdentifier(a).parentIdentifier;
     455            auto bParent = ruleSet->cascadeLayerForIdentifier(b).parentIdentifier;
     456            if (aParent == bParent || aParent == b || bParent == a)
     457                break;
     458            if (aParent > bParent)
     459                a = aParent;
     460            else
     461                b = bParent;
     462        }
     463        return a < b;
     464    };
     465
     466    Vector<CascadeLayerIdentifier> orderVector;
     467    auto layerCount = ruleSet->m_cascadeLayers.size();
     468    orderVector.reserveInitialCapacity(layerCount);
     469    for (CascadeLayerIdentifier identifier = 1; identifier <= layerCount; ++identifier)
     470        orderVector.uncheckedAppend(identifier);
     471
     472    std::sort(orderVector.begin(), orderVector.end(), compare);
     473
     474    for (unsigned i = 0; i < orderVector.size(); ++i)
     475        ruleSet->cascadeLayerForIdentifier(orderVector[i]).order = i + 1;
    428476}
    429477
     
    562610    shrinkDynamicRules(m_dynamicMediaQueryRules);
    563611
    564     m_cascadeLayerOrderForPosition.shrinkToFit();
     612    m_cascadeLayers.shrinkToFit();
     613    m_cascadeLayerIdentifierForRulePosition.shrinkToFit();
    565614}
    566615
  • trunk/Source/WebCore/style/RuleSet.h

    r281742 r281798  
    151151    RuleSet();
    152152
     153    using CascadeLayerIdentifier = unsigned;
     154
    153155    struct Builder {
    154156        enum class Mode { Normal, ResolverMutationScan };
     
    159161        Mode mode { Mode::Normal };
    160162        CascadeLayerName resolvedCascadeLayerName { };
    161         unsigned cascadeLayerOrder { 0 };
     163        HashMap<CascadeLayerName, CascadeLayerIdentifier> cascadeLayerIdentifierMap { };
     164        CascadeLayerIdentifier currentCascadeLayerIdentifier { 0 };
    162165
    163166        void addRulesFromSheet(const StyleSheetContents&);
     167
     168        ~Builder();
    164169       
    165170    private:
     
    169174        void pushCascadeLayer(const CascadeLayerName&);
    170175        void popCascadeLayer(const CascadeLayerName&);
     176        void updateCascadeLayerOrder();
    171177    };
    172178
     
    179185
    180186    template<typename Function> void traverseRuleDatas(Function&&);
     187
     188    struct CascadeLayer {
     189        CascadeLayerName resolvedName;
     190        CascadeLayerIdentifier parentIdentifier;
     191        unsigned order { 0 };
     192    };
     193    CascadeLayer& cascadeLayerForIdentifier(CascadeLayerIdentifier identifier) { return m_cascadeLayers[identifier - 1]; }
     194    const CascadeLayer& cascadeLayerForIdentifier(CascadeLayerIdentifier identifier) const { return m_cascadeLayers[identifier - 1]; }
    181195
    182196    AtomRuleMap m_idRules;
     
    200214    unsigned m_ruleCount { 0 };
    201215
    202     HashMap<CascadeLayerName, unsigned> m_cascadeLayerOrderMap;
    203     // This is a side vector to hold layer order without bloating RuleData.
    204     Vector<unsigned> m_cascadeLayerOrderForPosition;
     216    Vector<CascadeLayer> m_cascadeLayers;
     217    // This is a side vector to hold layer identifiers without bloating RuleData.
     218    Vector<CascadeLayerIdentifier> m_cascadeLayerIdentifierForRulePosition;
    205219
    206220    bool m_hasHostPseudoClassRulesMatchingInShadowTree { false };
     
    221235inline unsigned RuleSet::cascadeLayerOrderFor(const RuleData& ruleData) const
    222236{
    223     if (m_cascadeLayerOrderForPosition.size() > ruleData.position())
    224         return m_cascadeLayerOrderForPosition[ruleData.position()];
    225     return 0;
     237    if (m_cascadeLayerIdentifierForRulePosition.size() <= ruleData.position())
     238        return 0;
     239    auto identifier = m_cascadeLayerIdentifierForRulePosition[ruleData.position()];
     240    if (!identifier)
     241        return 0;
     242    return cascadeLayerForIdentifier(identifier).order;
    226243}
    227 
    228244
    229245} // namespace Style
Note: See TracChangeset for help on using the changeset viewer.