Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (281797 => 281798)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-08-31 11:48:10 UTC (rev 281798)
@@ -1,3 +1,12 @@
+2021-08-31 Antti Koivisto <[email protected]>
+
+ [CSS Cascade Layers] Compute order correctly for late added sublayers
+ https://bugs.webkit.org/show_bug.cgi?id=229666
+
+ Reviewed by Simon Fraser.
+
+ * web-platform-tests/css/css-cascade/layer-basic-expected.txt:
+
2021-08-31 Youenn Fablet <[email protected]>
Add support for RTCIceTransport
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt (281797 => 281798)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt 2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/css/css-cascade/layer-basic-expected.txt 2021-08-31 11:48:10 UTC (rev 281798)
@@ -17,20 +17,20 @@
PASS B7 Named layers
PASS B8 Named layers
PASS B9 Named layers
-FAIL B10 Named layers assert_equals: B10 Named layers, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS B10 Named layers
PASS C1 Named layers shorthand
PASS C2 Named layers shorthand
-FAIL C3 Named layers shorthand assert_equals: C3 Named layers shorthand, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS C3 Named layers shorthand
PASS C4 Named layers shorthand
-FAIL C5 Named layers shorthand assert_equals: C5 Named layers shorthand, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS C5 Named layers shorthand
PASS D1 Mixed named and anonymous layers
PASS D2 Mixed named and anonymous layers
PASS D3 Mixed named and anonymous layers
-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)"
+PASS D4 Mixed named and anonymous layers
PASS D5 Mixed named and anonymous layers
PASS E1 Statement syntax
PASS E2 Statement syntax
PASS E3 Statement syntax
PASS E4 Statement syntax
-FAIL E5 Statement syntax assert_equals: E5 Statement syntax, target 'first' expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS E5 Statement syntax
Modified: trunk/Source/WebCore/ChangeLog (281797 => 281798)
--- trunk/Source/WebCore/ChangeLog 2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/Source/WebCore/ChangeLog 2021-08-31 11:48:10 UTC (rev 281798)
@@ -1,3 +1,39 @@
+2021-08-31 Antti Koivisto <[email protected]>
+
+ [CSS Cascade Layers] Compute order correctly for late added sublayers
+ https://bugs.webkit.org/show_bug.cgi?id=229666
+
+ Reviewed by Simon Fraser.
+
+ 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):
+
2021-08-31 Philippe Normand <[email protected]>
Unreviewed, OpenXR build warning fix.
Modified: trunk/Source/WebCore/style/RuleSet.cpp (281797 => 281798)
--- trunk/Source/WebCore/style/RuleSet.cpp 2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/Source/WebCore/style/RuleSet.cpp 2021-08-31 11:48:10 UTC (rev 281798)
@@ -83,15 +83,15 @@
return leftmostSelector->match() == CSSSelector::PseudoClass && leftmostSelector->pseudoClassType() == CSSSelector::PseudoClassHost;
}
-void RuleSet::addRule(const StyleRule& rule, unsigned selectorIndex, unsigned selectorListIndex, unsigned cascadeLayerOrder, MediaQueryCollector* mediaQueryCollector)
+void RuleSet::addRule(const StyleRule& rule, unsigned selectorIndex, unsigned selectorListIndex, unsigned cascadeLayerIdentifier, MediaQueryCollector* mediaQueryCollector)
{
RuleData ruleData(rule, selectorIndex, selectorListIndex, m_ruleCount++);
- if (cascadeLayerOrder) {
- auto oldSize = m_cascadeLayerOrderForPosition.size();
- m_cascadeLayerOrderForPosition.grow(m_ruleCount);
- std::fill(m_cascadeLayerOrderForPosition.begin() + oldSize, m_cascadeLayerOrderForPosition.end(), 0);
- m_cascadeLayerOrderForPosition.last() = cascadeLayerOrder;
+ if (cascadeLayerIdentifier) {
+ auto oldSize = m_cascadeLayerIdentifierForRulePosition.size();
+ m_cascadeLayerIdentifierForRulePosition.grow(m_ruleCount);
+ std::fill(m_cascadeLayerIdentifierForRulePosition.begin() + oldSize, m_cascadeLayerIdentifierForRulePosition.end(), 0);
+ m_cascadeLayerIdentifierForRulePosition.last() = cascadeLayerIdentifier;
}
m_features.collectFeatures(ruleData);
@@ -385,6 +385,12 @@
addChildRules(sheet.childRules());
}
+RuleSet::Builder::~Builder()
+{
+ if (mode == Mode::Normal && !cascadeLayerIdentifierMap.isEmpty())
+ updateCascadeLayerOrder();
+}
+
void RuleSet::Builder::addStyleRule(const StyleRule& rule)
{
auto& selectorList = rule.selectorList();
@@ -392,7 +398,7 @@
return;
unsigned selectorListIndex = 0;
for (size_t selectorIndex = 0; selectorIndex != notFound; selectorIndex = selectorList.indexOfNextSelectorAfter(selectorIndex))
- ruleSet->addRule(rule, selectorIndex, selectorListIndex++, cascadeLayerOrder, &mediaQueryCollector);
+ ruleSet->addRule(rule, selectorIndex, selectorListIndex++, currentCascadeLayerIdentifier, &mediaQueryCollector);
}
void RuleSet::Builder::pushCascadeLayer(const CascadeLayerName& name)
@@ -399,6 +405,14 @@
{
if (mode != Mode::Normal)
return;
+
+ if (cascadeLayerIdentifierMap.isEmpty() && !ruleSet->m_cascadeLayers.isEmpty()) {
+ // For incremental build, reconstruct the name->identifier map.
+ CascadeLayerIdentifier identifier = 0;
+ for (auto& layer : ruleSet->m_cascadeLayers)
+ cascadeLayerIdentifierMap.add(layer.resolvedName, ++identifier);
+ }
+
auto nameResolvingAnonymous = [&] {
if (name.isEmpty()) {
// Make unique name for an anonymous layer.
@@ -411,9 +425,10 @@
// For hierarchical names we register the containing layers individually first.
for (auto& nameSegment : nameResolvingAnonymous()) {
resolvedCascadeLayerName.append(nameSegment);
- cascadeLayerOrder = ruleSet->m_cascadeLayerOrderMap.ensure(resolvedCascadeLayerName, [&] {
- // FIXME: This is not correct when adding a sublayer to an already registered layer after it has gained siblings.
- return ruleSet->m_cascadeLayerOrderMap.size() + 1;
+ currentCascadeLayerIdentifier = cascadeLayerIdentifierMap.ensure(resolvedCascadeLayerName, [&] {
+ // Previously unseen layer.
+ ruleSet->m_cascadeLayers.append({ resolvedCascadeLayerName, currentCascadeLayerIdentifier });
+ return ruleSet->m_cascadeLayers.size();
}).iterator->value;
}
}
@@ -422,11 +437,44 @@
{
if (mode != Mode::Normal)
return;
- auto size = name.isEmpty() ? 1 : name.size();
- resolvedCascadeLayerName.shrink(resolvedCascadeLayerName.size() - size);
- cascadeLayerOrder = resolvedCascadeLayerName.isEmpty() ? 0 : ruleSet->m_cascadeLayerOrderMap.get(resolvedCascadeLayerName);
+
+ for (auto size = name.isEmpty() ? 1 : name.size(); size--;) {
+ resolvedCascadeLayerName.removeLast();
+ currentCascadeLayerIdentifier = ruleSet->cascadeLayerForIdentifier(currentCascadeLayerIdentifier).parentIdentifier;
+ }
}
+void RuleSet::Builder::updateCascadeLayerOrder()
+{
+ auto compare = [&](CascadeLayerIdentifier a, CascadeLayerIdentifier b) {
+ while (a && b) {
+ // Identifiers are in parse order which almost corresponds to the layer priority order.
+ // The only exception is when a sublayer gets added to a layer after adding other non-sublayers.
+ // To resolve this we need look for a shared ancestor layer.
+ auto aParent = ruleSet->cascadeLayerForIdentifier(a).parentIdentifier;
+ auto bParent = ruleSet->cascadeLayerForIdentifier(b).parentIdentifier;
+ if (aParent == bParent || aParent == b || bParent == a)
+ break;
+ if (aParent > bParent)
+ a = aParent;
+ else
+ b = bParent;
+ }
+ return a < b;
+ };
+
+ Vector<CascadeLayerIdentifier> orderVector;
+ auto layerCount = ruleSet->m_cascadeLayers.size();
+ orderVector.reserveInitialCapacity(layerCount);
+ for (CascadeLayerIdentifier identifier = 1; identifier <= layerCount; ++identifier)
+ orderVector.uncheckedAppend(identifier);
+
+ std::sort(orderVector.begin(), orderVector.end(), compare);
+
+ for (unsigned i = 0; i < orderVector.size(); ++i)
+ ruleSet->cascadeLayerForIdentifier(orderVector[i]).order = i + 1;
+}
+
template<typename Function>
void RuleSet::traverseRuleDatas(Function&& function)
{
@@ -561,7 +609,8 @@
shrinkDynamicRules(m_dynamicMediaQueryRules);
- m_cascadeLayerOrderForPosition.shrinkToFit();
+ m_cascadeLayers.shrinkToFit();
+ m_cascadeLayerIdentifierForRulePosition.shrinkToFit();
}
RuleSet::MediaQueryCollector::~MediaQueryCollector() = default;
Modified: trunk/Source/WebCore/style/RuleSet.h (281797 => 281798)
--- trunk/Source/WebCore/style/RuleSet.h 2021-08-31 09:46:29 UTC (rev 281797)
+++ trunk/Source/WebCore/style/RuleSet.h 2021-08-31 11:48:10 UTC (rev 281798)
@@ -150,6 +150,8 @@
private:
RuleSet();
+ using CascadeLayerIdentifier = unsigned;
+
struct Builder {
enum class Mode { Normal, ResolverMutationScan };
@@ -158,9 +160,12 @@
Style::Resolver* resolver { nullptr };
Mode mode { Mode::Normal };
CascadeLayerName resolvedCascadeLayerName { };
- unsigned cascadeLayerOrder { 0 };
+ HashMap<CascadeLayerName, CascadeLayerIdentifier> cascadeLayerIdentifierMap { };
+ CascadeLayerIdentifier currentCascadeLayerIdentifier { 0 };
void addRulesFromSheet(const StyleSheetContents&);
+
+ ~Builder();
private:
void addChildRules(const Vector<RefPtr<StyleRuleBase>>&);
@@ -168,6 +173,7 @@
void pushCascadeLayer(const CascadeLayerName&);
void popCascadeLayer(const CascadeLayerName&);
+ void updateCascadeLayerOrder();
};
struct CollectedMediaQueryChanges {
@@ -179,6 +185,14 @@
template<typename Function> void traverseRuleDatas(Function&&);
+ struct CascadeLayer {
+ CascadeLayerName resolvedName;
+ CascadeLayerIdentifier parentIdentifier;
+ unsigned order { 0 };
+ };
+ CascadeLayer& cascadeLayerForIdentifier(CascadeLayerIdentifier identifier) { return m_cascadeLayers[identifier - 1]; }
+ const CascadeLayer& cascadeLayerForIdentifier(CascadeLayerIdentifier identifier) const { return m_cascadeLayers[identifier - 1]; }
+
AtomRuleMap m_idRules;
AtomRuleMap m_classRules;
AtomRuleMap m_tagLocalNameRules;
@@ -199,9 +213,9 @@
HashMap<Vector<size_t>, Ref<const RuleSet>> m_mediaQueryInvalidationRuleSetCache;
unsigned m_ruleCount { 0 };
- HashMap<CascadeLayerName, unsigned> m_cascadeLayerOrderMap;
- // This is a side vector to hold layer order without bloating RuleData.
- Vector<unsigned> m_cascadeLayerOrderForPosition;
+ Vector<CascadeLayer> m_cascadeLayers;
+ // This is a side vector to hold layer identifiers without bloating RuleData.
+ Vector<CascadeLayerIdentifier> m_cascadeLayerIdentifierForRulePosition;
bool m_hasHostPseudoClassRulesMatchingInShadowTree { false };
bool m_autoShrinkToFitEnabled { true };
@@ -220,11 +234,13 @@
inline unsigned RuleSet::cascadeLayerOrderFor(const RuleData& ruleData) const
{
- if (m_cascadeLayerOrderForPosition.size() > ruleData.position())
- return m_cascadeLayerOrderForPosition[ruleData.position()];
- return 0;
+ if (m_cascadeLayerIdentifierForRulePosition.size() <= ruleData.position())
+ return 0;
+ auto identifier = m_cascadeLayerIdentifierForRulePosition[ruleData.position()];
+ if (!identifier)
+ return 0;
+ return cascadeLayerForIdentifier(identifier).order;
}
-
} // namespace Style
} // namespace WebCore