void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) { FeatureMetadata metadata; bool selectorUsesClassInvalidationSet = false; if (m_targetedStyleRecalcEnabled) selectorUsesClassInvalidationSet = updateClassInvalidationSets(ruleData.selector()); SelectorFeatureCollectionMode collectionMode; if (selectorUsesClassInvalidationSet) collectionMode = DontProcessClasses; else collectionMode = ProcessClasses; collectFeaturesFromSelector(ruleData.selector(), metadata, collectionMode); m_metadata.add(metadata); if (metadata.foundSiblingSelector) siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); if (ruleData.containsUncommonAttributeSelector()) uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); }
static void collectFeaturesFromRuleData(RuleFeatureSet& features, const RuleData& ruleData) { bool foundSiblingSelector = false; for (CSSSelector* selector = ruleData.selector(); selector; selector = selector->tagHistory()) { features.collectFeaturesFromSelector(selector); if (CSSSelectorList* selectorList = selector->selectorList()) { for (CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(subSelector)) { if (!foundSiblingSelector && selector->isSiblingSelector()) foundSiblingSelector = true; features.collectFeaturesFromSelector(subSelector); } } else if (!foundSiblingSelector && selector->isSiblingSelector()) foundSiblingSelector = true; } if (foundSiblingSelector) features.siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); if (ruleData.containsUncommonAttributeSelector()) features.uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); }
void ElementRuleCollector::didMatchRule(const RuleData& ruleData, const SelectorChecker::MatchResult& result, CascadeOrder cascadeOrder, const MatchRequest& matchRequest) { PseudoId dynamicPseudo = result.dynamicPseudo; // If we're matching normal rules, set a pseudo bit if // we really just matched a pseudo-element. if (dynamicPseudo != NOPSEUDO && m_pseudoStyleRequest.pseudoId == NOPSEUDO) { if (m_mode == SelectorChecker::CollectingCSSRules || m_mode == SelectorChecker::CollectingStyleRules) return; // FIXME: Matching should not modify the style directly. if (!m_style || dynamicPseudo >= FIRST_INTERNAL_PSEUDOID) return; if ((dynamicPseudo == BEFORE || dynamicPseudo == AFTER) && !ruleData.rule()->properties().hasProperty(CSSPropertyContent)) return; m_style->setHasPseudoStyle(dynamicPseudo); } else { if (m_style && ruleData.containsUncommonAttributeSelector()) m_style->setUnique(); m_matchedRules.append(MatchedRule(&ruleData, result.specificity, cascadeOrder, matchRequest.styleSheetIndex, matchRequest.styleSheet)); } }
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, unsigned& specificity) { // We know a sufficiently simple single part selector matches simply because we found it from the rule hash when filtering the RuleSet. // This is limited to HTML only so we don't need to check the namespace (because of tag name match). MatchBasedOnRuleHash matchBasedOnRuleHash = ruleData.matchBasedOnRuleHash(); if (matchBasedOnRuleHash != MatchBasedOnRuleHash::None && m_element.isHTMLElement()) { ASSERT_WITH_MESSAGE(m_pseudoStyleRequest.pseudoId == NOPSEUDO, "If we match based on the rule hash while collecting for a particular pseudo element ID, we would add incorrect rules for that pseudo element ID. We should never end in ruleMatches() with a pseudo element if the ruleData cannot match any pseudo element."); switch (matchBasedOnRuleHash) { case MatchBasedOnRuleHash::None: ASSERT_NOT_REACHED(); break; case MatchBasedOnRuleHash::Universal: specificity = 0; break; case MatchBasedOnRuleHash::ClassA: specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassA); break; case MatchBasedOnRuleHash::ClassB: specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassB); break; case MatchBasedOnRuleHash::ClassC: specificity = static_cast<unsigned>(SelectorSpecificityIncrement::ClassC); break; } return true; } #if ENABLE(CSS_SELECTOR_JIT) void* compiledSelectorChecker = ruleData.compiledSelectorCodeRef().code().executableAddress(); if (!compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::NotCompiled) { JSC::VM& vm = m_element.document().scriptExecutionContext()->vm(); SelectorCompilationStatus compilationStatus; JSC::MacroAssemblerCodeRef compiledSelectorCodeRef; compilationStatus = SelectorCompiler::compileSelector(ruleData.selector(), &vm, SelectorCompiler::SelectorContext::RuleCollector, compiledSelectorCodeRef); ruleData.setCompiledSelector(compilationStatus, compiledSelectorCodeRef); compiledSelectorChecker = ruleData.compiledSelectorCodeRef().code().executableAddress(); } if (compiledSelectorChecker && ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) { SelectorCompiler::RuleCollectorSimpleSelectorChecker selectorChecker = SelectorCompiler::ruleCollectorSimpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus()); #if !ASSERT_MSG_DISABLED unsigned ignoreSpecificity; ASSERT_WITH_MESSAGE(!selectorChecker(&m_element, &ignoreSpecificity) || m_pseudoStyleRequest.pseudoId == NOPSEUDO, "When matching pseudo elements, we should never compile a selector checker without context unless it cannot match anything."); #endif #if CSS_SELECTOR_JIT_PROFILING ruleData.compiledSelectorUsed(); #endif bool selectorMatches = selectorChecker(&m_element, &specificity); if (selectorMatches && ruleData.containsUncommonAttributeSelector()) m_didMatchUncommonAttributeSelector = true; return selectorMatches; } #endif // ENABLE(CSS_SELECTOR_JIT) SelectorChecker::CheckingContext context(m_mode); context.pseudoId = m_pseudoStyleRequest.pseudoId; context.scrollbar = m_pseudoStyleRequest.scrollbar; context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; bool selectorMatches; #if ENABLE(CSS_SELECTOR_JIT) if (compiledSelectorChecker) { ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext); SelectorCompiler::RuleCollectorSelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::ruleCollectorSelectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus()); #if CSS_SELECTOR_JIT_PROFILING ruleData.compiledSelectorUsed(); #endif selectorMatches = selectorChecker(&m_element, &context, &specificity); } else #endif // ENABLE(CSS_SELECTOR_JIT) { auto* selector = ruleData.selector(); if (m_isMatchingSlottedPseudoElements) { selector = findSlottedPseudoElementSelector(ruleData.selector()); if (!selector) return false; } // Slow path. SelectorChecker selectorChecker(m_element.document()); selectorMatches = selectorChecker.match(*selector, m_element, context, specificity); } if (ruleData.containsUncommonAttributeSelector()) { if (selectorMatches || context.pseudoIDSet) m_didMatchUncommonAttributeSelector = true; } m_matchedPseudoElementIds.merge(context.pseudoIDSet); m_styleRelations.appendVector(context.styleRelations); return selectorMatches; }