Chromium Code Reviews| Index: Source/core/css/resolver/StyleResolver.cpp |
| diff --git a/Source/core/css/resolver/StyleResolver.cpp b/Source/core/css/resolver/StyleResolver.cpp |
| index 57f33842d5b36cd49c3ec1a293008548b1376e85..467daa83a4547fb4ceec5602f2ee7f9079fab59a 100644 |
| --- a/Source/core/css/resolver/StyleResolver.cpp |
| +++ b/Source/core/css/resolver/StyleResolver.cpp |
| @@ -123,21 +123,6 @@ static StylePropertySet* rightToLeftDeclaration() |
| return rightToLeftDecl; |
| } |
| -static void collectScopedResolversForHostedShadowTrees(const Element* element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolvers) |
| -{ |
| - ElementShadow* shadow = element->shadow(); |
| - if (!shadow) |
| - return; |
| - |
| - // Adding scoped resolver for active shadow roots for shadow host styling. |
| - for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) { |
| - if (shadowRoot->numberOfStyles() > 0) { |
| - if (ScopedStyleResolver* resolver = shadowRoot->scopedStyleResolver()) |
| - resolvers.append(resolver); |
| - } |
| - } |
| -} |
| - |
| StyleResolver::StyleResolver(Document& document) |
| : m_document(document) |
| , m_viewportStyleResolver(ViewportStyleResolver::create(&document)) |
| @@ -237,12 +222,12 @@ void StyleResolver::resetRuleFeatures() |
| void StyleResolver::addTreeBoundaryCrossingScope(ContainerNode& scope) |
| { |
| - m_treeBoundaryCrossingRules.addScope(scope); |
| + m_treeBoundaryCrossingScopes.add(&scope); |
| } |
| void StyleResolver::resetAuthorStyle(TreeScope& treeScope) |
| { |
| - m_treeBoundaryCrossingRules.removeScope(treeScope.rootNode()); |
| + m_treeBoundaryCrossingScopes.remove(&treeScope.rootNode()); |
| ScopedStyleResolver* resolver = treeScope.scopedStyleResolver(); |
| if (!resolver) |
| @@ -343,11 +328,11 @@ StyleResolver::~StyleResolver() |
| { |
| } |
| -static inline ScopedStyleResolver* scopedResolverFor(const Element* element) |
| +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 m_treeBoundaryCrossingScopes. |
| // 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 |
| @@ -356,40 +341,82 @@ static inline ScopedStyleResolver* scopedResolverFor(const Element* element) |
| // FIXME: Make ::cue and custom pseudo elements part of boundary crossing rules |
| // when moving those rules to ScopedStyleResolver as part of issue 401359. |
| - TreeScope* treeScope = &element->treeScope(); |
| + TreeScope* treeScope = &element.treeScope(); |
| if (ScopedStyleResolver* resolver = treeScope->scopedStyleResolver()) { |
| - ASSERT(element->shadowPseudoId().isEmpty()); |
| - ASSERT(!element->isVTTElement()); |
| + ASSERT(element.shadowPseudoId().isEmpty()); |
| + ASSERT(!element.isVTTElement()); |
| return resolver; |
| } |
| treeScope = treeScope->parentTreeScope(); |
| if (!treeScope) |
| return nullptr; |
| - if (element->shadowPseudoId().isEmpty() && !element->isVTTElement()) |
| + if (element.shadowPseudoId().isEmpty() && !element.isVTTElement()) |
| return nullptr; |
| return treeScope->scopedStyleResolver(); |
| } |
| -void StyleResolver::matchAuthorRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) |
| +void StyleResolver::matchHostRules(const Element& element, ElementRuleCollector& collector, bool includeEmptyRules) |
| { |
| - collector.clearMatchedRules(); |
| + ElementShadow* shadow = element.shadow(); |
| + if (!shadow) |
| + return; |
| - CascadeOrder cascadeOrder = 0; |
| - WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8> resolversInShadowTree; |
| - collectScopedResolversForHostedShadowTrees(element, resolversInShadowTree); |
| + // Adding scoped resolvers for active shadow roots for shadow host styling. |
| + for (ShadowRoot* shadowRoot = shadow->oldestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->youngerShadowRoot()) { |
| + if (!shadowRoot->numberOfStyles()) |
| + continue; |
| + if (ScopedStyleResolver* resolver = shadowRoot->scopedStyleResolver()) { |
| + collector.clearMatchedRules(); |
| + resolver->collectMatchingShadowHostRules(collector, includeEmptyRules); |
| + collector.sortAndTransferMatchedRules(); |
| + collector.closeOriginOrScope(); |
| + } |
| + } |
| +} |
| - // 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); |
| +ScopedStyleResolver* StyleResolver::matchElementScopeRules(const Element& element, ElementRuleCollector& collector, bool includeEmptyRules) |
|
kochi
2015/08/10 12:15:03
Can this be a static function, rather than a priva
|
| +{ |
| + ScopedStyleResolver* resolver = scopedResolverFor(element); |
| + if (resolver) { |
| + collector.clearMatchedRules(); |
| + resolver->collectMatchingAuthorRules(collector, includeEmptyRules); |
| + resolver->collectMatchingTreeBoundaryCrossingRules(collector, includeEmptyRules); |
| + collector.sortAndTransferMatchedRules(); |
| + } |
| + collector.closeOriginOrScope(); |
| + return resolver; |
| +} |
| - // Apply normal rules from element scope. |
| - if (ScopedStyleResolver* resolver = scopedResolverFor(element)) |
| - resolver->collectMatchingAuthorRules(collector, includeEmptyRules, ++cascadeOrder); |
| +void StyleResolver::matchScopedRules(const Element& element, ElementRuleCollector& collector, bool includeEmptyRules) |
| +{ |
| + bool matchElementScope = true; |
| - // Apply /deep/ and ::shadow rules from outer scopes, and ::content from inner. |
| - m_treeBoundaryCrossingRules.collectTreeBoundaryCrossingRules(element, collector, includeEmptyRules); |
| - collector.sortAndTransferMatchedRules(); |
| + for (auto it = m_treeBoundaryCrossingScopes.rbegin(); it != m_treeBoundaryCrossingScopes.rend(); ++it) { |
| + const TreeScope& scope = (*it)->treeScope(); |
| + ScopedStyleResolver* resolver = scope.scopedStyleResolver(); |
| + ASSERT(resolver); |
| + |
| + if (matchElementScope && scope.isInclusiveAncestorOf(element.treeScope())) { |
| + matchElementScope = false; |
| + if (matchElementScopeRules(element, collector, includeEmptyRules) == resolver) |
| + continue; |
| + } |
| + |
| + collector.clearMatchedRules(); |
| + resolver->collectMatchingTreeBoundaryCrossingRules(collector, includeEmptyRules); |
| + collector.sortAndTransferMatchedRules(); |
| + collector.closeOriginOrScope(); |
| + } |
| + |
| + if (matchElementScope) |
| + matchElementScopeRules(element, collector, includeEmptyRules); |
| +} |
| + |
| +void StyleResolver::matchAuthorRules(const Element& element, ElementRuleCollector& collector, bool includeEmptyRules) |
| +{ |
| + matchHostRules(element, collector, includeEmptyRules); |
| + matchScopedRules(element, collector, includeEmptyRules); |
| } |
| void StyleResolver::matchUARules(ElementRuleCollector& collector) |
| @@ -408,6 +435,7 @@ void StyleResolver::matchUARules(ElementRuleCollector& collector) |
| if (document().isViewSource()) |
| matchRuleSet(collector, defaultStyleSheets.defaultViewSourceStyle()); |
| + collector.closeOriginOrScope(); |
| collector.setMatchingUARules(false); |
| } |
| @@ -416,6 +444,7 @@ void StyleResolver::matchRuleSet(ElementRuleCollector& collector, RuleSet* rules |
| collector.clearMatchedRules(); |
| collector.collectMatchingRules(MatchRequest(rules)); |
| collector.sortAndTransferMatchedRules(); |
| + collector.closeOriginOrScope(); |
| } |
| void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollector& collector, bool includeSMILProperties) |
| @@ -441,9 +470,15 @@ void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollecto |
| } |
| } |
| - matchAuthorRules(state.element(), collector, false); |
| + matchAuthorRules(*state.element(), collector, false); |
| if (state.element()->isStyledElement()) { |
| + // TODO(rune@opera.com): Adding style attribute rules here is probably too late |
| + // when you have shadow piercing combinators. When we don't have piercing combinators, |
| + // the style attribute always belong to the outermost scope whose rules apply to |
| + // the element. Thus, applying inline style here is correct. Fixing this for piercing |
| + // combinators means moving the code below into matchElementScopeRules and _not_ |
| + // invoking it for pseudo style requests. |
| if (state.element()->inlineStyle()) { |
| // Inline style is immutable as long as there is no CSSOM wrapper. |
| bool isInlineStyleCacheable = !state.element()->inlineStyle()->isMutable(); |
| @@ -453,6 +488,8 @@ void StyleResolver::matchAllRules(StyleResolverState& state, ElementRuleCollecto |
| // Now check SMIL animation override style. |
| if (includeSMILProperties && state.element()->isSVGElement()) |
| collector.addElementStyleProperties(toSVGElement(state.element())->animatedSMILStyleProperties(), false /* isCacheable */); |
| + |
| + collector.closeOriginOrScope(); |
| } |
| } |
| @@ -747,9 +784,9 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo |
| collector.setPseudoStyleRequest(pseudoStyleRequest); |
| matchUARules(collector); |
| - matchAuthorRules(state.element(), collector, false); |
| + matchAuthorRules(*state.element(), collector, false); |
| - if (collector.matchedResult().matchedProperties.isEmpty()) |
| + if (!collector.matchedResult().hasMatchedProperties()) |
| return false; |
| applyMatchedProperties(state, collector.matchedResult()); |
| @@ -822,12 +859,12 @@ PassRefPtr<ComputedStyle> StyleResolver::styleForPage(int pageIndex) |
| bool inheritedOnly = false; |
| const MatchResult& result = collector.matchedResult(); |
| - applyMatchedProperties<HighPropertyPriority>(state, result, false, result.begin(), result.end(), inheritedOnly); |
| + applyMatchedProperties<HighPropertyPriority>(state, result.allRules(), false, inheritedOnly); |
| // If our font got dirtied, go ahead and update it now. |
| updateFont(state); |
| - applyMatchedProperties<LowPropertyPriority>(state, result, false, result.begin(), result.end(), inheritedOnly); |
| + applyMatchedProperties<LowPropertyPriority>(state, result.allRules(), false, inheritedOnly); |
| loadPendingResources(state); |
| @@ -897,7 +934,7 @@ void StyleResolver::collectPseudoRulesForElement(Element* element, ElementRuleCo |
| if (rulesToInclude & AuthorCSSRules) { |
| collector.setSameOriginOnly(!(rulesToInclude & CrossOriginCSSRules)); |
| - matchAuthorRules(element, collector, rulesToInclude & EmptyCSSRules); |
| + matchAuthorRules(*element, collector, rulesToInclude & EmptyCSSRules); |
| } |
| } |
| @@ -940,10 +977,25 @@ bool StyleResolver::applyAnimatedProperties(StyleResolverState& state, const Ele |
| return true; |
| } |
| +static void collectScopedResolversForHostedShadowTrees(const Element& element, WillBeHeapVector<RawPtrWillBeMember<ScopedStyleResolver>, 8>& resolvers) |
| +{ |
| + ElementShadow* shadow = element.shadow(); |
| + if (!shadow) |
| + return; |
| + |
| + // Adding scoped resolver for active shadow roots for shadow host styling. |
| + for (ShadowRoot* shadowRoot = shadow->youngestShadowRoot(); shadowRoot; shadowRoot = shadowRoot->olderShadowRoot()) { |
| + if (shadowRoot->numberOfStyles() > 0) { |
| + if (ScopedStyleResolver* resolver = shadowRoot->scopedStyleResolver()) |
| + resolvers.append(resolver); |
| + } |
| + } |
| +} |
| + |
| 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); |
| @@ -1225,16 +1277,13 @@ void StyleResolver::applyProperties(StyleResolverState& state, const StyleProper |
| } |
| template <CSSPropertyPriority priority> |
| -void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult, bool isImportant, unsigned startIndex, unsigned endIndex, bool inheritedOnly) |
| +void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchedPropertiesRange& range, bool isImportant, bool inheritedOnly) |
| { |
| - if (startIndex == endIndex) |
| + if (range.begin() == range.end()) |
| return; |
| - ASSERT_WITH_SECURITY_IMPLICATION(endIndex <= matchResult.matchedProperties.size()); |
| - |
| if (state.style()->insideLink() != NotInsideLink) { |
| - for (unsigned i = startIndex; i < endIndex; ++i) { |
| - const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; |
| + for (const auto& matchedProperties : range) { |
| unsigned linkMatchType = matchedProperties.m_types.linkMatchType; |
| // FIXME: It would be nicer to pass these as arguments but that requires changes in many places. |
| state.setApplyPropertyToRegularStyle(linkMatchType & CSSSelector::MatchLink); |
| @@ -1246,10 +1295,8 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc |
| state.setApplyPropertyToVisitedLinkStyle(false); |
| return; |
| } |
| - for (unsigned i = startIndex; i < endIndex; ++i) { |
| - const MatchedProperties& matchedProperties = matchResult.matchedProperties[i]; |
| + for (const auto& matchedProperties : range) |
| applyProperties<priority>(state, matchedProperties.properties.get(), isImportant, inheritedOnly, static_cast<PropertyWhitelistType>(matchedProperties.m_types.whitelistType)); |
| - } |
| } |
| static unsigned computeMatchedPropertiesHash(const MatchedProperties* properties, unsigned size) |
| @@ -1275,9 +1322,9 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc |
| INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply, 1); |
| - unsigned cacheHash = matchResult.isCacheable ? computeMatchedPropertiesHash(matchResult.matchedProperties.data(), matchResult.matchedProperties.size()) : 0; |
| + unsigned cacheHash = matchResult.isCacheable() ? computeMatchedPropertiesHash(matchResult.matchedProperties().data(), matchResult.matchedProperties().size()) : 0; |
| bool applyInheritedOnly = false; |
| - const CachedMatchedProperties* cachedMatchedProperties = cacheHash ? m_matchedPropertiesCache.find(cacheHash, state, matchResult) : 0; |
| + const CachedMatchedProperties* cachedMatchedProperties = cacheHash ? m_matchedPropertiesCache.find(cacheHash, state, matchResult.matchedProperties()) : 0; |
| if (cachedMatchedProperties && MatchedPropertiesCache::isCacheable(element, *state.style(), *state.parentStyle())) { |
| INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit, 1); |
| @@ -1308,9 +1355,10 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc |
| // high-priority properties first, i.e., those properties that other properties depend on. |
| // The order is (1) high-priority not important, (2) high-priority important, (3) normal not important |
| // and (4) normal important. |
| - applyMatchedProperties<HighPropertyPriority>(state, matchResult, false, matchResult.begin(), matchResult.end(), applyInheritedOnly); |
| - applyMatchedProperties<HighPropertyPriority>(state, matchResult, true, matchResult.beginAuthor(), matchResult.endAuthor(), applyInheritedOnly); |
| - applyMatchedProperties<HighPropertyPriority>(state, matchResult, true, matchResult.beginUA(), matchResult.endUA(), applyInheritedOnly); |
| + applyMatchedProperties<HighPropertyPriority>(state, matchResult.allRules(), false, applyInheritedOnly); |
| + for (auto range : ImportantAuthorRanges(matchResult)) |
| + applyMatchedProperties<HighPropertyPriority>(state, range, true, applyInheritedOnly); |
| + applyMatchedProperties<HighPropertyPriority>(state, matchResult.uaRules(), true, applyInheritedOnly); |
| if (UNLIKELY(isSVGForeignObjectElement(element))) { |
| // LayoutSVGRoot handles zooming for the whole SVG subtree, so foreignObject content should not be scaled again. |
| @@ -1336,21 +1384,22 @@ void StyleResolver::applyMatchedProperties(StyleResolverState& state, const Matc |
| applyInheritedOnly = false; |
| // Now do the normal priority UA properties. |
| - applyMatchedProperties<LowPropertyPriority>(state, matchResult, false, matchResult.beginUA(), matchResult.endUA(), applyInheritedOnly); |
| + applyMatchedProperties<LowPropertyPriority>(state, matchResult.uaRules(), false, applyInheritedOnly); |
| // Cache the UA properties to pass them to LayoutTheme in adjustComputedStyle. |
| state.cacheUserAgentBorderAndBackground(); |
| // Now do the author and user normal priority properties and all the !important properties. |
| - applyMatchedProperties<LowPropertyPriority>(state, matchResult, false, matchResult.beginAuthor(), matchResult.endAuthor(), applyInheritedOnly); |
| - applyMatchedProperties<LowPropertyPriority>(state, matchResult, true, matchResult.beginAuthor(), matchResult.endAuthor(), applyInheritedOnly); |
| - applyMatchedProperties<LowPropertyPriority>(state, matchResult, true, matchResult.beginUA(), matchResult.endUA(), applyInheritedOnly); |
| + applyMatchedProperties<LowPropertyPriority>(state, matchResult.authorRules(), false, applyInheritedOnly); |
| + for (auto range : ImportantAuthorRanges(matchResult)) |
| + applyMatchedProperties<LowPropertyPriority>(state, range, true, applyInheritedOnly); |
| + applyMatchedProperties<LowPropertyPriority>(state, matchResult.uaRules(), true, applyInheritedOnly); |
| loadPendingResources(state); |
| if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, *state.style(), *state.parentStyle())) { |
| INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded, 1); |
| - m_matchedPropertiesCache.add(*state.style(), *state.parentStyle(), cacheHash, matchResult); |
| + m_matchedPropertiesCache.add(*state.style(), *state.parentStyle(), cacheHash, matchResult.matchedProperties()); |
| } |
| ASSERT(!state.fontBuilder().fontDirty()); |
| @@ -1437,7 +1486,7 @@ DEFINE_TRACE(StyleResolver) |
| visitor->trace(m_siblingRuleSet); |
| visitor->trace(m_uncommonAttributeRuleSet); |
| visitor->trace(m_watchedSelectorsRules); |
| - visitor->trace(m_treeBoundaryCrossingRules); |
| + visitor->trace(m_treeBoundaryCrossingScopes); |
| visitor->trace(m_styleResourceLoader); |
| visitor->trace(m_styleSharingLists); |
| visitor->trace(m_pendingStyleSheets); |