| 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);
|
|
|