static inline MatchBasedOnRuleHash computeMatchBasedOnRuleHash(const CSSSelector& selector) { if (selector.tagHistory()) return MatchBasedOnRuleHash::None; if (selector.match() == CSSSelector::Tag) { const QualifiedName& tagQualifiedName = selector.tagQName(); const AtomicString& selectorNamespace = tagQualifiedName.namespaceURI(); if (selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI) { if (tagQualifiedName == anyQName()) return MatchBasedOnRuleHash::Universal; return MatchBasedOnRuleHash::ClassC; } return MatchBasedOnRuleHash::None; } if (SelectorChecker::isCommonPseudoClassSelector(&selector)) return MatchBasedOnRuleHash::ClassB; #if ENABLE(SHADOW_DOM) if (selector.match() == CSSSelector::PseudoClass && selector.pseudoClassType() == CSSSelector::PseudoClassHost) return MatchBasedOnRuleHash::ClassB; #endif if (selector.match() == CSSSelector::Id) return MatchBasedOnRuleHash::ClassA; if (selector.match() == CSSSelector::Class) return MatchBasedOnRuleHash::ClassB; return MatchBasedOnRuleHash::None; }
static inline bool isSelectorMatchingHTMLBasedOnRuleHash(const CSSSelector& selector) { if (selector.match() == CSSSelector::Tag) { const AtomicString& selectorNamespace = selector.tagQName().namespaceURI(); if (selectorNamespace != starAtom && selectorNamespace != xhtmlNamespaceURI) return false; if (selector.relation() == CSSSelector::SubSelector) { ASSERT(selector.tagHistory()); return isSelectorMatchingHTMLBasedOnRuleHash(*selector.tagHistory()); } return true; } if (SelectorChecker::isCommonPseudoClassSelector(selector)) return true; return selector.match() == CSSSelector::Id || selector.match() == CSSSelector::Class; }
static bool determineSelectorScopes(const CSSSelectorList& selectorList, HashSet<AtomicStringImpl*>& idScopes, HashSet<AtomicStringImpl*>& classScopes) { for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) { CSSSelector* scopeSelector = 0; // This picks the widest scope, not the narrowest, to minimize the number of found scopes. for (CSSSelector* current = selector; current; current = current->tagHistory()) { // Prefer ids over classes. if (current->m_match == CSSSelector::Id) scopeSelector = current; else if (current->m_match == CSSSelector::Class && (!scopeSelector || scopeSelector->m_match != CSSSelector::Id)) scopeSelector = current; CSSSelector::Relation relation = current->relation(); if (relation != CSSSelector::Descendant && relation != CSSSelector::Child && relation != CSSSelector::SubSelector) break; } if (!scopeSelector) return false; ASSERT(scopeSelector->m_match == CSSSelector::Class || scopeSelector->m_match == CSSSelector::Id); if (scopeSelector->m_match == CSSSelector::Id) idScopes.add(scopeSelector->value().impl()); else classScopes.add(scopeSelector->value().impl()); } return true; }
static unsigned selectorSpecificity(const CSSSelector& firstSimpleSelector, bool isComputingMaximumSpecificity) { unsigned total = simpleSelectorSpecificityInternal(firstSimpleSelector, isComputingMaximumSpecificity); for (const CSSSelector* selector = firstSimpleSelector.tagHistory(); selector; selector = selector->tagHistory()) total = CSSSelector::addSpecificities(total, simpleSelectorSpecificityInternal(*selector, isComputingMaximumSpecificity)); return total; }
void SelectorFilter::collectIdentifierHashes(const CSSSelector& selector, unsigned* identifierHashes, unsigned maximumIdentifierCount) { unsigned* hash = identifierHashes; unsigned* end = identifierHashes + maximumIdentifierCount; CSSSelector::RelationType relation = selector.relation(); if (selector.relationIsAffectedByPseudoContent()) { // Disable fastRejectSelector. *identifierHashes = 0; return; } // Skip the topmost selector. It is handled quickly by the rule hashes. bool skipOverSubselectors = true; for (const CSSSelector* current = selector.tagHistory(); current; current = current->tagHistory()) { // Only collect identifiers that match ancestors. switch (relation) { case CSSSelector::SubSelector: if (!skipOverSubselectors) collectDescendantSelectorIdentifierHashes(*current, hash); break; case CSSSelector::DirectAdjacent: case CSSSelector::IndirectAdjacent: skipOverSubselectors = true; break; case CSSSelector::ShadowSlot: // Disable fastRejectSelector. *identifierHashes = 0; return; case CSSSelector::Descendant: case CSSSelector::Child: // Fall through. case CSSSelector::ShadowPseudo: case CSSSelector::ShadowDeep: skipOverSubselectors = false; collectDescendantSelectorIdentifierHashes(*current, hash); break; } if (hash == end) return; relation = current->relation(); if (current->relationIsAffectedByPseudoContent()) { // Disable fastRejectSelector. *identifierHashes = 0; return; } } *hash = 0; }
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())); }
static bool validateSelector(CSSSelector* selector) { ASSERT(selector); if (!validateSubSelector(selector)) return false; CSSSelector* prevSubSelector = selector; CSSSelector* subSelector = selector->tagHistory(); while (subSelector) { if (prevSubSelector->relation() != CSSSelector::SubSelector) return false; if (!validateSubSelector(subSelector)) return false; prevSubSelector = subSelector; subSelector = subSelector->tagHistory(); } return true; }