Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(470)

Unified Diff: Source/core/css/resolver/StyleResolver.cpp

Issue 1134173002: Get rid of TreeBoundaryCrossingRules. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Missing resolver decrement and adjusted test. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/css/resolver/StyleResolver.cpp
diff --git a/Source/core/css/resolver/StyleResolver.cpp b/Source/core/css/resolver/StyleResolver.cpp
index 1d84bacaf6c88376f7580e695724a25b7b7100e1..c38e67ba3f130509554da735338c97107c2ec8ce 100644
--- a/Source/core/css/resolver/StyleResolver.cpp
+++ b/Source/core/css/resolver/StyleResolver.cpp
@@ -124,9 +124,9 @@ static StylePropertySet* rightToLeftDeclaration()
return rightToLeftDecl;
}
-static void collectScopedResolversForHostedShadowTrees(const Element* element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolvers)
+static void collectScopedResolversForHostedShadowTrees(const Element& element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolvers)
{
- ElementShadow* shadow = element->shadow();
+ ElementShadow* shadow = element.shadow();
if (!shadow)
return;
@@ -139,6 +139,25 @@ static void collectScopedResolversForHostedShadowTrees(const Element* element, W
}
}
+static void collectScopedResolversForTreeBoundaryCrossingRules(const Element& element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolversInOuterScopes, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolversInDistributedScopes)
+{
+ // TODO(rune@opera.com): TreeScope::treeScopeInComposedTree can potentially be expensive as its doing
+ // composed tree traversal to find the closest tree-scope for the element in the composed tree. Getting the
+ // ancestor tree-scopes are much cheaper as we do the composed tree traversal for each TreeScope once and then cache
+ // its composed tree parent scope as a member.
+ for (TreeScope* scope = TreeScope::treeScopeInComposedTree(element); scope; scope = scope->composedParent()) {
+ if (scope == element.treeScope())
+ continue;
+ ScopedStyleResolver* resolver = scope->scopedStyleResolver();
+ if (!resolver || !resolver->hasTreeBoundaryCrossingRules())
+ continue;
+ if (element.treeScope().isInclusiveAncestorOf(resolver->treeScope()))
+ resolversInDistributedScopes.append(resolver);
+ else
+ resolversInOuterScopes.append(resolver);
+ }
+}
+
StyleResolver::StyleResolver(Document& document)
: m_document(document)
, m_viewportStyleResolver(ViewportStyleResolver::create(&document))
@@ -233,14 +252,8 @@ void StyleResolver::resetRuleFeatures()
m_needCollectFeatures = true;
}
-void StyleResolver::addTreeBoundaryCrossingScope(ContainerNode& scope)
-{
- m_treeBoundaryCrossingRules.addScope(scope);
-}
-
void StyleResolver::resetAuthorStyle(TreeScope& treeScope)
{
- m_treeBoundaryCrossingRules.removeScope(treeScope.rootNode());
resetRuleFeatures();
ScopedStyleResolver* resolver = treeScope.scopedStyleResolver();
@@ -359,7 +372,7 @@ static inline ScopedStyleResolver* scopedResolverFor(const Element* element)
{
// Ideally, returning element->treeScope().scopedStyleResolver() should be
// enough, but ::cue and custom pseudo elements like ::-webkit-meter-bar pierce
- // through a shadow dom boundary, yet they are not part of m_treeBoundaryCrossingRules.
+ // through a shadow dom boundary, yet they are not part of treeBoundaryCrossingRules.
// The assumption here is that these rules only pierce through one boundary and
// that the scope of these elements do not have a style resolver due to the fact
// that VTT scopes and UA shadow trees don't have <style> elements. This is
@@ -385,24 +398,69 @@ static inline ScopedStyleResolver* scopedResolverFor(const Element* element)
void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules)
{
- collector.clearMatchedRules();
collector.matchedResult().ranges.lastAuthorRule = collector.matchedResult().matchedProperties.size() - 1;
- CascadeOrder cascadeOrder = 0;
WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShadowTree;
- collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree);
+ WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInOuterScopes;
+ WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInDistributedScopes;
+
+ collectScopedResolversForHostedShadowTrees(*element, resolversInShadowTree);
+ if (document().styleEngine().hasTreeBoundaryCrossingRules())
+ collectScopedResolversForTreeBoundaryCrossingRules(*element, resolversInOuterScopes, resolversInDistributedScopes);
+
+ // According to the CSS Scoping spec, cascading of rules from inner vs outer scopes happens
+ // such that outer scope rules wins regardless of specificity. For rules from tree-scopes
+ // that do not have an ascendant/descendant relationship in the tree-of-trees (typical for
+ // ::content rules from different scopes during re-distribution), tree-of-trees order of
+ // appearance applies, hence specificity wins although last rule in order of appearance wins
+ // if the specificity is the same.
+ //
+ // The code below uses CascadeOrder which is an order-of-appearance value, and should give
+ // the correct cascading order when order-of-appearance applies.
+ // The "outer scope wins" rule is ensured by calls to sortAndTransferMatchedRules().
+ //
+ // TODO(rune@opera.com): The current implementation does not handle cascading order as
+ // spec'ed for !important rules or multiple shadow trees per host.
// Apply :host and :host-context rules from inner scopes.
- for (int j = resolversInShadowTree.size() - 1; j >= 0; --j)
- resolversInShadowTree.at(j)->collectMatchingShadowHostRules(collector, includeEmptyRules, ++cascadeOrder);
+ if (resolversInShadowTree.size()) {
+ collector.clearMatchedRules();
+ CascadeOrder cascadeOrder = 0;
+ for (int i = resolversInShadowTree.size() - 1; i >= 0; --i)
+ resolversInShadowTree.at(i)->collectMatchingShadowHostRules(collector, includeEmptyRules, ++cascadeOrder);
+ collector.sortAndTransferMatchedRules();
+ }
- // Apply normal rules from element scope.
- if (ScopedStyleResolver* resolver = scopedResolverFor(element))
- resolver->collectMatchingAuthorRules(collector, includeEmptyRules, ++cascadeOrder);
+ // Apply ::content rules from distributed scopes
+ if (resolversInDistributedScopes.size()) {
+ collector.clearMatchedRules();
+ CascadeOrder cascadeOrder = 0;
+ for (int j = resolversInDistributedScopes.size() - 1; j >= 0; --j)
+ resolversInDistributedScopes.at(j)->collectMatchingTreeBoundaryCrossingRules(collector, includeEmptyRules, ++cascadeOrder);
+ collector.sortAndTransferMatchedRules();
+ }
- // Apply /deep/ and ::shadow rules from outer scopes, and ::content from inner.
- m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules);
- collector.sortAndTransferMatchedRules();
+ // Apply rules from the element's scope.
+ if (ScopedStyleResolver* resolver = scopedResolverFor(element)) {
+ collector.clearMatchedRules();
+ resolver->collectMatchingAuthorRules(collector, includeEmptyRules, ignoreCascadeOrder);
+
+ // TODO(rune@opera.com): Only piercing rules, of the boundary crossing rules,
+ // can match elements in the same scope as the rules, thus we can drop the code
+ // below if piercing combinators are removed.
+ if (resolver->hasTreeBoundaryCrossingRules())
+ resolver->collectMatchingTreeBoundaryCrossingRules(collector, includeEmptyRules, ignoreCascadeOrder);
+
+ collector.sortAndTransferMatchedRules();
+ }
+
+ // Apply /deep/ and ::shadow rules from outer scopes.
+ // TODO(rune@opera.com): The code below can be removed if we remove support for shadow piercing selectors.
+ for (unsigned k = 0; k < resolversInOuterScopes.size(); k++) {
+ collector.clearMatchedRules();
+ resolversInOuterScopes.at(k)->collectMatchingTreeBoundaryCrossingRules(collector, includeEmptyRules, ignoreCascadeOrder);
+ collector.sortAndTransferMatchedRules();
+ }
}
void StyleResolver::matchUARules(ElementRuleCollector& collector)
@@ -994,7 +1052,7 @@ bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, const Ele
StyleRuleKeyframes* StyleResolver::findKeyframesRule(const Element* element, const AtomicString& animationName)
{
WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolvers;
- collectScopedResolversForHostedShadowTrees(element, resolvers);
+ collectScopedResolversForHostedShadowTrees(*element, resolvers);
if (ScopedStyleResolver* scopedResolver = element->treeScope().scopedStyleResolver())
resolvers.append(scopedResolver);
@@ -1503,7 +1561,6 @@ DEFINE_TRACE(StyleResolver)
visitor->trace(m_siblingRuleSet);
visitor->trace(m_uncommonAttributeRuleSet);
visitor->trace(m_watchedSelectorsRules);
- visitor->trace(m_treeBoundaryCrossingRules);
visitor->trace(m_styleResourceLoader);
visitor->trace(m_styleSharingLists);
visitor->trace(m_pendingStyleSheets);

Powered by Google App Engine
This is Rietveld 408576698