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; } }
bool SelectorChecker::checkPseudoClass(const CSSSelector& selector) { switch (selector.pseudoType()) { case CSSSelector::PseudoFocus: m_matchedFocusSelector = true; return matchesFocusPseudoClass(m_element); case CSSSelector::PseudoHover: m_matchedHoverSelector = true; return m_element.hovered(); case CSSSelector::PseudoActive: m_matchedActiveSelector = true; return m_element.active(); case CSSSelector::PseudoLang: { AtomicString value = m_element.computeInheritedLanguage(); const AtomicString& argument = selector.argument(); if (value.isEmpty() || !value.startsWith(argument, false)) break; if (value.length() != argument.length() && value[argument.length()] != '-') break; return true; } case CSSSelector::PseudoHost: { // We can only get here if the selector was defined in the right // scope so we don't need to check it. // For empty parameter case, i.e. just :host or :host(). if (!selector.selectorList()) return true; for (const CSSSelector* current = selector.selectorList()->first(); current; current = CSSSelectorList::next(*current)) { if (match(*current)) return true; } return false; } case CSSSelector::PseudoUnknown: case CSSSelector::PseudoNotParsed: case CSSSelector::PseudoUserAgentCustomElement: return false; } ASSERT_NOT_REACHED(); return false; }
void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags) { RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags); static const unsigned athostRuleSpecificity = 0x100000; if (addRuleFlags & RuleIsHostRule) ruleData.increaseSpecificity(athostRuleSpecificity); collectFeaturesFromRuleData(m_features, ruleData); CSSSelector* selector = ruleData.selector(); if (selector->m_match == CSSSelector::Id) { addToRuleSet(selector->value().impl(), m_idRules, ruleData); return; } if (selector->m_match == CSSSelector::Class) { addToRuleSet(selector->value().impl(), m_classRules, ruleData); return; } if (selector->isCustomPseudoElement()) { addToRuleSet(selector->value().impl(), m_shadowPseudoElementRules, ruleData); return; } if (SelectorChecker::isCommonPseudoClassSelector(selector)) { switch (selector->pseudoType()) { case CSSSelector::PseudoLink: case CSSSelector::PseudoVisited: case CSSSelector::PseudoAnyLink: m_linkPseudoClassRules.append(ruleData); return; case CSSSelector::PseudoFocus: m_focusPseudoClassRules.append(ruleData); return; default: ASSERT_NOT_REACHED(); } return; } const AtomicString& localName = selector->tag().localName(); if (localName != starAtom) { addToRuleSet(localName.impl(), m_tagRules, ruleData); return; } m_universalRules.append(ruleData); }
bool RuleSet::findBestRuleSetAndAdd(const CSSSelector& component, RuleData& ruleData) { AtomicString id; AtomicString className; AtomicString customPseudoElementName; AtomicString tagName; #ifndef NDEBUG m_allRules.append(ruleData); #endif const CSSSelector* it = &component; for (; it && it->relation() == CSSSelector::SubSelector; it = it->tagHistory()) extractValuesforSelector(it, id, className, customPseudoElementName, tagName); if (it) extractValuesforSelector(it, id, className, customPseudoElementName, tagName); // Prefer rule sets in order of most likely to apply infrequently. if (!id.isEmpty()) { addToRuleSet(id, ensurePendingRules()->idRules, ruleData); return true; } if (!className.isEmpty()) { addToRuleSet(className, ensurePendingRules()->classRules, ruleData); return true; } if (!customPseudoElementName.isEmpty()) { // Custom pseudos come before ids and classes in the order of tagHistory, and have a relation of // ShadowPseudo between them. Therefore we should never be a situation where extractValuesforSelector // finsd id and className in addition to custom pseudo. ASSERT(id.isEmpty() && className.isEmpty()); addToRuleSet(customPseudoElementName, ensurePendingRules()->shadowPseudoElementRules, ruleData); return true; } if (component.pseudoType() == CSSSelector::PseudoCue) { m_cuePseudoRules.append(ruleData); return true; } if (SelectorChecker::isCommonPseudoClassSelector(component)) { switch (component.pseudoType()) { case CSSSelector::PseudoLink: case CSSSelector::PseudoVisited: case CSSSelector::PseudoAnyLink: m_linkPseudoClassRules.append(ruleData); return true; case CSSSelector::PseudoFocus: m_focusPseudoClassRules.append(ruleData); return true; default: ASSERT_NOT_REACHED(); return true; } } if (!tagName.isEmpty()) { addToRuleSet(tagName, ensurePendingRules()->tagRules, ruleData); return true; } if (component.isHostPseudoClass()) { m_shadowHostRules.append(ruleData); return true; } return false; }
bool RuleSet::findBestRuleSetAndAdd(const CSSSelector& component, RuleData& ruleData) { AtomicString id; AtomicString className; AtomicString customPseudoElementName; AtomicString tagName; #ifndef NDEBUG m_allRules.append(ruleData); #endif const CSSSelector* it = &component; for (; it && it->relation() == CSSSelector::SubSelector; it = it->tagHistory()) extractValuesforSelector(it, id, className, customPseudoElementName, tagName); if (it) extractValuesforSelector(it, id, className, customPseudoElementName, tagName); // Prefer rule sets in order of most likely to apply infrequently. if (!id.isEmpty()) { addToRuleSet(id, ensurePendingRules()->idRules, ruleData); return true; } if (!className.isEmpty()) { addToRuleSet(className, ensurePendingRules()->classRules, ruleData); return true; } if (!customPseudoElementName.isEmpty()) { // Custom pseudos come before ids and classes in the order of tagHistory, and have a relation of // ShadowPseudo between them. Therefore we should never be a situation where extractValuesforSelector // finsd id and className in addition to custom pseudo. ASSERT(id.isEmpty() && className.isEmpty()); addToRuleSet(customPseudoElementName, ensurePendingRules()->shadowPseudoElementRules, ruleData); return true; } switch (component.pseudoType()) { case CSSSelector::PseudoCue: m_cuePseudoRules.append(ruleData); return true; case CSSSelector::PseudoLink: case CSSSelector::PseudoVisited: case CSSSelector::PseudoAnyLink: m_linkPseudoClassRules.append(ruleData); return true; case CSSSelector::PseudoFocus: m_focusPseudoClassRules.append(ruleData); return true; default: break; } if (!tagName.isEmpty()) { addToRuleSet(tagName, ensurePendingRules()->tagRules, ruleData); return true; } // TODO(esprehn): We shouldn't favor tagName over m_shadowHostRules, it means // selectors with div:host end up in the tagName list matched against all tags // even though they can't match anything at all. if (component.isHostPseudoClass()) { m_shadowHostRules.append(ruleData); return true; } return false; }
static bool isSkippableComponentForInvalidation(const CSSSelector& selector) { if (selector.matchesPseudoElement() || selector.pseudoType() == CSSSelector::PseudoHost) return false; return true; }
static bool isSkippableComponentForInvalidation(const CSSSelector& selector) { if (selector.m_match == CSSSelector::Tag || selector.m_match == CSSSelector::Id || selector.isAttributeSelector()) return true; if (selector.m_match == CSSSelector::PseudoElement) { switch (selector.pseudoType()) { case CSSSelector::PseudoBefore: case CSSSelector::PseudoAfter: case CSSSelector::PseudoBackdrop: case CSSSelector::PseudoShadow: return true; default: return selector.isCustomPseudoElement(); } } if (selector.m_match != CSSSelector::PseudoClass) return false; switch (selector.pseudoType()) { case CSSSelector::PseudoEmpty: case CSSSelector::PseudoFirstChild: case CSSSelector::PseudoFirstOfType: case CSSSelector::PseudoLastChild: case CSSSelector::PseudoLastOfType: case CSSSelector::PseudoOnlyChild: case CSSSelector::PseudoOnlyOfType: case CSSSelector::PseudoNthChild: case CSSSelector::PseudoNthOfType: case CSSSelector::PseudoNthLastChild: case CSSSelector::PseudoNthLastOfType: case CSSSelector::PseudoLink: case CSSSelector::PseudoVisited: case CSSSelector::PseudoAnyLink: case CSSSelector::PseudoHover: case CSSSelector::PseudoDrag: case CSSSelector::PseudoFocus: case CSSSelector::PseudoActive: case CSSSelector::PseudoChecked: case CSSSelector::PseudoEnabled: case CSSSelector::PseudoDefault: case CSSSelector::PseudoDisabled: case CSSSelector::PseudoOptional: case CSSSelector::PseudoRequired: case CSSSelector::PseudoReadOnly: case CSSSelector::PseudoReadWrite: case CSSSelector::PseudoValid: case CSSSelector::PseudoInvalid: case CSSSelector::PseudoIndeterminate: case CSSSelector::PseudoTarget: case CSSSelector::PseudoLang: case CSSSelector::PseudoRoot: case CSSSelector::PseudoScope: case CSSSelector::PseudoInRange: case CSSSelector::PseudoOutOfRange: case CSSSelector::PseudoUnresolved: return true; default: return false; } }