| Index: third_party/WebKit/Source/core/css/RuleFeature.cpp
|
| diff --git a/third_party/WebKit/Source/core/css/RuleFeature.cpp b/third_party/WebKit/Source/core/css/RuleFeature.cpp
|
| index 8ba872b147dd812063caee2a940108d165509c56..899f7e2fcea8c44a27163d79c31bdb5ab238b7ff 100644
|
| --- a/third_party/WebKit/Source/core/css/RuleFeature.cpp
|
| +++ b/third_party/WebKit/Source/core/css/RuleFeature.cpp
|
| @@ -47,8 +47,6 @@ namespace blink {
|
|
|
| namespace {
|
|
|
| -#if ENABLE(ASSERT)
|
| -
|
| bool supportsInvalidation(CSSSelector::MatchType match)
|
| {
|
| switch (match) {
|
| @@ -66,11 +64,11 @@ bool supportsInvalidation(CSSSelector::MatchType match)
|
| case CSSSelector::Unknown:
|
| case CSSSelector::PagePseudoClass:
|
| // These should not appear in StyleRule selectors.
|
| - ASSERT_NOT_REACHED();
|
| + NOTREACHED();
|
| return false;
|
| default:
|
| // New match type added. Figure out if it needs a subtree invalidation or not.
|
| - ASSERT_NOT_REACHED();
|
| + NOTREACHED();
|
| return false;
|
| }
|
| }
|
| @@ -162,11 +160,11 @@ bool supportsInvalidation(CSSSelector::PseudoType type)
|
| case CSSSelector::PseudoRightPage:
|
| case CSSSelector::PseudoFirstPage:
|
| // These should not appear in StyleRule selectors.
|
| - ASSERT_NOT_REACHED();
|
| + NOTREACHED();
|
| return false;
|
| default:
|
| // New pseudo type added. Figure out if it needs a subtree invalidation or not.
|
| - ASSERT_NOT_REACHED();
|
| + NOTREACHED();
|
| return false;
|
| }
|
| }
|
| @@ -181,12 +179,10 @@ bool supportsInvalidationWithSelectorList(CSSSelector::PseudoType pseudo)
|
| || pseudo == CSSSelector::PseudoSlotted;
|
| }
|
|
|
| -#endif // ENABLE(ASSERT)
|
| -
|
| bool requiresSubtreeInvalidation(const CSSSelector& selector)
|
| {
|
| if (selector.match() != CSSSelector::PseudoElement && selector.match() != CSSSelector::PseudoClass) {
|
| - ASSERT(supportsInvalidation(selector.match()));
|
| + DCHECK(supportsInvalidation(selector.match()));
|
| return false;
|
| }
|
|
|
| @@ -201,7 +197,7 @@ bool requiresSubtreeInvalidation(const CSSSelector& selector)
|
| // :host-context matches an ancestor of the shadow host.
|
| return true;
|
| default:
|
| - ASSERT(supportsInvalidation(selector.getPseudoType()));
|
| + DCHECK(supportsInvalidation(selector.getPseudoType()));
|
| return false;
|
| }
|
| }
|
| @@ -294,37 +290,80 @@ ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSe
|
| return ensureInvalidationSet(m_pseudoInvalidationSets, pseudoType, type);
|
| }
|
|
|
| -bool RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, InvalidationSetFeatures& features)
|
| +void RuleFeatureSet::updateFeaturesFromCombinator(
|
| + const CSSSelector& lastInCompound,
|
| + const CSSSelector* lastCompoundInAdjacentChain,
|
| + InvalidationSetFeatures& lastCompoundInAdjacentChainFeatures,
|
| + InvalidationSetFeatures*& siblingFeatures,
|
| + InvalidationSetFeatures& descendantFeatures)
|
| +{
|
| + if (lastInCompound.isAdjacentSelector()) {
|
| + if (!siblingFeatures) {
|
| + siblingFeatures = &lastCompoundInAdjacentChainFeatures;
|
| + if (lastCompoundInAdjacentChain) {
|
| + extractInvalidationSetFeaturesFromCompound(*lastCompoundInAdjacentChain, lastCompoundInAdjacentChainFeatures, Ancestor);
|
| + if (!lastCompoundInAdjacentChainFeatures.hasFeatures())
|
| + lastCompoundInAdjacentChainFeatures.forceSubtree = true;
|
| + }
|
| + }
|
| + if (siblingFeatures->maxDirectAdjacentSelectors == UINT_MAX)
|
| + return;
|
| + if (lastInCompound.relation() == CSSSelector::DirectAdjacent)
|
| + ++siblingFeatures->maxDirectAdjacentSelectors;
|
| + else
|
| + siblingFeatures->maxDirectAdjacentSelectors = UINT_MAX;
|
| + return;
|
| + }
|
| +
|
| + if (siblingFeatures && lastCompoundInAdjacentChainFeatures.maxDirectAdjacentSelectors)
|
| + lastCompoundInAdjacentChainFeatures = InvalidationSetFeatures();
|
| +
|
| + siblingFeatures = nullptr;
|
| +
|
| + if (lastInCompound.isShadowSelector())
|
| + descendantFeatures.treeBoundaryCrossing = true;
|
| + if (lastInCompound.relation() == CSSSelector::ShadowSlot || lastInCompound.relationIsAffectedByPseudoContent())
|
| + descendantFeatures.insertionPointCrossing = true;
|
| + if (lastInCompound.relationIsAffectedByPseudoContent())
|
| + descendantFeatures.contentPseudoCrossing = true;
|
| +}
|
| +
|
| +void RuleFeatureSet::extractInvalidationSetFeaturesFromSimpleSelector(const CSSSelector& selector, InvalidationSetFeatures& features)
|
| {
|
| if (selector.match() == CSSSelector::Tag && selector.tagQName().localName() != starAtom) {
|
| features.tagNames.append(selector.tagQName().localName());
|
| - return true;
|
| + return;
|
| }
|
| if (selector.match() == CSSSelector::Id) {
|
| features.ids.append(selector.value());
|
| - return true;
|
| + return;
|
| }
|
| if (selector.match() == CSSSelector::Class) {
|
| features.classes.append(selector.value());
|
| - return true;
|
| + return;
|
| }
|
| if (selector.isAttributeSelector()) {
|
| features.attributes.append(selector.attribute().localName());
|
| - return true;
|
| + return;
|
| }
|
| - if (selector.getPseudoType() == CSSSelector::PseudoWebKitCustomElement || selector.getPseudoType() == CSSSelector::PseudoBlinkInternalElement) {
|
| + switch (selector.getPseudoType()) {
|
| + case CSSSelector::PseudoWebKitCustomElement:
|
| + case CSSSelector::PseudoBlinkInternalElement:
|
| features.customPseudoElement = true;
|
| - return true;
|
| - }
|
| - // Returning false for ::before and ::after as they are not used as
|
| - // invalidation set features, only used later to generate invalidation sets
|
| - // for attributes present in "content: attr(...)" declarations.
|
| - if (selector.getPseudoType() == CSSSelector::PseudoBefore || selector.getPseudoType() == CSSSelector::PseudoAfter)
|
| + return;
|
| + case CSSSelector::PseudoBefore:
|
| + case CSSSelector::PseudoAfter:
|
| features.hasBeforeOrAfter = true;
|
| - return false;
|
| + return;
|
| + case CSSSelector::PseudoSlotted:
|
| + features.invalidatesSlotted = true;
|
| + return;
|
| + default:
|
| + return;
|
| + }
|
| }
|
|
|
| -InvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector, InvalidationType type)
|
| +InvalidationSet* RuleFeatureSet::invalidationSetForSimpleSelector(const CSSSelector& selector, InvalidationType type)
|
| {
|
| if (selector.match() == CSSSelector::Class)
|
| return &ensureClassInvalidationSet(selector.value(), type);
|
| @@ -382,35 +421,38 @@ InvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& s
|
| return nullptr;
|
| }
|
|
|
| -// Given a rule, update the descendant invalidation sets for the features found
|
| -// in its selector. The first step is to extract the features from the rightmost
|
| -// compound selector (extractInvalidationSetFeatures). Secondly, add those features
|
| -// to the invalidation sets for the features found in the other compound selectors
|
| -// (addFeaturesToInvalidationSets). If we find a feature in the right-most compound
|
| -// selector that requires a subtree recalc, we addFeaturesToInvalidationSets for the
|
| -// rightmost compound selector as well.
|
| -
|
| void RuleFeatureSet::updateInvalidationSets(const RuleData& ruleData)
|
| {
|
| + // Given a rule, update the descendant invalidation sets for the features
|
| + // found in its selector. The first step is to extract the features from the
|
| + // rightmost compound selector (extractInvalidationSetFeaturesFromCompound).
|
| + // Secondly, add those features to the invalidation sets for the features
|
| + // found in the other compound selectors (addFeaturesToInvalidationSets). If
|
| + // we find a feature in the right-most compound selector that requires a
|
| + // subtree recalc, nextCompound will be the rightmost compound and we will
|
| + // addFeaturesToInvalidationSets for that one as well.
|
| +
|
| InvalidationSetFeatures features;
|
| - auto result = extractInvalidationSetFeatures(ruleData.selector(), features, Subject);
|
| -
|
| - features.forceSubtree = result.second == ForceSubtree;
|
| - if (result.first) {
|
| - addFeaturesToInvalidationSets(result.first, features.adjacent ? &features : nullptr, features);
|
| - } else if (features.hasNthPseudo) {
|
| - DCHECK(m_nthInvalidationSet);
|
| - addFeaturesToInvalidationSet(*m_nthInvalidationSet, features);
|
| - }
|
| + const CSSSelector* nextCompound = extractInvalidationSetFeaturesFromCompound(ruleData.selector(), features, Subject);
|
| +
|
| + if (!features.hasFeatures())
|
| + features.forceSubtree = true;
|
| +
|
| + if (nextCompound)
|
| + addFeaturesToInvalidationSets(*nextCompound, features);
|
| + else if (features.hasNthPseudo)
|
| + addFeaturesToInvalidationSet(ensureNthInvalidationSet(), features);
|
|
|
| - // If any ::before and ::after rules specify 'content: attr(...)', we
|
| - // need to create invalidation sets for those attributes.
|
| if (features.hasBeforeOrAfter)
|
| updateInvalidationSetsForContentAttribute(ruleData);
|
| }
|
|
|
| void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& ruleData)
|
| {
|
| + // If any ::before and ::after rules specify 'content: attr(...)', we
|
| + // need to create invalidation sets for those attributes to have content
|
| + // changes applied through style recalc.
|
| +
|
| const StylePropertySet& propertySet = ruleData.rule()->properties();
|
|
|
| int propertyIndex = propertySet.findPropertyIndex(CSSPropertyContent);
|
| @@ -434,74 +476,101 @@ void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& r
|
| }
|
| }
|
|
|
| -std::pair<const CSSSelector*, RuleFeatureSet::UseFeaturesType>
|
| -RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, InvalidationSetFeatures& features, PositionType position, CSSSelector::PseudoType pseudo)
|
| +const CSSSelector*
|
| +RuleFeatureSet::extractInvalidationSetFeaturesFromSelectorList(const CSSSelector& simpleSelector, InvalidationSetFeatures& features, PositionType position)
|
| {
|
| - bool foundFeatures = false;
|
| - for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
|
| - if (pseudo != CSSSelector::PseudoNot)
|
| - foundFeatures |= extractInvalidationSetFeature(*current, features);
|
| - // Initialize the entry in the invalidation set map, if supported.
|
| - if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, InvalidateDescendants)) {
|
| - if (position == Subject) {
|
| - if (invalidationSet == m_nthInvalidationSet)
|
| - features.hasNthPseudo = true;
|
| - else
|
| - invalidationSet->setInvalidatesSelf();
|
| - }
|
| - } else {
|
| - if (requiresSubtreeInvalidation(*current)) {
|
| - // Fall back to use subtree invalidations, even for features in the
|
| - // rightmost compound selector. Returning the start &selector here
|
| - // will make addFeaturesToInvalidationSets start marking invalidation
|
| - // sets for subtree recalc for features in the rightmost compound
|
| - // selector.
|
| - return std::make_pair(&selector, ForceSubtree);
|
| - }
|
| - if (const CSSSelectorList* selectorList = current->selectorList()) {
|
| - if (current->getPseudoType() == CSSSelector::PseudoSlotted) {
|
| - ASSERT(position == Subject);
|
| - features.invalidatesSlotted = true;
|
| - }
|
| - ASSERT(supportsInvalidationWithSelectorList(current->getPseudoType()));
|
| - const CSSSelector* subSelector = selectorList->first();
|
| - bool allSubSelectorsHaveFeatures = !!subSelector;
|
| - for (; subSelector; subSelector = CSSSelectorList::next(*subSelector)) {
|
| - auto result = extractInvalidationSetFeatures(*subSelector, features, position, current->getPseudoType());
|
| - if (result.first) {
|
| - // A non-null selector return means the sub-selector contained a
|
| - // selector which requiresSubtreeInvalidation(). Return the rightmost
|
| - // selector to mark for subtree recalcs like above.
|
| - return std::make_pair(&selector, ForceSubtree);
|
| - }
|
| - allSubSelectorsHaveFeatures &= result.second == UseFeatures;
|
| - }
|
| - foundFeatures |= allSubSelectorsHaveFeatures;
|
| - }
|
| + const CSSSelectorList* selectorList = simpleSelector.selectorList();
|
| + if (!selectorList)
|
| + return nullptr;
|
| +
|
| + DCHECK(supportsInvalidationWithSelectorList(simpleSelector.getPseudoType()));
|
| +
|
| + const CSSSelector* subSelector = selectorList->first();
|
| +
|
| + bool allSubSelectorsHaveFeatures = true;
|
| + InvalidationSetFeatures anyFeatures;
|
| +
|
| + for (; subSelector; subSelector = CSSSelectorList::next(*subSelector)) {
|
| + InvalidationSetFeatures compoundFeatures;
|
| + if (extractInvalidationSetFeaturesFromCompound(*subSelector, compoundFeatures, position, simpleSelector.getPseudoType())) {
|
| + // A non-null selector return means the sub-selector contained a
|
| + // selector which requiresSubtreeInvalidation().
|
| + DCHECK(compoundFeatures.forceSubtree);
|
| + features.forceSubtree = true;
|
| + return &simpleSelector;
|
| }
|
| + if (allSubSelectorsHaveFeatures && !compoundFeatures.hasFeatures())
|
| + allSubSelectorsHaveFeatures = false;
|
| + else
|
| + anyFeatures.add(compoundFeatures);
|
| + if (compoundFeatures.hasNthPseudo)
|
| + features.hasNthPseudo = true;
|
| + }
|
| + // Don't add any features if one of the sub-selectors of does not contain
|
| + // any invalidation set features. E.g. :-webkit-any(*, span).
|
| + if (allSubSelectorsHaveFeatures)
|
| + features.add(anyFeatures);
|
| + return nullptr;
|
| +}
|
|
|
| - if (current->relation() == CSSSelector::SubSelector)
|
| - continue;
|
| +const CSSSelector*
|
| +RuleFeatureSet::extractInvalidationSetFeaturesFromCompound(const CSSSelector& compound, InvalidationSetFeatures& features, PositionType position, CSSSelector::PseudoType pseudo)
|
| +{
|
| + const CSSSelector* simpleSelector = &compound;
|
| + for (; simpleSelector; simpleSelector = simpleSelector->tagHistory()) {
|
| +
|
| + // Fall back to use subtree invalidations, even for features in the
|
| + // rightmost compound selector. Returning the start &selector here
|
| + // will make addFeaturesToInvalidationSets start marking invalidation
|
| + // sets for subtree recalc for features in the rightmost compound
|
| + // selector.
|
| + if (requiresSubtreeInvalidation(*simpleSelector)) {
|
| + features.forceSubtree = true;
|
| + return &compound;
|
| + }
|
|
|
| - if (features.hasNthPseudo && position == Subject) {
|
| - DCHECK(m_nthInvalidationSet);
|
| - if (foundFeatures)
|
| - addFeaturesToInvalidationSet(*m_nthInvalidationSet, features);
|
| - else
|
| - m_nthInvalidationSet->setWholeSubtreeInvalid();
|
| + // When inside a :not(), we should not use the found features for
|
| + // invalidation because we should invalidate elements _without_ that
|
| + // feature. On the other hand, we should still have invalidation sets
|
| + // for the features since we are able to detect when they change.
|
| + // That is, ".a" should not have ".b" in its invalidation set for
|
| + // ".a :not(.b)", but there should be an invalidation set for ".a" in
|
| + // ":not(.a) .b".
|
| + if (pseudo != CSSSelector::PseudoNot)
|
| + extractInvalidationSetFeaturesFromSimpleSelector(*simpleSelector, features);
|
| +
|
| + // Initialize the entry in the invalidation set map for self-
|
| + // invalidation, if supported.
|
| + if (InvalidationSet* invalidationSet = invalidationSetForSimpleSelector(*simpleSelector, InvalidateDescendants)) {
|
| + if (invalidationSet == m_nthInvalidationSet)
|
| + features.hasNthPseudo = true;
|
| + else if (position == Subject)
|
| + invalidationSet->setInvalidatesSelf();
|
| + }
|
| +
|
| + if (extractInvalidationSetFeaturesFromSelectorList(*simpleSelector, features, position)) {
|
| + DCHECK(features.forceSubtree);
|
| + return &compound;
|
| }
|
|
|
| - features.treeBoundaryCrossing = current->isShadowSelector();
|
| - if (current->relationIsAffectedByPseudoContent()) {
|
| - features.contentPseudoCrossing = true;
|
| - features.insertionPointCrossing = true;
|
| + if (simpleSelector->relation() == CSSSelector::SubSelector)
|
| + continue;
|
| +
|
| + if (position == Subject) {
|
| + if (features.hasNthPseudo) {
|
| + DCHECK(m_nthInvalidationSet);
|
| + if (features.hasFeatures())
|
| + addFeaturesToInvalidationSet(*m_nthInvalidationSet, features);
|
| + else
|
| + m_nthInvalidationSet->setWholeSubtreeInvalid();
|
| + }
|
| + InvalidationSetFeatures* siblingFeatures = nullptr;
|
| + updateFeaturesFromCombinator(*simpleSelector, nullptr, features, siblingFeatures, features);
|
| }
|
| - features.adjacent = current->isAdjacentSelector();
|
| - if (current->relation() == CSSSelector::DirectAdjacent)
|
| - features.maxDirectAdjacentSelectors = 1;
|
| - return std::make_pair(current->tagHistory(), foundFeatures ? UseFeatures : ForceSubtree);
|
| + return simpleSelector->tagHistory();
|
| }
|
| - return std::make_pair(nullptr, foundFeatures ? UseFeatures : ForceSubtree);
|
| +
|
| + return nullptr;
|
| }
|
|
|
| // Add features extracted from the rightmost compound selector to descendant invalidation
|
| @@ -538,86 +607,79 @@ void RuleFeatureSet::addFeaturesToInvalidationSet(InvalidationSet& invalidationS
|
| invalidationSet.setCustomPseudoInvalid();
|
| }
|
|
|
| -// 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;
|
| +void RuleFeatureSet::addFeaturesToInvalidationSetsForSelectorList(const CSSSelector& simpleSelector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFeatures)
|
| +{
|
| + if (!simpleSelector.selectorList())
|
| + return;
|
|
|
| - bool universalCompound = true;
|
| + DCHECK(supportsInvalidationWithSelectorList(simpleSelector.getPseudoType()));
|
|
|
| - for (const CSSSelector* current = selector; current; current = current->tagHistory()) {
|
| - InvalidationType type = siblingFeatures ? InvalidateSiblings : InvalidateDescendants;
|
| - if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, type)) {
|
| - if (current->match() != CSSSelector::PseudoClass)
|
| - universalCompound = false;
|
| - if (siblingFeatures && invalidationSet != m_nthInvalidationSet) {
|
| - SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvalidationSet(invalidationSet);
|
| - siblingInvalidationSet->updateMaxDirectAdjacentSelectors(siblingFeatures->maxDirectAdjacentSelectors);
|
| + for (const CSSSelector* subSelector = simpleSelector.selectorList()->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector))
|
| + addFeaturesToInvalidationSetsForCompoundSelector(*subSelector, siblingFeatures, descendantFeatures);
|
| +}
|
|
|
| - addFeaturesToInvalidationSet(*invalidationSet, *siblingFeatures);
|
| - if (siblingFeatures == &descendantFeatures)
|
| - siblingInvalidationSet->setInvalidatesSelf();
|
| - else
|
| - addFeaturesToInvalidationSet(siblingInvalidationSet->ensureSiblingDescendants(), 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->getPseudoType()));
|
| - for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector))
|
| - addFeaturesToInvalidationSets(subSelector, siblingFeatures, descendantFeatures);
|
| - }
|
| +void RuleFeatureSet::addFeaturesToInvalidationSetsForSimpleSelector(const CSSSelector& simpleSelector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFeatures)
|
| +{
|
| + if (InvalidationSet* invalidationSet = invalidationSetForSimpleSelector(simpleSelector, siblingFeatures ? InvalidateSiblings : InvalidateDescendants)) {
|
| + if (!siblingFeatures || invalidationSet == m_nthInvalidationSet) {
|
| + addFeaturesToInvalidationSet(*invalidationSet, descendantFeatures);
|
| + return;
|
| }
|
|
|
| - if (current->relation() == CSSSelector::SubSelector)
|
| - continue;
|
| -
|
| - if (universalCompound && siblingFeatures)
|
| - addFeaturesToUniversalSiblingInvalidationSet(*siblingFeatures, descendantFeatures);
|
| - universalCompound = true;
|
| -
|
| - if (current->relationIsAffectedByPseudoContent() || current->relation() == CSSSelector::ShadowSlot) {
|
| - descendantFeatures.insertionPointCrossing = true;
|
| - descendantFeatures.contentPseudoCrossing = true;
|
| - }
|
| - if (current->isShadowSelector())
|
| - descendantFeatures.treeBoundaryCrossing = true;
|
| - if (!current->isAdjacentSelector()) {
|
| - lastCompoundSelectorInAdjacentChain = current->tagHistory();
|
| - siblingFeatures = nullptr;
|
| - continue;
|
| - }
|
| + SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvalidationSet(invalidationSet);
|
| + siblingInvalidationSet->updateMaxDirectAdjacentSelectors(siblingFeatures->maxDirectAdjacentSelectors);
|
| + addFeaturesToInvalidationSet(*invalidationSet, *siblingFeatures);
|
| + if (siblingFeatures == &descendantFeatures)
|
| + siblingInvalidationSet->setInvalidatesSelf();
|
| + else
|
| + addFeaturesToInvalidationSet(siblingInvalidationSet->ensureSiblingDescendants(), descendantFeatures);
|
| + return;
|
| + }
|
|
|
| - if (siblingFeatures) {
|
| - if (siblingFeatures->maxDirectAdjacentSelectors == UINT_MAX)
|
| - continue;
|
| + if (simpleSelector.isHostPseudoClass())
|
| + descendantFeatures.treeBoundaryCrossing = true;
|
| + if (simpleSelector.isInsertionPointCrossing())
|
| + descendantFeatures.insertionPointCrossing = true;
|
|
|
| - if (current->relation() == CSSSelector::DirectAdjacent)
|
| - siblingFeatures->maxDirectAdjacentSelectors++;
|
| - else
|
| - siblingFeatures->maxDirectAdjacentSelectors = UINT_MAX;
|
| - continue;
|
| - }
|
| + addFeaturesToInvalidationSetsForSelectorList(simpleSelector, siblingFeatures, descendantFeatures);
|
| +}
|
|
|
| - localFeatures = InvalidationSetFeatures();
|
| - auto result = extractInvalidationSetFeatures(*lastCompoundSelectorInAdjacentChain, localFeatures, Ancestor);
|
| - ASSERT(result.first);
|
| - localFeatures.forceSubtree = result.second == ForceSubtree;
|
| - siblingFeatures = &localFeatures;
|
| +const CSSSelector* RuleFeatureSet::addFeaturesToInvalidationSetsForCompoundSelector(const CSSSelector& compound, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFeatures)
|
| +{
|
| + bool compoundHasTagIdClassOrAttribute = false;
|
| + const CSSSelector* simpleSelector = &compound;
|
| + for (; simpleSelector; simpleSelector = simpleSelector->tagHistory()) {
|
| + addFeaturesToInvalidationSetsForSimpleSelector(*simpleSelector, siblingFeatures, descendantFeatures);
|
| + if (siblingFeatures)
|
| + compoundHasTagIdClassOrAttribute |= simpleSelector->isIdClassOrAttributeSelector();
|
| + if (simpleSelector->relation() != CSSSelector::SubSelector)
|
| + break;
|
| + if (!simpleSelector->tagHistory())
|
| + break;
|
| }
|
|
|
| - if (universalCompound && siblingFeatures)
|
| + if (siblingFeatures && !compoundHasTagIdClassOrAttribute)
|
| addFeaturesToUniversalSiblingInvalidationSet(*siblingFeatures, descendantFeatures);
|
| +
|
| + return simpleSelector;
|
| +}
|
| +
|
| +void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& descendantFeatures)
|
| +{
|
| + // selector is the selector immediately to the left of the rightmost combinator.
|
| + // descendantFeatures has the features of the rightmost compound selector.
|
| +
|
| + InvalidationSetFeatures lastCompoundInSiblingChainFeatures;
|
| + InvalidationSetFeatures* siblingFeatures = descendantFeatures.maxDirectAdjacentSelectors ? &descendantFeatures : nullptr;
|
| +
|
| + const CSSSelector* compound = &selector;
|
| + while (compound) {
|
| + const CSSSelector* lastInCompound = addFeaturesToInvalidationSetsForCompoundSelector(*compound, siblingFeatures, descendantFeatures);
|
| + DCHECK(lastInCompound);
|
| + updateFeaturesFromCombinator(*lastInCompound, compound, lastCompoundInSiblingChainFeatures, siblingFeatures, descendantFeatures);
|
| + compound = lastInCompound->tagHistory();
|
| + }
|
| }
|
|
|
| RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData)
|
| @@ -706,7 +768,7 @@ RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromSelector(con
|
| metadata.foundSiblingSelector = true;
|
| }
|
|
|
| - ASSERT(!maxDirectAdjacentSelectors);
|
| + DCHECK(!maxDirectAdjacentSelectors);
|
| return SelectorMayMatch;
|
| }
|
|
|
| @@ -945,4 +1007,30 @@ DEFINE_TRACE(RuleFeatureSet)
|
| visitor->trace(uncommonAttributeRules);
|
| }
|
|
|
| +void RuleFeatureSet::InvalidationSetFeatures::add(const InvalidationSetFeatures& other)
|
| +{
|
| + classes.appendVector(other.classes);
|
| + attributes.appendVector(other.attributes);
|
| + ids.appendVector(other.ids);
|
| + tagNames.appendVector(other.tagNames);
|
| + maxDirectAdjacentSelectors = std::max(maxDirectAdjacentSelectors, other.maxDirectAdjacentSelectors);
|
| + customPseudoElement |= other.customPseudoElement;
|
| + hasBeforeOrAfter |= other.hasBeforeOrAfter;
|
| + treeBoundaryCrossing |= other.treeBoundaryCrossing;
|
| + insertionPointCrossing |= other.insertionPointCrossing;
|
| + forceSubtree |= other.forceSubtree;
|
| + contentPseudoCrossing |= other.contentPseudoCrossing;
|
| + invalidatesSlotted |= other.invalidatesSlotted;
|
| + hasNthPseudo |= other.hasNthPseudo;
|
| +}
|
| +
|
| +bool RuleFeatureSet::InvalidationSetFeatures::hasFeatures() const
|
| +{
|
| + return !classes.isEmpty()
|
| + || !attributes.isEmpty()
|
| + || !ids.isEmpty()
|
| + || !tagNames.isEmpty()
|
| + || customPseudoElement;
|
| +}
|
| +
|
| } // namespace blink
|
|
|