Chromium Code Reviews| Index: Source/core/css/RuleFeature.cpp |
| diff --git a/Source/core/css/RuleFeature.cpp b/Source/core/css/RuleFeature.cpp |
| index 0b5311cbcabc3eeb41b3c50f51360bafc94a8cfa..0320c91f5d94899a17ed1e1a4c3a4fdd0d81ac83 100644 |
| --- a/Source/core/css/RuleFeature.cpp |
| +++ b/Source/core/css/RuleFeature.cpp |
| @@ -37,7 +37,7 @@ |
| #include "core/css/RuleSet.h" |
| #include "core/css/StylePropertySet.h" |
| #include "core/css/StyleRule.h" |
| -#include "core/css/invalidation/DescendantInvalidationSet.h" |
| +#include "core/css/invalidation/InvalidationSet.h" |
| #include "core/dom/Element.h" |
| #include "core/dom/Node.h" |
| #include "core/inspector/InspectorTraceEvents.h" |
| @@ -238,14 +238,14 @@ RuleFeatureSet::~RuleFeatureSet() |
| { |
| } |
| -DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector) |
| +InvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector, InvalidateType type) |
|
esprehn
2015/09/10 08:54:53
InvalidateType is a weird name, I think you want I
Eric Willigers
2015/09/14 07:20:23
Done.
|
| { |
| if (selector.match() == CSSSelector::Class) |
| - return &ensureClassInvalidationSet(selector.value()); |
| + return &ensureClassInvalidationSet(selector.value(), type); |
| if (selector.isAttributeSelector()) |
| - return &ensureAttributeInvalidationSet(selector.attribute().localName()); |
| + return &ensureAttributeInvalidationSet(selector.attribute().localName(), type); |
| if (selector.match() == CSSSelector::Id) |
| - return &ensureIdInvalidationSet(selector.value()); |
| + return &ensureIdInvalidationSet(selector.value(), type); |
| if (selector.match() == CSSSelector::PseudoClass) { |
| switch (selector.pseudoType()) { |
| case CSSSelector::PseudoEmpty: |
| @@ -266,7 +266,7 @@ DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSS |
| case CSSSelector::PseudoInvalid: |
| case CSSSelector::PseudoIndeterminate: |
| case CSSSelector::PseudoTarget: |
| - return &ensurePseudoInvalidationSet(selector.pseudoType()); |
| + return &ensurePseudoInvalidationSet(selector.pseudoType(), type); |
| default: |
| break; |
| } |
| @@ -276,25 +276,27 @@ DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSS |
| // 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. |
| +// compound selector (extractInvalidationSetFeatures). |
| +// 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. |
| +// Finally, add those features to the invalidation sets for the features found |
| +// in the other compound selectors (addFeaturesToInvalidationSets). |
| 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); |
| + |
| + if (result.first) { |
| + features.forceSubtree = result.second == ForceSubtree; |
| + addFeaturesToInvalidationSets(result.first, features.adjacent ? &features : nullptr, features); |
| + } |
| } |
| void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& ruleData) |
| @@ -318,7 +320,7 @@ void RuleFeatureSet::updateInvalidationSetsForContentAttribute(const RuleData& r |
| CSSFunctionValue* functionValue = toCSSFunctionValue(item.get()); |
| if (functionValue->functionType() != CSSValueAttr) |
| continue; |
| - ensureAttributeInvalidationSet(AtomicString(toCSSPrimitiveValue(functionValue->item(0))->getStringValue())); |
| + ensureAttributeInvalidationSet(AtomicString(toCSSPrimitiveValue(functionValue->item(0))->getStringValue()), InvalidateDescendants).setAppliesDirectly(); |
| } |
| } |
| @@ -330,7 +332,9 @@ RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva |
| if (!negated) |
| foundFeatures |= extractInvalidationSetFeature(*current, features); |
| // Initialize the entry in the invalidation set map, if supported. |
| - if (!invalidationSetForSelector(*current)) { |
| + if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, InvalidateDescendants)) { |
| + invalidationSet->setAppliesDirectly(); |
| + } else { |
| if (requiresSubtreeInvalidation(*current)) { |
| // Fall back to use subtree invalidations, even for features in the |
| // rightmost compound selector. Returning the start &selector here |
| @@ -362,6 +366,8 @@ RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva |
| features.treeBoundaryCrossing = current->isShadowSelector(); |
| features.adjacent = current->isAdjacentSelector(); |
| + if (current->relation() == CSSSelector::DirectAdjacent) |
| + features.maxDirectAdjacentSelectors = 1; |
| return std::make_pair(current->tagHistory(), foundFeatures ? UseFeatures : ForceSubtree); |
| } |
| return std::make_pair(nullptr, foundFeatures ? UseFeatures : ForceSubtree); |
| @@ -370,22 +376,21 @@ RuleFeatureSet::extractInvalidationSetFeatures(const CSSSelector& selector, Inva |
| // Add features extracted from the rightmost compound selector to descendant invalidation |
| // sets for features found in other compound selectors. |
| // |
| -// Style invalidation is currently supported for descendants only, not for sibling subtrees. |
| -// We use wholeSubtree invalidation for features found left of adjacent combinators as |
| -// SubtreeStyleChange will force sibling subtree recalc in |
| -// ContainerNode::checkForChildrenAdjacentRuleChanges. |
| +// We use descendant invalidation for descendants, sibling invalidation for siblings and their subtrees. |
| // |
| // As we encounter a descendant type of combinator, the features only need to be checked |
| // against descendants in the same subtree only. features.adjacent is set to false, and |
| -// we start adding features instead of calling setWholeSubtreeInvalid. |
| +// we start adding features to the descendant invalidation set. |
| -void RuleFeatureSet::addFeaturesToInvalidationSet(DescendantInvalidationSet& invalidationSet, const InvalidationSetFeatures& features) |
| +void RuleFeatureSet::addFeaturesToInvalidationSet(InvalidationSet& invalidationSet, const InvalidationSetFeatures& features) |
| { |
| + invalidationSet.setMaxDirectAdjacentSelectors(features.maxDirectAdjacentSelectors); |
|
Timothy Loh
2015/09/10 06:09:40
updateMax..?
Eric Willigers
2015/09/14 07:20:23
Done.
|
| + |
| if (features.treeBoundaryCrossing) |
| invalidationSet.setTreeBoundaryCrossing(); |
| if (features.insertionPointCrossing) |
| invalidationSet.setInsertionPointCrossing(); |
| - if (features.useSubtreeInvalidation()) { |
| + if (features.forceSubtree) { |
| invalidationSet.setWholeSubtreeInvalid(); |
| return; |
| } |
| @@ -401,20 +406,34 @@ void RuleFeatureSet::addFeaturesToInvalidationSet(DescendantInvalidationSet& inv |
| invalidationSet.setCustomPseudoInvalid(); |
| } |
| -void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, InvalidationSetFeatures& features) |
| +// selector is the selector immediately to the left of the rightmost selector. |
| +// siblingFeatures is null if selector is not immediately to the left of a sibling combinator. |
| +// descendantFeatures has the features of the rightmost selector. |
| +void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector, InvalidationSetFeatures* siblingFeatures, InvalidationSetFeatures& descendantFeatures) |
| { |
| - for (const CSSSelector* current = &selector; current; current = current->tagHistory()) { |
| - if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) { |
| - addFeaturesToInvalidationSet(*invalidationSet, features); |
| + // We set siblingFeatures to &localFeatures if we find a rightmost sibling combinator. |
| + InvalidationSetFeatures localFeatures; |
| + |
| + for (const CSSSelector* current = selector; current; current = current->tagHistory()) { |
| + InvalidateType type = siblingFeatures ? InvalidateSiblings : InvalidateDescendants; |
| + if (InvalidationSet* invalidationSet = invalidationSetForSelector(*current, type)) { |
| + addFeaturesToInvalidationSet(*invalidationSet, siblingFeatures ? *siblingFeatures : descendantFeatures); |
|
Timothy Loh
2015/09/10 06:09:40
This would probably be clearer if we did this sepa
Eric Willigers
2015/09/14 07:20:23
Done.
|
| + |
| + if (siblingFeatures) { |
| + if (siblingFeatures == &descendantFeatures) |
| + invalidationSet->setAppliesDirectly(); |
| + else |
| + addFeaturesToInvalidationSet(invalidationSet->ensureInvalidationSet(), descendantFeatures); |
| + } |
| } else { |
| if (current->isTreeBoundaryCrossing()) |
| - features.treeBoundaryCrossing = true; |
| + descendantFeatures.treeBoundaryCrossing = true; |
| if (current->isInsertionPointCrossing()) |
| - features.insertionPointCrossing = true; |
| + descendantFeatures.insertionPointCrossing = true; |
| if (const CSSSelectorList* selectorList = current->selectorList()) { |
| ASSERT(supportsInvalidationWithSelectorList(current->pseudoType())); |
| - for (const CSSSelector* selector = selectorList->first(); selector; selector = CSSSelectorList::next(*selector)) |
| - addFeaturesToInvalidationSets(*selector, features); |
| + for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector)) |
| + addFeaturesToInvalidationSets(subSelector, siblingFeatures, descendantFeatures); |
| } |
| } |
| @@ -422,9 +441,29 @@ void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector& selector, |
| continue; |
| if (current->isShadowSelector()) |
| - features.treeBoundaryCrossing = true; |
| + descendantFeatures.treeBoundaryCrossing = true; |
| - features.adjacent = current->isAdjacentSelector(); |
| + if (!current->isAdjacentSelector()) { |
| + selector = current->tagHistory(); |
| + siblingFeatures = nullptr; |
| + continue; |
| + } |
| + |
| + if (siblingFeatures) { |
| + if (siblingFeatures->maxDirectAdjacentSelectors != std::numeric_limits<unsigned>::max()) { |
| + if (current->relation() == CSSSelector::DirectAdjacent) |
| + siblingFeatures->maxDirectAdjacentSelectors++; |
| + else |
| + siblingFeatures->maxDirectAdjacentSelectors = std::numeric_limits<unsigned>::max(); |
| + } |
| + } else { |
| + localFeatures = InvalidationSetFeatures(); |
| + auto result = extractInvalidationSetFeatures(*selector, localFeatures, false); |
| + if (result.first) |
|
Timothy Loh
2015/09/10 06:09:40
this might always be non-null?
Eric Willigers
2015/09/14 07:20:23
Acknowledged.
|
| + localFeatures.forceSubtree = result.second == ForceSubtree; |
| + |
| + siblingFeatures = &localFeatures; |
| + } |
| } |
| } |
| @@ -442,38 +481,6 @@ void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) |
| uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); |
| } |
| -DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const AtomicString& className) |
| -{ |
| - InvalidationSetMap::AddResult addResult = m_classInvalidationSets.add(className, nullptr); |
| - if (addResult.isNewEntry) |
| - addResult.storedValue->value = DescendantInvalidationSet::create(); |
| - return *addResult.storedValue->value; |
| -} |
| - |
| -DescendantInvalidationSet& RuleFeatureSet::ensureAttributeInvalidationSet(const AtomicString& attributeName) |
| -{ |
| - InvalidationSetMap::AddResult addResult = m_attributeInvalidationSets.add(attributeName, nullptr); |
| - if (addResult.isNewEntry) |
| - addResult.storedValue->value = DescendantInvalidationSet::create(); |
| - return *addResult.storedValue->value; |
| -} |
| - |
| -DescendantInvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(const AtomicString& id) |
| -{ |
| - InvalidationSetMap::AddResult addResult = m_idInvalidationSets.add(id, nullptr); |
| - if (addResult.isNewEntry) |
| - addResult.storedValue->value = DescendantInvalidationSet::create(); |
| - return *addResult.storedValue->value; |
| -} |
| - |
| -DescendantInvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(CSSSelector::PseudoType pseudoType) |
| -{ |
| - PseudoTypeInvalidationSetMap::AddResult addResult = m_pseudoInvalidationSets.add(pseudoType, nullptr); |
| - if (addResult.isNewEntry) |
| - addResult.storedValue->value = DescendantInvalidationSet::create(); |
| - return *addResult.storedValue->value; |
| -} |
| - |
| void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, RuleFeatureSet::FeatureMetadata& metadata) |
| { |
| unsigned maxDirectAdjacentSelectors = 0; |
| @@ -522,14 +529,14 @@ void RuleFeatureSet::FeatureMetadata::clear() |
| void RuleFeatureSet::add(const RuleFeatureSet& other) |
| { |
| - for (const auto& invalidationSet : other.m_classInvalidationSets) |
| - ensureClassInvalidationSet(invalidationSet.key).combine(*invalidationSet.value); |
| - for (const auto& invalidationSet : other.m_attributeInvalidationSets) |
| - ensureAttributeInvalidationSet(invalidationSet.key).combine(*invalidationSet.value); |
| - for (const auto& invalidationSet : other.m_idInvalidationSets) |
| - ensureIdInvalidationSet(invalidationSet.key).combine(*invalidationSet.value); |
| - for (const auto& invalidationSet : other.m_pseudoInvalidationSets) |
| - ensurePseudoInvalidationSet(static_cast<CSSSelector::PseudoType>(invalidationSet.key)).combine(*invalidationSet.value); |
| + for (const auto& entry : other.m_classInvalidationSets) |
| + ensureClassInvalidationData(entry.key).combine(*entry.value); |
| + for (const auto& entry : other.m_attributeInvalidationSets) |
| + ensureAttributeInvalidationData(entry.key).combine(*entry.value); |
| + for (const auto& entry : other.m_idInvalidationSets) |
| + ensureIdInvalidationData(entry.key).combine(*entry.value); |
| + for (const auto& entry : other.m_pseudoInvalidationSets) |
| + ensurePseudoInvalidationData(static_cast<CSSSelector::PseudoType>(entry.key)).combine(*entry.value); |
| m_metadata.add(other.m_metadata); |
| @@ -547,35 +554,63 @@ void RuleFeatureSet::clear() |
| m_idInvalidationSets.clear(); |
| } |
| -void RuleFeatureSet::collectInvalidationSetsForClass(InvalidationSetVector& invalidationSets, Element& element, const AtomicString& className) const |
| +void RuleFeatureSet::collectInvalidationSetsForClass(InvalidationSetVector& descendant, InvalidationSetVector& sibling, Element& element, const AtomicString& className) const |
| { |
| - if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_classInvalidationSets.get(className)) { |
| - TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, classChange, className); |
| - invalidationSets.append(invalidationSet); |
| + if (RefPtrWillBeRawPtr<InvalidationData> invalidationData = m_classInvalidationSets.get(className)) { |
| + if (invalidationData->descendants()) { |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationData->descendants(), classChange, className); |
| + descendant.append(invalidationData->descendants()); |
| + } |
| + if (invalidationData->siblings()) { |
| + if (element.parentElement()) |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(*element.parentElement(), *invalidationData->siblings(), classChange, className); |
| + sibling.append(invalidationData->siblings()); |
| + } |
| } |
| } |
| -void RuleFeatureSet::collectInvalidationSetsForId(InvalidationSetVector& invalidationSets, Element& element, const AtomicString& id) const |
| +void RuleFeatureSet::collectInvalidationSetsForId(InvalidationSetVector& descendant, InvalidationSetVector& sibling, Element& element, const AtomicString& id) const |
| { |
| - if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_idInvalidationSets.get(id)) { |
| - TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, idChange, id); |
| - invalidationSets.append(invalidationSet); |
| + if (RefPtrWillBeRawPtr<InvalidationData> invalidationData = m_idInvalidationSets.get(id)) { |
| + if (invalidationData->descendants()) { |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationData->descendants(), idChange, id); |
| + descendant.append(invalidationData->descendants()); |
| + } |
| + if (invalidationData->siblings()) { |
| + if (element.parentElement()) |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(*element.parentElement(), *invalidationData->siblings(), idChange, id); |
| + sibling.append(invalidationData->siblings()); |
| + } |
| } |
| } |
| -void RuleFeatureSet::collectInvalidationSetsForAttribute(InvalidationSetVector& invalidationSets, Element& element, const QualifiedName& attributeName) const |
| +void RuleFeatureSet::collectInvalidationSetsForAttribute(InvalidationSetVector& descendant, InvalidationSetVector& sibling, Element& element, const QualifiedName& attributeName) const |
| { |
| - if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_attributeInvalidationSets.get(attributeName.localName())) { |
| - TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, attributeChange, attributeName); |
| - invalidationSets.append(invalidationSet); |
| + if (RefPtrWillBeRawPtr<InvalidationData> invalidationData = m_attributeInvalidationSets.get(attributeName.localName())) { |
| + if (invalidationData->descendants()) { |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationData->descendants(), attributeChange, attributeName); |
| + descendant.append(invalidationData->descendants()); |
| + } |
| + if (invalidationData->siblings()) { |
| + if (element.parentElement()) |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(*element.parentElement(), *invalidationData->siblings(), attributeChange, attributeName); |
| + sibling.append(invalidationData->siblings()); |
| + } |
| } |
| } |
| -void RuleFeatureSet::collectInvalidationSetsForPseudoClass(InvalidationSetVector& invalidationSets, Element& element, CSSSelector::PseudoType pseudo) const |
| +void RuleFeatureSet::collectInvalidationSetsForPseudoClass(InvalidationSetVector& descendant, InvalidationSetVector& sibling, Element& element, CSSSelector::PseudoType pseudo) const |
| { |
| - if (RefPtrWillBeRawPtr<DescendantInvalidationSet> invalidationSet = m_pseudoInvalidationSets.get(pseudo)) { |
| - TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationSet, pseudoChange, pseudo); |
| - invalidationSets.append(invalidationSet); |
| + if (RefPtrWillBeRawPtr<InvalidationData> invalidationData = m_pseudoInvalidationSets.get(pseudo)) { |
| + if (invalidationData->descendants()) { |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(element, *invalidationData->descendants(), pseudoChange, pseudo); |
| + descendant.append(invalidationData->descendants()); |
| + } |
| + if (invalidationData->siblings()) { |
| + if (element.parentElement()) |
| + TRACE_SCHEDULE_STYLE_INVALIDATION(*element.parentElement(), *invalidationData->siblings(), pseudoChange, pseudo); |
| + sibling.append(invalidationData->siblings()); |
| + } |
| } |
| } |