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 |