void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& features) { for (const CSSSelector* current = &selector; current; current = current->tagHistory()) { if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current)) { addFeaturesToInvalidationSet(*invalidationSet, features); } else { if (current->isTreeBoundaryCrossing()) features.treeBoundaryCrossing = true; if (current->isInsertionPointCrossing()) features.insertionPointCrossing = true; if (const CSSSelectorList* selectorList = current->selectorList()) { ASSERT(supportsInvalidationWithSelectorList(current->pseudoType())); for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector)) addFeaturesToInvalidationSets(*subSelector, features); } } if (current->relation() == CSSSelector::SubSelector) continue; if (current->isShadowSelector()) features.treeBoundaryCrossing = true; features.adjacent = current->isAdjacentSelector(); } }
// selector is the selector immediately to the left of the rightmost combinator. // siblingFeatures is null if selector is not immediately to the left of a sibling combinator. // descendantFeatures has the features of the rightmost compound selector. void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFeatures) { const CSSSelector* lastCompoundSelectorInAdjacentChain = selector; // We set siblingFeatures to &localFeatures if we find a rightmost sibling combinator. InvalidationSetFeatures localFeatures; for (const CSSSelector* current = selector; current; current = current->tagHistory()) { InvalidationType type = siblingFeatures ? InvalidateSiblings : InvalidateDescendants; if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, type)) { if (siblingFeatures) { SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvalidationSet(invalidationSet); siblingInvalidationSet->updateMaxDirectAdjacentSelectors(siblingFeatures->maxDirectAdjacentSelectors); addFeaturesToInvalidationSet(*invalidationSet, *siblingFeatures); if (siblingFeatures == &descendantFeatures) siblingInvalidationSet->descendants().setInvalidatesSelf(); else addFeaturesToInvalidationSet(siblingInvalidationSet->descendants(), descendantFeatures); } else { addFeaturesToInvalidationSet(*invalidationSet, descendantFeatures); } } else { if (current->isHostPseudoClass()) descendantFeatures.treeBoundaryCrossing = true; if (current->isInsertionPointCrossing()) descendantFeatures.insertionPointCrossing = true; if (const CSSSelectorList* selectorList = current->selectorList()) { ASSERT(supportsInvalidationWithSelectorList(current->pseudoType())); for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector)) addFeaturesToInvalidationSets(subSelector, siblingFeatures, descendantFeatures); } } if (current->relation() == CSSSelector::SubSelector) continue; if (current->isShadowSelector()) descendantFeatures.treeBoundaryCrossing = true; if (!current->isAdjacentSelector()) { lastCompoundSelectorInAdjacentChain = current->tagHistory(); siblingFeatures = nullptr; continue; } if (siblingFeatures) { if (siblingFeatures->maxDirectAdjacentSelectors == UINT_MAX) continue; if (current->relation() == CSSSelector::DirectAdjacent) siblingFeatures->maxDirectAdjacentSelectors++; else siblingFeatures->maxDirectAdjacentSelectors = UINT_MAX; continue; } localFeatures = InvalidationSetFeatures(); auto result = extractInvalidationSetFeatures(*lastCompoundSelectorInAdjacentChain, localFeatures, Ancestor); ASSERT(result.first); localFeatures.forceSubtree = result.second == ForceSubtree; siblingFeatures = &localFeatures; } }