RenderStyle* SharedStyleFinder::findSharedStyle() { INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleLookups); if (!element().supportsStyleSharing()) return 0; if (attributesAffectedByRules(element())) { INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleRejectedByAttributeRules); return 0; } // Cache whether context.element() is affected by any known class selectors. m_elementAffectedByClassRules = element().hasClass() && classNamesAffectedByRules(element()); m_renderingParent = NodeRenderingTraversal::parent(&element()); Element* shareElement = findElementForStyleSharing(); if (!shareElement) { if (m_styleResolver.stats() && m_styleResolver.stats()->printMissedCandidateCount && documentContainsValidCandidate()) INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleMissed); return 0; } INCREMENT_STYLE_STATS_COUNTER(m_styleResolver, sharedStyleFound); return shareElement->renderStyle(); }
void ElementRuleCollector::collectMatchingRulesForList(const RuleDataListType* rules, CascadeOrder cascadeOrder, const MatchRequest& matchRequest) { if (!rules) return; SelectorChecker::Init init; init.mode = m_mode; init.isUARule = m_matchingUARules; init.elementStyle = m_style.get(); init.scrollbar = m_pseudoStyleRequest.scrollbar; init.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; SelectorChecker checker(init); SelectorChecker::SelectorCheckingContext context(m_context.element(), SelectorChecker::VisitedMatchEnabled); context.scope = matchRequest.scope; context.pseudoId = m_pseudoStyleRequest.pseudoId; unsigned rejected = 0; unsigned fastRejected = 0; unsigned matched = 0; for (const auto& ruleData : *rules) { if (m_canUseFastReject && m_selectorFilter.fastRejectSelector<RuleData::maximumIdentifierCount>(ruleData.descendantSelectorIdentifierHashes())) { fastRejected++; continue; } // FIXME: Exposing the non-standard getMatchedCSSRules API to web is the only reason this is needed. if (m_sameOriginOnly && !ruleData.hasDocumentSecurityOrigin()) continue; StyleRule* rule = ruleData.rule(); // If the rule has no properties to apply, then ignore it in the non-debug mode. const StylePropertySet& properties = rule->properties(); if (properties.isEmpty() && !m_includeEmptyRules) continue; SelectorChecker::MatchResult result; context.selector = &ruleData.selector(); if (!checker.match(context, result)) { rejected++; continue; } if (m_pseudoStyleRequest.pseudoId != PseudoIdNone && m_pseudoStyleRequest.pseudoId != result.dynamicPseudo) { rejected++; continue; } matched++; didMatchRule(ruleData, result, cascadeOrder, matchRequest); } StyleEngine& styleEngine = m_context.element()->document().styleEngine(); if (!styleEngine.stats()) return; INCREMENT_STYLE_STATS_COUNTER(styleEngine, rulesRejected, rejected); INCREMENT_STYLE_STATS_COUNTER(styleEngine, rulesFastRejected, fastRejected); INCREMENT_STYLE_STATS_COUNTER(styleEngine, rulesMatched, matched); }
void StyleResolver::applyMatchedProperties(StyleResolverState& state, const MatchResult& matchResult) { const Element* element = state.element(); ASSERT(element); INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyApply); 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; if (cachedMatchedProperties && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) { INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheHit); // We can build up the style by copying non-inherited properties from an earlier style object built using the same exact // style declarations. We then only need to apply the inherited properties, if any, as their values can depend on the // element context. This is fast and saves memory by reusing the style data structures. state.style()->copyNonInheritedFrom(cachedMatchedProperties->renderStyle.get()); if (state.parentStyle()->inheritedDataShared(cachedMatchedProperties->parentRenderStyle.get()) && (state.style()->userModify() == READ_ONLY)) { INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheInheritedHit); // If the cache item parent style has identical inherited properties to the current parent style then the // resulting style will be identical too. We copy the inherited properties over from the cache and are done. state.style()->inheritFrom(cachedMatchedProperties->renderStyle.get()); return; } applyInheritedOnly = true; } state.setLineHeightValue(0); applyMatchedProperties<HighPriorityProperties>(state, matchResult, applyInheritedOnly); // If our font got dirtied, go ahead and update it now. updateFont(state); // Line-height is set when we are sure we decided on the font-size. if (state.lineHeightValue()) StyleBuilder::applyProperty(CSSPropertyLineHeight, state, state.lineHeightValue()); // Many properties depend on the font. If it changes we just apply all properties. if (cachedMatchedProperties && cachedMatchedProperties->renderStyle->fontDescription() != state.style()->fontDescription()) applyInheritedOnly = false; applyMatchedProperties<LowPriorityProperties>(state, matchResult, applyInheritedOnly); if (!cachedMatchedProperties && cacheHash && MatchedPropertiesCache::isCacheable(element, state.style(), state.parentStyle())) { INCREMENT_STYLE_STATS_COUNTER(*this, matchedPropertyCacheAdded); m_matchedPropertiesCache.add(state.style(), state.parentStyle(), cacheHash, matchResult); } ASSERT(!state.fontBuilder().fontDirty()); }
void StyleResolver::addToStyleSharingList(Element& element) { // Never add elements to the style sharing list if we're not in a recalcStyle, // otherwise we could leave stale pointers in there. if (!m_document.inStyleRecalc()) return; ASSERT(element.supportsStyleSharing()); INCREMENT_STYLE_STATS_COUNTER(*this, sharedStyleCandidates); StyleSharingList& list = styleSharingList(); if (list.size() >= styleSharingListSize) list.removeLast(); list.prepend(&element); }