| Index: Source/core/css/RuleFeature.cpp
|
| diff --git a/Source/core/css/RuleFeature.cpp b/Source/core/css/RuleFeature.cpp
|
| index 0b5311cbcabc3eeb41b3c50f51360bafc94a8cfa..b75abca9e855463c30ef2e7fa7dd66c9a5076372 100644
|
| --- a/Source/core/css/RuleFeature.cpp
|
| +++ b/Source/core/css/RuleFeature.cpp
|
| @@ -238,14 +238,14 @@ RuleFeatureSet::~RuleFeatureSet()
|
| {
|
| }
|
|
|
| -DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector)
|
| +DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector, InvalidateType type)
|
| {
|
| 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 (DescendantInvalidationSet* 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)
|
| {
|
| + invalidationSet.setMaxDirectAdjacentSelectors(features.maxDirectAdjacentSelectors);
|
| +
|
| 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 (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current, type)) {
|
| + addFeaturesToInvalidationSet(*invalidationSet, siblingFeatures ? *siblingFeatures : descendantFeatures);
|
| +
|
| + if (siblingFeatures) {
|
| + if (siblingFeatures == &descendantFeatures)
|
| + invalidationSet->setAppliesDirectly();
|
| + else
|
| + addFeaturesToInvalidationSet(invalidationSet->ensureDescendantInvalidationSet(), 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)
|
| + 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());
|
| + }
|
| }
|
| }
|
|
|
|
|