bool SelectorChecker::checkOne(const CSSSelector& selector) { switch (selector.match()) { case CSSSelector::Tag: { const AtomicString& localName = selector.tagQName().localName(); return localName == starAtom || localName == m_element.localName(); } case CSSSelector::Class: return m_element.hasClass() && m_element.classNames().contains(selector.value()); case CSSSelector::Id: return m_element.hasID() && m_element.idForStyleResolution() == selector.value(); case CSSSelector::Exact: case CSSSelector::Set: if (anyAttributeMatches(m_element, selector.match(), selector)) { m_matchedAttributeSelector = true; return true; } return false; case CSSSelector::PseudoClass: return checkPseudoClass(selector); // FIXME(sky): Remove pseudo elements completely. case CSSSelector::PseudoElement: case CSSSelector::Unknown: return false; } ASSERT_NOT_REACHED(); return false; }
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.tagHistory()) return false; if (selector.match() == CSSSelector::Tag) { const AtomicString& selectorNamespace = selector.tagQName().namespaceURI(); return selectorNamespace == starAtom || selectorNamespace == xhtmlNamespaceURI; } if (SelectorChecker::isCommonPseudoClassSelector(&selector)) return true; return selector.match() == CSSSelector::Id || selector.match() == CSSSelector::Class; }
static unsigned simpleSelectorFunctionalPseudoClassStaticSpecificity(const CSSSelector& simpleSelector, bool& ok) { if (simpleSelector.match() == CSSSelector::PseudoClass) { CSSSelector::PseudoClassType pseudoClassType = simpleSelector.pseudoClassType(); if (pseudoClassType == CSSSelector::PseudoClassMatches || pseudoClassType == CSSSelector::PseudoClassNthChild || pseudoClassType == CSSSelector::PseudoClassNthLastChild) { const CSSSelectorList* selectorList = simpleSelector.selectorList(); if (!selectorList) { ASSERT_WITH_MESSAGE(pseudoClassType != CSSSelector::PseudoClassMatches, ":matches() should never be created without a valid selector list."); return 0; } const CSSSelector& firstSubselector = *selectorList->first(); unsigned initialSpecificity = staticSpecificityInternal(firstSubselector, ok); if (!ok) return 0; const CSSSelector* subselector = &firstSubselector; while ((subselector = CSSSelectorList::next(subselector))) { unsigned subSelectorSpecificity = staticSpecificityInternal(*subselector, ok); if (initialSpecificity != subSelectorSpecificity) ok = false; if (!ok) return 0; } return initialSpecificity; } } return 0; }
bool operator()(const CSSSelector& selector) { if (selector.match() == CSSSelector::Tag && selector.tagQName().prefix() != nullAtom && selector.tagQName().prefix() != starAtom) return true; if (selector.isAttributeSelector() && selector.attribute().prefix() != nullAtom && selector.attribute().prefix() != starAtom) return true; return false; }
static inline bool includesDisallowedPseudoClass(const CSSSelector& selector) { if (selector.pseudoType() == CSSSelector::PseudoNot) { const CSSSelector* subSelector = selector.selectorList()->first(); return subSelector->match() == CSSSelector::PseudoClass; } return selector.match() == CSSSelector::PseudoClass; }
bool RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features) { if (selector.match() == CSSSelector::Tag && selector.tagQName().localName() != starAtom) features.tagName = selector.tagQName().localName(); else if (selector.match() == CSSSelector::Id) features.id = selector.value(); else if (selector.match() == CSSSelector::Class) features.classes.append(selector.value()); else if (selector.isAttributeSelector()) features.attributes.append(selector.attribute().localName()); else if (selector.pseudoType() == CSSSelector::PseudoWebKitCustomElement) features.customPseudoElement = true; else if (selector.pseudoType() == CSSSelector::PseudoBefore || selector.pseudoType() == CSSSelector::PseudoAfter) features.hasBeforeOrAfter = true; else return false; return true; }
static bool requiresSubtreeInvalidation(const CSSSelector& selector) { if (selector.match() != CSSSelector::PseudoElement && selector.match() != CSSSelector::PseudoClass) { ASSERT(supportsInvalidation(selector.match())); return false; } switch (selector.pseudoType()) { case CSSSelector::PseudoFirstLine: case CSSSelector::PseudoFirstLetter: // FIXME: Most pseudo classes/elements above can be supported and moved // to assertSupportedPseudo(). Move on a case-by-case basis. If they // require subtree invalidation, document why. case CSSSelector::PseudoHostContext: // :host-context matches a shadow host, yet the simple selectors inside // :host-context matches an ancestor of the shadow host. return true; default: ASSERT(supportsInvalidation(selector.pseudoType())); return false; } }
static inline void collectDescendantSelectorIdentifierHashes(const CSSSelector& selector, unsigned*& hash) { switch (selector.match()) { case CSSSelector::Id: if (!selector.value().isEmpty()) (*hash++) = selector.value().impl()->existingHash() * IdAttributeSalt; break; case CSSSelector::Class: if (!selector.value().isEmpty()) (*hash++) = selector.value().impl()->existingHash() * ClassAttributeSalt; break; case CSSSelector::Tag: if (selector.tagQName().localName() != starAtom) (*hash++) = selector.tagQName().localName().impl()->existingHash() * TagNameSalt; break; default: break; } }
static unsigned simpleSelectorSpecificityInternal(const CSSSelector& simpleSelector, bool isComputingMaximumSpecificity) { ASSERT_WITH_MESSAGE(!simpleSelector.isForPage(), "At the time of this writing, page selectors are not treated as real selectors that are matched. The value computed here only account for real selectors."); switch (simpleSelector.match()) { case CSSSelector::Id: return static_cast<unsigned>(SelectorSpecificityIncrement::ClassA); case CSSSelector::PagePseudoClass: break; case CSSSelector::PseudoClass: if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassMatches) { ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :matches()."); if (!isComputingMaximumSpecificity) return 0; return maxSpecificity(*simpleSelector.selectorList()); } if (simpleSelector.pseudoClassType() == CSSSelector::PseudoClassNot) { ASSERT_WITH_MESSAGE(simpleSelector.selectorList() && simpleSelector.selectorList()->first(), "The parser should never generate a valid selector for an empty :not()."); return maxSpecificity(*simpleSelector.selectorList()); } FALLTHROUGH; case CSSSelector::Exact: case CSSSelector::Class: case CSSSelector::Set: case CSSSelector::List: case CSSSelector::Hyphen: case CSSSelector::Contain: case CSSSelector::Begin: case CSSSelector::End: return static_cast<unsigned>(SelectorSpecificityIncrement::ClassB); case CSSSelector::Tag: return (simpleSelector.tagQName().localName() != starAtom) ? static_cast<unsigned>(SelectorSpecificityIncrement::ClassC) : 0; case CSSSelector::PseudoElement: return static_cast<unsigned>(SelectorSpecificityIncrement::ClassC); case CSSSelector::Unknown: return 0; } ASSERT_NOT_REACHED(); return 0; }
static bool canBeUsedForIdFastPath(const CSSSelector& selector) { return selector.match() == CSSSelector::Id || (selector.match() == CSSSelector::Exact && selector.attribute() == HTMLNames::idAttr && !selector.attributeValueMatchingIsCaseInsensitive()); }
static bool isSingleClassNameSelector(const CSSSelector& selector) { return selector.isLastInTagHistory() && selector.match() == CSSSelector::Class; }
static inline bool includesDisallowedPseudoClass(const CSSSelector& selector) { return selector.match() == CSSSelector::PseudoClass; }
static RuleFeatureSet::AttributeRules::SelectorKey makeAttributeSelectorKey(const CSSSelector& selector) { bool caseInsensitive = selector.attributeValueMatchingIsCaseInsensitive(); unsigned matchAndCase = static_cast<unsigned>(selector.match()) << 1 | (caseInsensitive ? 1 : 0); return std::make_pair(selector.attributeCanonicalLocalName().impl(), std::make_pair(selector.value().impl(), matchAndCase)); }