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; }
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 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 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; }
bool operator()(const CSSSelector& selector) { return selector.relation() == CSSSelector::ShadowDeep || selector.isShadowPseudoElement(); }