// 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;
}
Exemple #2
0
// 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;
}