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 fa5268046a1d7de88956888acfa1d51b42902d4e..74858be47922ebf4b50fb5adf7876c7048affe59 100644 |
--- a/third_party/WebKit/Source/core/css/RuleFeature.cpp |
+++ b/third_party/WebKit/Source/core/css/RuleFeature.cpp |
@@ -303,6 +303,9 @@ bool RuleFeatureSet::extractInvalidationSetFeature(const CSSSelector& selector, |
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) |
features.hasBeforeOrAfter = true; |
return false; |
@@ -351,6 +354,14 @@ InvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& s |
case CSSSelector::PseudoUnresolved: |
case CSSSelector::PseudoDefined: |
return &ensurePseudoInvalidationSet(selector.getPseudoType(), type); |
+ case CSSSelector::PseudoFirstOfType: |
+ case CSSSelector::PseudoLastOfType: |
+ case CSSSelector::PseudoOnlyOfType: |
+ case CSSSelector::PseudoNthChild: |
+ case CSSSelector::PseudoNthOfType: |
+ case CSSSelector::PseudoNthLastChild: |
+ case CSSSelector::PseudoNthLastOfType: |
+ return &ensureNthInvalidationSet(); |
default: |
break; |
} |
@@ -371,9 +382,12 @@ void RuleFeatureSet::updateInvalidationSets(const RuleData& ruleData) |
InvalidationSetFeatures features; |
auto result = extractInvalidationSetFeatures(ruleData.selector(), features, Subject); |
+ features.forceSubtree = result.second == ForceSubtree; |
if (result.first) { |
- features.forceSubtree = result.second == ForceSubtree; |
addFeaturesToInvalidationSets(result.first, features.adjacent ? &features : nullptr, features); |
+ } else if (features.hasNthPseudo) { |
+ DCHECK(m_nthInvalidationSet); |
+ addFeaturesToInvalidationSet(*m_nthInvalidationSet, features); |
} |
// If any ::before and ::after rules specify 'content: attr(...)', we |
@@ -416,8 +430,12 @@ RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva |
foundFeatures |= extractInvalidationSetFeature(*current, features); |
// Initialize the entry in the invalidation set map, if supported. |
if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, InvalidateDescendants)) { |
- if (position == Subject) |
- invalidationSet->setInvalidatesSelf(); |
+ 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 |
@@ -452,6 +470,14 @@ RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva |
if (current->relation() == CSSSelector::SubSelector) |
continue; |
+ if (features.hasNthPseudo && position == Subject) { |
+ DCHECK(m_nthInvalidationSet); |
+ if (foundFeatures) |
+ addFeaturesToInvalidationSet(*m_nthInvalidationSet, features); |
+ else |
+ m_nthInvalidationSet->setWholeSubtreeInvalid(); |
+ } |
+ |
features.treeBoundaryCrossing = current->isShadowSelector(); |
if (current->relationIsAffectedByPseudoContent()) { |
features.contentPseudoCrossing = true; |
@@ -462,7 +488,7 @@ RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva |
features.maxDirectAdjacentSelectors = 1; |
return std::make_pair(current->tagHistory(), foundFeatures ? UseFeatures : ForceSubtree); |
} |
- return std::make_pair(nullptr, foundFeatures ? UseFeatures : ForceSubtree); |
+ return std::make_pair(nullptr, foundFeatures ? UseFeatures : ForceSubtree); |
} |
// Add features extracted from the rightmost compound selector to descendant invalidation |
@@ -516,7 +542,7 @@ void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector, |
if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, type)) { |
if (current->match() != CSSSelector::PseudoClass) |
universalCompound = false; |
- if (siblingFeatures) { |
+ if (siblingFeatures && invalidationSet != m_nthInvalidationSet) { |
SiblingInvalidationSet* siblingInvalidationSet = toSiblingInvalidationSet(invalidationSet); |
siblingInvalidationSet->updateMaxDirectAdjacentSelectors(siblingFeatures->maxDirectAdjacentSelectors); |
@@ -698,6 +724,8 @@ void RuleFeatureSet::add(const RuleFeatureSet& other) |
ensureInvalidationSet(m_pseudoInvalidationSets, static_cast<CSSSelector::PseudoType>(entry.key), entry.value->type()).combine(*entry.value); |
if (other.m_universalSiblingInvalidationSet) |
ensureUniversalSiblingInvalidationSet().combine(*other.m_universalSiblingInvalidationSet); |
+ if (other.m_nthInvalidationSet) |
+ ensureNthInvalidationSet().combine(*other.m_nthInvalidationSet); |
m_metadata.add(other.m_metadata); |
@@ -867,6 +895,19 @@ SiblingInvalidationSet& RuleFeatureSet::ensureUniversalSiblingInvalidationSet() |
return *m_universalSiblingInvalidationSet; |
} |
+void RuleFeatureSet::collectNthInvalidationSet(InvalidationLists& invalidationLists) const |
+{ |
+ if (m_nthInvalidationSet) |
+ invalidationLists.descendants.append(m_nthInvalidationSet); |
+} |
+ |
+DescendantInvalidationSet& RuleFeatureSet::ensureNthInvalidationSet() |
+{ |
+ if (!m_nthInvalidationSet) |
+ m_nthInvalidationSet = DescendantInvalidationSet::create(); |
+ return *m_nthInvalidationSet; |
+} |
+ |
void RuleFeatureSet::addFeaturesToUniversalSiblingInvalidationSet(const InvalidationSetFeatures& siblingFeatures, const InvalidationSetFeatures& descendantFeatures) |
{ |
SiblingInvalidationSet& universalSet = ensureUniversalSiblingInvalidationSet(); |