| Index: Source/core/css/RuleFeature.cpp
|
| diff --git a/Source/core/css/RuleFeature.cpp b/Source/core/css/RuleFeature.cpp
|
| index d49e8ad5c84db54ec5bd1b046881e124a9d161b7..a30022f1d0006737cbe311a7432ad9c3eba843c3 100644
|
| --- a/Source/core/css/RuleFeature.cpp
|
| +++ b/Source/core/css/RuleFeature.cpp
|
| @@ -34,15 +34,8 @@
|
| #include "core/css/CSSSelector.h"
|
| #include "core/css/CSSSelectorList.h"
|
| #include "core/css/RuleSet.h"
|
| -#include "core/css/invalidation/StyleInvalidator.h"
|
| -#include "core/dom/Document.h"
|
| #include "core/dom/Element.h"
|
| -#include "core/dom/ElementTraversal.h"
|
| #include "core/dom/Node.h"
|
| -#include "core/dom/NodeRenderStyle.h"
|
| -#include "core/dom/shadow/ElementShadow.h"
|
| -#include "core/dom/shadow/ShadowRoot.h"
|
| -#include "core/rendering/RenderObject.h"
|
| #include "wtf/BitVector.h"
|
|
|
| namespace WebCore {
|
| @@ -116,7 +109,7 @@ RuleFeatureSet::InvalidationSetMode RuleFeatureSet::supportsClassDescendantInval
|
| for (const CSSSelector* component = &selector; component; component = component->tagHistory()) {
|
|
|
| // FIXME: next up: Tag and Id.
|
| - if (component->m_match == CSSSelector::Class) {
|
| + if (component->m_match == CSSSelector::Class || component->isAttributeSelector()) {
|
| if (!foundDescendantRelation)
|
| foundIdent = true;
|
| } else if (!isSkippableComponentForInvalidation(*component)) {
|
| @@ -138,7 +131,7 @@ RuleFeatureSet::InvalidationSetMode RuleFeatureSet::supportsClassDescendantInval
|
| return foundIdent ? AddFeatures : UseLocalStyleChange;
|
| }
|
|
|
| -void extractClassIdOrTag(const CSSSelector& selector, Vector<AtomicString>& classes, AtomicString& id, AtomicString& tagName)
|
| +void extractClassIdTagOrAttribute(const CSSSelector& selector, Vector<AtomicString>& classes, AtomicString& id, AtomicString& tagName, Vector<AtomicString>& attributes)
|
| {
|
| if (selector.m_match == CSSSelector::Tag)
|
| tagName = selector.tagQName().localName();
|
| @@ -146,6 +139,8 @@ void extractClassIdOrTag(const CSSSelector& selector, Vector<AtomicString>& clas
|
| id = selector.value();
|
| else if (selector.m_match == CSSSelector::Class)
|
| classes.append(selector.value());
|
| + else if (selector.isAttributeSelector())
|
| + attributes.append(selector.attribute().localName());
|
| }
|
|
|
| RuleFeatureSet::RuleFeatureSet()
|
| @@ -153,7 +148,16 @@ RuleFeatureSet::RuleFeatureSet()
|
| {
|
| }
|
|
|
| -RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateClassInvalidationSets(const CSSSelector& selector)
|
| +DescendantInvalidationSet* RuleFeatureSet::invalidationSetForSelector(const CSSSelector& selector)
|
| +{
|
| + if (selector.m_match == CSSSelector::Class)
|
| + return &ensureClassInvalidationSet(selector.value());
|
| + if (selector.isAttributeSelector())
|
| + return &ensureAttributeInvalidationSet(selector.attribute().localName());
|
| + return 0;
|
| +}
|
| +
|
| +RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateInvalidationSets(const CSSSelector& selector)
|
| {
|
| InvalidationSetMode mode = supportsClassDescendantInvalidation(selector);
|
| if (mode != AddFeatures)
|
| @@ -162,37 +166,39 @@ RuleFeatureSet::InvalidationSetMode RuleFeatureSet::updateClassInvalidationSets(
|
| Vector<AtomicString> classes;
|
| AtomicString id;
|
| AtomicString tagName;
|
| + Vector<AtomicString> attributes;
|
|
|
| const CSSSelector* lastSelector = &selector;
|
| for (; lastSelector; lastSelector = lastSelector->tagHistory()) {
|
| - extractClassIdOrTag(*lastSelector, classes, id, tagName);
|
| - if (lastSelector->m_match == CSSSelector::Class)
|
| - ensureClassInvalidationSet(lastSelector->value());
|
| + extractClassIdTagOrAttribute(*lastSelector, classes, id, tagName, attributes);
|
| + // Initialize the entry in the invalidation set map, if supported.
|
| + invalidationSetForSelector(*lastSelector);
|
| +
|
| if (lastSelector->relation() != CSSSelector::SubSelector)
|
| break;
|
| }
|
|
|
| if (!lastSelector)
|
| return AddFeatures;
|
| -
|
| for (const CSSSelector* current = lastSelector->tagHistory(); current; current = current->tagHistory()) {
|
| - if (current->m_match == CSSSelector::Class) {
|
| - DescendantInvalidationSet& invalidationSet = ensureClassInvalidationSet(current->value());
|
| + if (DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current)) {
|
| if (!id.isEmpty())
|
| - invalidationSet.addId(id);
|
| + invalidationSet->addId(id);
|
| if (!tagName.isEmpty())
|
| - invalidationSet.addTagName(tagName);
|
| - for (Vector<AtomicString>::const_iterator it = classes.begin(); it != classes.end(); ++it) {
|
| - invalidationSet.addClass(*it);
|
| - }
|
| + invalidationSet->addTagName(tagName);
|
| + for (Vector<AtomicString>::const_iterator it = classes.begin(); it != classes.end(); ++it)
|
| + invalidationSet->addClass(*it);
|
| + for (Vector<AtomicString>::const_iterator it = attributes.begin(); it != attributes.end(); ++it)
|
| + invalidationSet->addAttribute(*it);
|
| }
|
| }
|
| return AddFeatures;
|
| }
|
|
|
| -void RuleFeatureSet::addAttributeInASelector(const AtomicString& attributeName)
|
| +void RuleFeatureSet::addContentAttr(const AtomicString& attributeName)
|
| {
|
| - m_metadata.attrsInRules.add(attributeName);
|
| + DescendantInvalidationSet& invalidationSet = ensureAttributeInvalidationSet(attributeName);
|
| + invalidationSet.setWholeSubtreeInvalid();
|
| }
|
|
|
| void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData)
|
| @@ -200,7 +206,7 @@ void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData)
|
| FeatureMetadata metadata;
|
| InvalidationSetMode mode = UseSubtreeStyleChange;
|
| if (m_targetedStyleRecalcEnabled)
|
| - mode = updateClassInvalidationSets(ruleData.selector());
|
| + mode = updateInvalidationSets(ruleData.selector());
|
|
|
| collectFeaturesFromSelector(ruleData.selector(), metadata, mode);
|
| m_metadata.add(metadata);
|
| @@ -219,6 +225,13 @@ DescendantInvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(const Atom
|
| 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;
|
| +}
|
| void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector)
|
| {
|
| collectFeaturesFromSelector(selector, m_metadata, UseSubtreeStyleChange);
|
| @@ -231,12 +244,11 @@ void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, Ru
|
| for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
|
| if (current->m_match == CSSSelector::Id) {
|
| metadata.idsInRules.add(current->value());
|
| - } else if (current->m_match == CSSSelector::Class && mode != AddFeatures) {
|
| - DescendantInvalidationSet& invalidationSet = ensureClassInvalidationSet(current->value());
|
| + } else if (mode != AddFeatures && (current->m_match == CSSSelector::Class || current->isAttributeSelector())) {
|
| + DescendantInvalidationSet* invalidationSet = invalidationSetForSelector(*current);
|
| + ASSERT(invalidationSet);
|
| if (mode == UseSubtreeStyleChange)
|
| - invalidationSet.setWholeSubtreeInvalid();
|
| - } else if (current->isAttributeSelector()) {
|
| - metadata.attrsInRules.add(current->attribute().localName());
|
| + invalidationSet->setWholeSubtreeInvalid();
|
| }
|
| if (current->pseudoType() == CSSSelector::PseudoFirstLine)
|
| metadata.usesFirstLineRules = true;
|
| @@ -276,15 +288,11 @@ void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other)
|
| HashSet<AtomicString>::const_iterator end = other.idsInRules.end();
|
| for (HashSet<AtomicString>::const_iterator it = other.idsInRules.begin(); it != end; ++it)
|
| idsInRules.add(*it);
|
| - end = other.attrsInRules.end();
|
| - for (HashSet<AtomicString>::const_iterator it = other.attrsInRules.begin(); it != end; ++it)
|
| - attrsInRules.add(*it);
|
| }
|
|
|
| void RuleFeatureSet::FeatureMetadata::clear()
|
| {
|
| idsInRules.clear();
|
| - attrsInRules.clear();
|
| usesFirstLineRules = false;
|
| foundSiblingSelector = false;
|
| maxDirectAdjacentSelectors = 0;
|
| @@ -292,9 +300,10 @@ void RuleFeatureSet::FeatureMetadata::clear()
|
|
|
| void RuleFeatureSet::add(const RuleFeatureSet& other)
|
| {
|
| - for (InvalidationSetMap::const_iterator it = other.m_classInvalidationSets.begin(); it != other.m_classInvalidationSets.end(); ++it) {
|
| + for (InvalidationSetMap::const_iterator it = other.m_classInvalidationSets.begin(); it != other.m_classInvalidationSets.end(); ++it)
|
| ensureClassInvalidationSet(it->key).combine(*it->value);
|
| - }
|
| + for (InvalidationSetMap::const_iterator it = other.m_attributeInvalidationSets.begin(); it != other.m_attributeInvalidationSets.end(); ++it)
|
| + ensureAttributeInvalidationSet(it->key).combine(*it->value);
|
|
|
| m_metadata.add(other.m_metadata);
|
|
|
| @@ -308,6 +317,7 @@ void RuleFeatureSet::clear()
|
| uncommonAttributeRules.clear();
|
| m_metadata.clear();
|
| m_classInvalidationSets.clear();
|
| + m_attributeInvalidationSets.clear();
|
| m_pendingInvalidationMap.clear();
|
| }
|
|
|
| @@ -352,6 +362,14 @@ void RuleFeatureSet::scheduleStyleInvalidationForClassChange(const SpaceSplitStr
|
| }
|
| }
|
|
|
| +void RuleFeatureSet::scheduleStyleInvalidationForAttributeChange(const QualifiedName& attributeName, Element* element)
|
| +{
|
| + if (RefPtr<DescendantInvalidationSet> invalidationSet = m_attributeInvalidationSets.get(attributeName.localName())) {
|
| + ensurePendingInvalidationList(element).append(invalidationSet);
|
| + element->setNeedsStyleInvalidation();
|
| + }
|
| +}
|
| +
|
| void RuleFeatureSet::addClassToInvalidationSet(const AtomicString& className, Element* element)
|
| {
|
| if (RefPtr<DescendantInvalidationSet> invalidationSet = m_classInvalidationSets.get(className)) {
|
|
|