inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const { if (selectorData.isFastCheckable && !element.isSVGElement()) { SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, &element); if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::VisitedMatchDisabled)) return false; return selectorCheckerFastPath.matches(); } SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules); SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorData.selector, &element, SelectorChecker::VisitedMatchDisabled); selectorCheckingContext.scope = rootNode.isDocumentNode() ? nullptr : &rootNode; return selectorChecker.match(selectorCheckingContext); }
inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element& element, const ContainerNode& rootNode) const { if (selectorData.isFastCheckable && !element.isSVGElement()) { SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, element); if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::VisitedMatchDisabled)) return false; return selectorCheckerFastPath.matches(); } SelectorChecker selectorChecker(element.document(), SelectorChecker::QueryingRules); SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorData.selector, &element, SelectorChecker::VisitedMatchDisabled); selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTreeScope; selectorCheckingContext.scope = !rootNode.isDocumentNode() ? &rootNode : 0; return selectorChecker.match(selectorCheckingContext, DOMSiblingTraversalStrategy()) == SelectorChecker::SelectorMatches; }
inline bool SelectorDataList::selectorMatches(const SelectorData& selectorData, Element* element, const Node* rootNode) const { if (selectorData.isFastCheckable && !element->isSVGElement()) { SelectorCheckerFastPath selectorCheckerFastPath(selectorData.selector, element); if (!selectorCheckerFastPath.matchesRightmostSelector(SelectorChecker::VisitedMatchDisabled)) return false; return selectorCheckerFastPath.matches(); } SelectorChecker selectorChecker(element->document(), SelectorChecker::QueryingRules); SelectorChecker::SelectorCheckingContext selectorCheckingContext(selectorData.selector, element, SelectorChecker::VisitedMatchDisabled); selectorCheckingContext.behaviorAtBoundary = SelectorChecker::StaysWithinTreeScope; selectorCheckingContext.scope = !rootNode->isDocumentNode() && rootNode->isContainerNode() ? toContainerNode(rootNode) : 0; PseudoId ignoreDynamicPseudo = NOPSEUDO; return selectorChecker.match(selectorCheckingContext, ignoreDynamicPseudo) == SelectorChecker::SelectorMatches; }
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const ContainerNode* scope, PseudoId& dynamicPseudo, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary) { // They can't match because the fast path uses a pool of tag/class/ids, collected from // elements in that tree and those will never match the host, since it's in a different pool. // So when adding scoped rules to RuleSet, RuleCanUseFastCheckSelector is not used. if (ruleData.hasFastCheckableSelector()) { // We know this selector does not include any pseudo elements. if (m_pseudoStyleRequest.pseudoId != NOPSEUDO) return false; // We know a sufficiently simple single part selector matches simply because we found it from the rule hash. // This is limited to HTML only so we don't need to check the namespace. ASSERT(m_context.element()); if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && m_context.element()->isHTMLElement()) { if (!ruleData.hasMultipartSelector()) return true; } if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(*m_context.element(), ruleData.selector()->tagQName())) return false; SelectorCheckerFastPath selectorCheckerFastPath(ruleData.selector(), *m_context.element()); if (!selectorCheckerFastPath.matchesRightmostAttributeSelector()) return false; return selectorCheckerFastPath.matches(); } // Slow path. SelectorChecker selectorChecker(m_context.element()->document(), m_mode); SelectorChecker::SelectorCheckingContext context(ruleData.selector(), m_context.element(), SelectorChecker::VisitedMatchEnabled); context.elementStyle = m_style.get(); context.scope = scope; context.pseudoId = m_pseudoStyleRequest.pseudoId; context.scrollbar = m_pseudoStyleRequest.scrollbar; context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; context.behaviorAtBoundary = behaviorAtBoundary; SelectorChecker::Match match = selectorChecker.match(context, dynamicPseudo, DOMSiblingTraversalStrategy()); if (match != SelectorChecker::SelectorMatches) return false; if (m_pseudoStyleRequest.pseudoId != NOPSEUDO && m_pseudoStyleRequest.pseudoId != dynamicPseudo) return false; return true; }
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, const ContainerNode* scope, PseudoId& dynamicPseudo) { const StyleResolver::State& state = m_state; if (ruleData.hasFastCheckableSelector()) { // We know this selector does not include any pseudo elements. if (m_pseudoStyleRequest.pseudoId != NOPSEUDO) return false; // We know a sufficiently simple single part selector matches simply because we found it from the rule hash. // This is limited to HTML only so we don't need to check the namespace. if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && state.element()->isHTMLElement()) { if (!ruleData.hasMultipartSelector()) return true; } if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(state.element(), ruleData.selector()->tagQName())) return false; SelectorCheckerFastPath selectorCheckerFastPath(ruleData.selector(), state.element()); if (!selectorCheckerFastPath.matchesRightmostAttributeSelector()) return false; return selectorCheckerFastPath.matches(); } // Slow path. SelectorChecker selectorChecker(document(), m_mode); SelectorChecker::SelectorCheckingContext context(ruleData.selector(), state.element(), SelectorChecker::VisitedMatchEnabled); context.elementStyle = state.style(); context.scope = scope; context.pseudoId = m_pseudoStyleRequest.pseudoId; context.scrollbar = m_pseudoStyleRequest.scrollbar; context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; context.behaviorAtBoundary = m_behaviorAtBoundary; SelectorChecker::Match match = selectorChecker.match(context, dynamicPseudo); if (match != SelectorChecker::SelectorMatches) return false; if (m_pseudoStyleRequest.pseudoId != NOPSEUDO && m_pseudoStyleRequest.pseudoId != dynamicPseudo) return false; return true; }
inline bool ElementRuleCollector::ruleMatches(const RuleData& ruleData, PseudoId& dynamicPseudo) { bool fastCheckableSelector = ruleData.hasFastCheckableSelector(); if (fastCheckableSelector) { // We know this selector does not include any pseudo elements. if (m_pseudoStyleRequest.pseudoId != NOPSEUDO) return false; // We know a sufficiently simple single part selector matches simply because we found it from the rule hash. // This is limited to HTML only so we don't need to check the namespace. if (ruleData.hasRightmostSelectorMatchingHTMLBasedOnRuleHash() && m_element.isHTMLElement()) { if (!ruleData.hasMultipartSelector()) 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) { if (m_pseudoStyleRequest.pseudoId != NOPSEUDO) return false; if (ruleData.compilationStatus() == SelectorCompilationStatus::SimpleSelectorChecker) { SelectorCompiler::SimpleSelectorChecker selectorChecker = SelectorCompiler::simpleSelectorCheckerFunction(compiledSelectorChecker, ruleData.compilationStatus()); return selectorChecker(&m_element); } ASSERT(ruleData.compilationStatus() == SelectorCompilationStatus::SelectorCheckerWithCheckingContext); SelectorCompiler::SelectorCheckerWithCheckingContext selectorChecker = SelectorCompiler::selectorCheckerFunctionWithCheckingContext(compiledSelectorChecker, ruleData.compilationStatus()); SelectorCompiler::CheckingContext context; context.elementStyle = m_style; context.resolvingMode = m_mode; return selectorChecker(&m_element, &context); } #endif // ENABLE(CSS_SELECTOR_JIT) if (fastCheckableSelector) { if (ruleData.selector()->m_match == CSSSelector::Tag && !SelectorChecker::tagMatches(&m_element, ruleData.selector()->tagQName())) return false; SelectorCheckerFastPath selectorCheckerFastPath(ruleData.selector(), &m_element); if (!selectorCheckerFastPath.matchesRightmostAttributeSelector()) return false; return selectorCheckerFastPath.matches(); } // Slow path. SelectorChecker selectorChecker(m_element.document(), m_mode); SelectorChecker::SelectorCheckingContext context(ruleData.selector(), &m_element, SelectorChecker::VisitedMatchEnabled); context.elementStyle = m_style; context.pseudoId = m_pseudoStyleRequest.pseudoId; context.scrollbar = m_pseudoStyleRequest.scrollbar; context.scrollbarPart = m_pseudoStyleRequest.scrollbarPart; if (!selectorChecker.match(context, dynamicPseudo)) return false; if (m_pseudoStyleRequest.pseudoId != NOPSEUDO && m_pseudoStyleRequest.pseudoId != dynamicPseudo) return false; return true; }