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(); } }
void RuleFeatureSet::updateInvalidationSets(const RuleData& ruleData) { InvalidationSetFeatures features; auto result = extractInvalidationSetFeatures(ruleData.selector(), features, false); if (result.first) { features.forceSubtree = result.second == ForceSubtree; addFeaturesToInvalidationSets(*result.first, features); } // If any ::before and ::after rules specify 'content: attr(...)', we // need to create invalidation sets for those attributes. if (features.hasBeforeOrAfter) updateInvalidationSetsForContentAttribute(ruleData); }
RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const CSSSelector& selector) { InvalidationSetMode mode = invalidationSetModeForSelector(selector); if (mode != AddFeatures) return mode; InvalidationSetFeatures features; const CSSSelector* current = extractInvalidationSetFeatures(selector, features); if (current) { bool wholeSubtree = current->relation() == CSSSelector::DirectAdjacent || current->relation() == CSSSelector::IndirectAdjacent; current = current->tagHistory(); if (current) addFeaturesToInvalidationSets(*current, features, wholeSubtree); } return AddFeatures; }
void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, const InvalidationSetFeatures& features, bool wholeSubtree) { for (const CSSSelector* current = &selector; current; current = current->tagHistory()) { if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) { if (wholeSubtree) { invalidationSet->setWholeSubtreeInvalid(); } else { if (!features.id.isEmpty()) invalidationSet->addId(features.id); if (!features.tagName.isEmpty()) invalidationSet->addTagName(features.tagName); for (Vector<AtomicString>::const_iterator it = features.classes.begin(); it != features.classes.end(); ++it) invalidationSet->addClass(*it); for (Vector<AtomicString>::const_iterator it = features.attributes.begin(); it != features.attributes.end(); ++it) invalidationSet->addAttribute(*it); if (features.customPseudoElement) invalidationSet->setCustomPseudoInvalid(); } } else if (current->pseudoType() == CSSSelector::PseudoHost || current->pseudoType() == CSSSelector::PseudoAny) { if (const CSSSelectorList* selectorList = current->selectorList()) { for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) addFeaturesToInvalidationSets(*selector, features, wholeSubtree); } } switch (current->relation()) { case CSSSelector::Descendant: case CSSSelector::Child: case CSSSelector::ShadowPseudo: case CSSSelector::ShadowDeep: wholeSubtree = false; break; case CSSSelector::DirectAdjacent: case CSSSelector::IndirectAdjacent: wholeSubtree = true; break; case CSSSelector::SubSelector: break; default: // All combinators should be handled above. ASSERT_NOT_REACHED(); break; } } }
// 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; } }