// This method is somewhat conservative in what it acceptss. static bool supportsClassDescendantInvalidation(const CSSSelector& selector) { bool foundDescendantRelation = false; bool foundAncestorIdent = false; bool foundIdent = false; for (const CSSSelector* component = &selector; component; component = component->tagHistory()) { // FIXME: We should allow pseudo elements, but we need to change how they hook // into recalcStyle by moving them to recalcOwnStyle instead of recalcChildStyle. // FIXME: next up: Tag and Id. if (component->m_match == CSSSelector::Class) { if (!foundDescendantRelation) foundIdent = true; else foundAncestorIdent = true; } else if (!isSkippableComponentForInvalidation(*component)) { return false; } // FIXME: We can probably support ChildTree and DescendantTree. switch (component->relation()) { case CSSSelector::Descendant: case CSSSelector::Child: foundDescendantRelation = true; // Fall through! case CSSSelector::SubSelector: continue; default: return false; } } return foundDescendantRelation && foundAncestorIdent && foundIdent; }
// This method is somewhat conservative in what it accepts. RuleFeatureSet::InvalidationSetMode RuleFeatureSet::invalidationSetModeForSelector(const CSSSelector& selector) { bool foundDescendantRelation = false; bool foundIdent = false; for (const CSSSelector* component = &selector; component; component = component->tagHistory()) { if (component->m_match == CSSSelector::Class || component->m_match == CSSSelector::Id || (component->m_match == CSSSelector::Tag && component->tagQName().localName() != starAtom) || component->isAttributeSelector() || component->isCustomPseudoElement()) { if (!foundDescendantRelation) foundIdent = true; } else if (component->pseudoType() == CSSSelector::PseudoHost || component->pseudoType() == CSSSelector::PseudoAny) { if (const CSSSelectorList* selectorList = component->selectorList()) { for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) { InvalidationSetMode hostMode = invalidationSetModeForSelector(*selector); if (hostMode == UseSubtreeStyleChange) return foundDescendantRelation ? UseLocalStyleChange : UseSubtreeStyleChange; if (!foundDescendantRelation && hostMode == AddFeatures) foundIdent = true; } } } else if (!isSkippableComponentForInvalidation(*component)) { return foundDescendantRelation ? UseLocalStyleChange : UseSubtreeStyleChange; } switch (component->relation()) { case CSSSelector::Descendant: case CSSSelector::Child: case CSSSelector::ShadowPseudo: case CSSSelector::ShadowDeep: foundDescendantRelation = true; // Fall through! case CSSSelector::SubSelector: case CSSSelector::DirectAdjacent: case CSSSelector::IndirectAdjacent: continue; default: // All combinators should be handled above. ASSERT_NOT_REACHED(); return UseLocalStyleChange; } } return foundIdent ? AddFeatures : UseLocalStyleChange; }