Commit 6c4b4fbb authored by rune's avatar rune Committed by Commit bot

Don't add rule feature data for rules which may never match.

:host and :host-context must always be in the rightmost compound with
no other simple selectors except a succeding pseudo element in order to
match as the host element is feature-less in that context. It's however
not an invalid selector according to the CSS Scoping spec, so we
shouldn't drop it at parse time.

We could potentially skip adding other selectors to rulesets as well
including selectors like:

:hover:not(:hover), div:not(div), ::content and ::slotted not in
shadow trees, etc.

R=kochi@chromium.org,ericwilligers@chromium.org
BUG=489481

Review URL: https://codereview.chromium.org/1703893002

Cr-Commit-Position: refs/heads/master@{#376116}
parent 3106ad77
...@@ -253,7 +253,6 @@ public: ...@@ -253,7 +253,6 @@ public:
bool isAdjacentSelector() const { return m_relation == DirectAdjacent || m_relation == IndirectAdjacent; } bool isAdjacentSelector() const { return m_relation == DirectAdjacent || m_relation == IndirectAdjacent; }
bool isShadowSelector() const { return m_relation == ShadowPseudo || m_relation == ShadowDeep; } bool isShadowSelector() const { return m_relation == ShadowPseudo || m_relation == ShadowDeep; }
bool isSiblingPseudo() const;
bool isAttributeSelector() const { return m_match >= FirstAttributeSelectorMatch; } bool isAttributeSelector() const { return m_match >= FirstAttributeSelectorMatch; }
bool isHostPseudoClass() const { return m_pseudoType == PseudoHost || m_pseudoType == PseudoHostContext; } bool isHostPseudoClass() const { return m_pseudoType == PseudoHost || m_pseudoType == PseudoHostContext; }
bool isInsertionPointCrossing() const { return m_pseudoType == PseudoHostContext || m_pseudoType == PseudoContent || m_pseudoType == PseudoSlotted; } bool isInsertionPointCrossing() const { return m_pseudoType == PseudoHostContext || m_pseudoType == PseudoContent || m_pseudoType == PseudoSlotted; }
...@@ -365,22 +364,6 @@ inline CSSSelector::AttributeMatchType CSSSelector::attributeMatchType() const ...@@ -365,22 +364,6 @@ inline CSSSelector::AttributeMatchType CSSSelector::attributeMatchType() const
return m_data.m_rareData->m_bits.m_attributeMatchType; return m_data.m_rareData->m_bits.m_attributeMatchType;
} }
inline bool CSSSelector::isSiblingPseudo() const
{
PseudoType type = pseudoType();
return type == PseudoEmpty
|| type == PseudoFirstChild
|| type == PseudoFirstOfType
|| type == PseudoLastChild
|| type == PseudoLastOfType
|| type == PseudoOnlyChild
|| type == PseudoOnlyOfType
|| type == PseudoNthChild
|| type == PseudoNthOfType
|| type == PseudoNthLastChild
|| type == PseudoNthLastOfType;
}
inline bool CSSSelector::isASCIILower(const AtomicString& value) inline bool CSSSelector::isASCIILower(const AtomicString& value)
{ {
for (size_t i = 0; i < value.length(); ++i) { for (size_t i = 0; i < value.length(); ++i) {
......
...@@ -556,55 +556,90 @@ void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector, ...@@ -556,55 +556,90 @@ void RuleFeatureSet::addFeaturesToInvalidationSets(const CSSSelector* selector,
} }
} }
void RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData) RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromRuleData(const RuleData& ruleData)
{ {
updateInvalidationSets(ruleData);
FeatureMetadata metadata; FeatureMetadata metadata;
collectFeaturesFromSelector(ruleData.selector(), metadata); if (collectFeaturesFromSelector(ruleData.selector(), metadata) == SelectorNeverMatches)
return SelectorNeverMatches;
m_metadata.add(metadata); m_metadata.add(metadata);
if (metadata.foundSiblingSelector) if (metadata.foundSiblingSelector)
siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); siblingRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
if (ruleData.containsUncommonAttributeSelector()) if (ruleData.containsUncommonAttributeSelector())
uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin())); uncommonAttributeRules.append(RuleFeature(ruleData.rule(), ruleData.selectorIndex(), ruleData.hasDocumentSecurityOrigin()));
updateInvalidationSets(ruleData);
return SelectorMayMatch;
} }
void RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, RuleFeatureSet::FeatureMetadata& metadata) RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromSelector(const CSSSelector& selector, RuleFeatureSet::FeatureMetadata& metadata)
{ {
unsigned maxDirectAdjacentSelectors = 0; unsigned maxDirectAdjacentSelectors = 0;
CSSSelector::Relation relation = CSSSelector::Descendant;
bool foundHostPseudo = false;
for (const CSSSelector* current = &selector; current; current = current->tagHistory()) { for (const CSSSelector* current = &selector; current; current = current->tagHistory()) {
if (current->pseudoType() == CSSSelector::PseudoFirstLine) switch (current->pseudoType()) {
case CSSSelector::PseudoFirstLine:
metadata.usesFirstLineRules = true; metadata.usesFirstLineRules = true;
if (current->pseudoType() == CSSSelector::PseudoWindowInactive) break;
case CSSSelector::PseudoWindowInactive:
metadata.usesWindowInactiveSelector = true; metadata.usesWindowInactiveSelector = true;
if (current->relation() == CSSSelector::DirectAdjacent) { break;
case CSSSelector::PseudoEmpty:
case CSSSelector::PseudoFirstChild:
case CSSSelector::PseudoFirstOfType:
case CSSSelector::PseudoLastChild:
case CSSSelector::PseudoLastOfType:
case CSSSelector::PseudoOnlyChild:
case CSSSelector::PseudoOnlyOfType:
case CSSSelector::PseudoNthChild:
case CSSSelector::PseudoNthOfType:
case CSSSelector::PseudoNthLastChild:
case CSSSelector::PseudoNthLastOfType:
if (!metadata.foundInsertionPointCrossing)
metadata.foundSiblingSelector = true;
break;
case CSSSelector::PseudoHost:
case CSSSelector::PseudoHostContext:
if (relation == CSSSelector::SubSelector)
return SelectorNeverMatches;
if (!current->isLastInTagHistory() && current->tagHistory()->match() != CSSSelector::PseudoElement)
return SelectorNeverMatches;
foundHostPseudo = true;
// fall through.
default:
if (const CSSSelectorList* selectorList = current->selectorList()) {
for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector))
collectFeaturesFromSelector(*subSelector, metadata);
}
break;
}
if (current->relationIsAffectedByPseudoContent() || current->pseudoType() == CSSSelector::PseudoSlotted)
metadata.foundInsertionPointCrossing = true;
relation = current->relation();
if (foundHostPseudo && relation != CSSSelector::SubSelector)
return SelectorNeverMatches;
if (relation == CSSSelector::DirectAdjacent) {
maxDirectAdjacentSelectors++; maxDirectAdjacentSelectors++;
} else if (maxDirectAdjacentSelectors } else if (maxDirectAdjacentSelectors
&& ((current->relation() != CSSSelector::SubSelector) || current->isLastInTagHistory())) { && ((relation != CSSSelector::SubSelector) || current->isLastInTagHistory())) {
if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors) if (maxDirectAdjacentSelectors > metadata.maxDirectAdjacentSelectors)
metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors; metadata.maxDirectAdjacentSelectors = maxDirectAdjacentSelectors;
maxDirectAdjacentSelectors = 0; maxDirectAdjacentSelectors = 0;
} }
if (!metadata.foundInsertionPointCrossing && current->isSiblingPseudo())
metadata.foundSiblingSelector = true;
if (const CSSSelectorList* selectorList = current->selectorList()) {
for (const CSSSelector* subSelector = selectorList->first(); subSelector; subSelector = CSSSelectorList::next(*subSelector))
collectFeaturesFromSelector(*subSelector, metadata);
}
if (current->relationIsAffectedByPseudoContent()
|| current->pseudoType() == CSSSelector::PseudoHost
|| current->pseudoType() == CSSSelector::PseudoHostContext
|| current->pseudoType() == CSSSelector::PseudoSlotted) {
metadata.foundInsertionPointCrossing = true;
}
if (!metadata.foundInsertionPointCrossing && current->isAdjacentSelector()) if (!metadata.foundInsertionPointCrossing && current->isAdjacentSelector())
metadata.foundSiblingSelector = true; metadata.foundSiblingSelector = true;
} }
ASSERT(!maxDirectAdjacentSelectors); ASSERT(!maxDirectAdjacentSelectors);
return SelectorMayMatch;
} }
void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other) void RuleFeatureSet::FeatureMetadata::add(const FeatureMetadata& other)
......
...@@ -59,7 +59,9 @@ public: ...@@ -59,7 +59,9 @@ public:
void add(const RuleFeatureSet&); void add(const RuleFeatureSet&);
void clear(); void clear();
void collectFeaturesFromRuleData(const RuleData&); enum SelectorPreMatch { SelectorNeverMatches, SelectorMayMatch };
SelectorPreMatch collectFeaturesFromRuleData(const RuleData&);
bool usesSiblingRules() const { return !siblingRules.isEmpty(); } bool usesSiblingRules() const { return !siblingRules.isEmpty(); }
bool usesFirstLineRules() const { return m_metadata.usesFirstLineRules; } bool usesFirstLineRules() const { return m_metadata.usesFirstLineRules; }
...@@ -118,7 +120,7 @@ private: ...@@ -118,7 +120,7 @@ private:
unsigned maxDirectAdjacentSelectors = 0; unsigned maxDirectAdjacentSelectors = 0;
}; };
void collectFeaturesFromSelector(const CSSSelector&, FeatureMetadata&); SelectorPreMatch collectFeaturesFromSelector(const CSSSelector&, FeatureMetadata&);
InvalidationSet& ensureClassInvalidationSet(const AtomicString& className, InvalidationType); InvalidationSet& ensureClassInvalidationSet(const AtomicString& className, InvalidationType);
InvalidationSet& ensureAttributeInvalidationSet(const AtomicString& attributeName, InvalidationType); InvalidationSet& ensureAttributeInvalidationSet(const AtomicString& attributeName, InvalidationType);
......
...@@ -35,22 +35,13 @@ public: ...@@ -35,22 +35,13 @@ public:
m_document->body()->setInnerHTML("<b><i></i></b>", ASSERT_NO_EXCEPTION); m_document->body()->setInnerHTML("<b><i></i></b>", ASSERT_NO_EXCEPTION);
} }
void updateInvalidationSets(const String& selectorText) RuleFeatureSet::SelectorPreMatch collectFeatures(const String& selectorText)
{ {
CSSSelectorList selectorList = CSSParser::parseSelector(strictCSSParserContext(), nullptr, selectorText); CSSSelectorList selectorList = CSSParser::parseSelector(strictCSSParserContext(), nullptr, selectorText);
RefPtrWillBeRawPtr<StyleRule> styleRule = StyleRule::create(std::move(selectorList), MutableStylePropertySet::create(HTMLStandardMode)); RefPtrWillBeRawPtr<StyleRule> styleRule = StyleRule::create(std::move(selectorList), MutableStylePropertySet::create(HTMLStandardMode));
RuleData ruleData(styleRule.get(), 0, 0, RuleHasNoSpecialState); RuleData ruleData(styleRule.get(), 0, 0, RuleHasNoSpecialState);
m_ruleFeatureSet.updateInvalidationSets(ruleData); return m_ruleFeatureSet.collectFeaturesFromRuleData(ruleData);
}
void collectFeatures(const String& selectorText)
{
CSSSelectorList selectorList = CSSParser::parseSelector(strictCSSParserContext(), nullptr, selectorText);
RefPtrWillBeRawPtr<StyleRule> styleRule = StyleRule::create(std::move(selectorList), MutableStylePropertySet::create(HTMLStandardMode));
RuleData ruleData(styleRule.get(), 0, 0, RuleHasNoSpecialState);
m_ruleFeatureSet.collectFeaturesFromRuleData(ruleData);
} }
void collectInvalidationSetsForClass(InvalidationLists& invalidationLists, const AtomicString& className) const void collectInvalidationSetsForClass(InvalidationLists& invalidationLists, const AtomicString& className) const
...@@ -204,7 +195,7 @@ private: ...@@ -204,7 +195,7 @@ private:
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling1) TEST_F(RuleFeatureSetTest, interleavedDescendantSibling1)
{ {
updateInvalidationSets(".p"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".p"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "p"); collectInvalidationSetsForClass(invalidationLists, "p");
...@@ -214,7 +205,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling1) ...@@ -214,7 +205,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling1)
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling2) TEST_F(RuleFeatureSetTest, interleavedDescendantSibling2)
{ {
updateInvalidationSets(".o + .p"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".o + .p"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "o"); collectInvalidationSetsForClass(invalidationLists, "o");
...@@ -224,7 +215,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling2) ...@@ -224,7 +215,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling2)
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling3) TEST_F(RuleFeatureSetTest, interleavedDescendantSibling3)
{ {
updateInvalidationSets(".m + .n .o + .p"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".m + .n .o + .p"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "n"); collectInvalidationSetsForClass(invalidationLists, "n");
...@@ -235,7 +226,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling3) ...@@ -235,7 +226,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling3)
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling4) TEST_F(RuleFeatureSetTest, interleavedDescendantSibling4)
{ {
updateInvalidationSets(".m + .n .o + .p"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".m + .n .o + .p"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "m"); collectInvalidationSetsForClass(invalidationLists, "m");
...@@ -245,7 +236,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling4) ...@@ -245,7 +236,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling4)
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling5) TEST_F(RuleFeatureSetTest, interleavedDescendantSibling5)
{ {
updateInvalidationSets(".l ~ .m + .n .o + .p"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".l ~ .m + .n .o + .p"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "l"); collectInvalidationSetsForClass(invalidationLists, "l");
...@@ -255,7 +246,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling5) ...@@ -255,7 +246,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling5)
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling6) TEST_F(RuleFeatureSetTest, interleavedDescendantSibling6)
{ {
updateInvalidationSets(".k > .l ~ .m + .n .o + .p"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".k > .l ~ .m + .n .o + .p"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "k"); collectInvalidationSetsForClass(invalidationLists, "k");
...@@ -266,7 +257,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling6) ...@@ -266,7 +257,7 @@ TEST_F(RuleFeatureSetTest, interleavedDescendantSibling6)
TEST_F(RuleFeatureSetTest, anySibling) TEST_F(RuleFeatureSetTest, anySibling)
{ {
updateInvalidationSets(":-webkit-any(.q, .r) ~ .s .t"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":-webkit-any(.q, .r) ~ .s .t"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "q"); collectInvalidationSetsForClass(invalidationLists, "q");
...@@ -276,7 +267,7 @@ TEST_F(RuleFeatureSetTest, anySibling) ...@@ -276,7 +267,7 @@ TEST_F(RuleFeatureSetTest, anySibling)
TEST_F(RuleFeatureSetTest, any) TEST_F(RuleFeatureSetTest, any)
{ {
updateInvalidationSets(":-webkit-any(.w, .x)"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":-webkit-any(.w, .x)"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "w"); collectInvalidationSetsForClass(invalidationLists, "w");
...@@ -286,7 +277,7 @@ TEST_F(RuleFeatureSetTest, any) ...@@ -286,7 +277,7 @@ TEST_F(RuleFeatureSetTest, any)
TEST_F(RuleFeatureSetTest, siblingAny) TEST_F(RuleFeatureSetTest, siblingAny)
{ {
updateInvalidationSets(".v ~ :-webkit-any(.w, .x)"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".v ~ :-webkit-any(.w, .x)"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "v"); collectInvalidationSetsForClass(invalidationLists, "v");
...@@ -296,7 +287,7 @@ TEST_F(RuleFeatureSetTest, siblingAny) ...@@ -296,7 +287,7 @@ TEST_F(RuleFeatureSetTest, siblingAny)
TEST_F(RuleFeatureSetTest, descendantSiblingAny) TEST_F(RuleFeatureSetTest, descendantSiblingAny)
{ {
updateInvalidationSets(".u .v ~ :-webkit-any(.w, .x)"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".u .v ~ :-webkit-any(.w, .x)"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "u"); collectInvalidationSetsForClass(invalidationLists, "u");
...@@ -306,7 +297,7 @@ TEST_F(RuleFeatureSetTest, descendantSiblingAny) ...@@ -306,7 +297,7 @@ TEST_F(RuleFeatureSetTest, descendantSiblingAny)
TEST_F(RuleFeatureSetTest, id) TEST_F(RuleFeatureSetTest, id)
{ {
updateInvalidationSets("#a #b"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("#a #b"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForId(invalidationLists, "a"); collectInvalidationSetsForId(invalidationLists, "a");
...@@ -315,7 +306,7 @@ TEST_F(RuleFeatureSetTest, id) ...@@ -315,7 +306,7 @@ TEST_F(RuleFeatureSetTest, id)
TEST_F(RuleFeatureSetTest, attribute) TEST_F(RuleFeatureSetTest, attribute)
{ {
updateInvalidationSets("[c] [d]"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("[c] [d]"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForAttribute(invalidationLists, QualifiedName("", "c", "")); collectInvalidationSetsForAttribute(invalidationLists, QualifiedName("", "c", ""));
...@@ -324,7 +315,7 @@ TEST_F(RuleFeatureSetTest, attribute) ...@@ -324,7 +315,7 @@ TEST_F(RuleFeatureSetTest, attribute)
TEST_F(RuleFeatureSetTest, pseudoClass) TEST_F(RuleFeatureSetTest, pseudoClass)
{ {
updateInvalidationSets(":valid"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":valid"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForPseudoClass(invalidationLists, CSSSelector::PseudoValid); collectInvalidationSetsForPseudoClass(invalidationLists, CSSSelector::PseudoValid);
...@@ -333,7 +324,7 @@ TEST_F(RuleFeatureSetTest, pseudoClass) ...@@ -333,7 +324,7 @@ TEST_F(RuleFeatureSetTest, pseudoClass)
TEST_F(RuleFeatureSetTest, tagName) TEST_F(RuleFeatureSetTest, tagName)
{ {
updateInvalidationSets(":valid e"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":valid e"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForPseudoClass(invalidationLists, CSSSelector::PseudoValid); collectInvalidationSetsForPseudoClass(invalidationLists, CSSSelector::PseudoValid);
...@@ -342,138 +333,206 @@ TEST_F(RuleFeatureSetTest, tagName) ...@@ -342,138 +333,206 @@ TEST_F(RuleFeatureSetTest, tagName)
TEST_F(RuleFeatureSetTest, contentPseudo) TEST_F(RuleFeatureSetTest, contentPseudo)
{ {
updateInvalidationSets(".a ::content .b"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a ::content .b"));
updateInvalidationSets(".a .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a .c"));
InvalidationLists invalidationLists; InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "a"); collectInvalidationSetsForClass(invalidationLists, "a");
expectClassInvalidation("c", invalidationLists.descendants); expectClassInvalidation("c", invalidationLists.descendants);
updateInvalidationSets(".a .b"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a .b"));
invalidationLists.descendants.clear(); invalidationLists.descendants.clear();
collectInvalidationSetsForClass(invalidationLists, "a"); collectInvalidationSetsForClass(invalidationLists, "a");
expectClassesInvalidation("b", "c", invalidationLists.descendants); expectClassesInvalidation("b", "c", invalidationLists.descendants);
} }
TEST_F(RuleFeatureSetTest, nonMatchingHost)
{
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(".a:host"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("*:host(.a)"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("*:host .a"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("div :host .a"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(":host:hover .a"));
InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "a");
expectNoInvalidation(invalidationLists.descendants);
}
TEST_F(RuleFeatureSetTest, nonMatchingHostContext)
{
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(".a:host-context(*)"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("*:host-context(.a)"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("*:host-context(*) .a"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("div :host-context(div) .a"));
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(":host-context(div):hover .a"));
InvalidationLists invalidationLists;
collectInvalidationSetsForClass(invalidationLists, "a");
expectNoInvalidation(invalidationLists.descendants);
}
TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo) TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo)
{ {
collectFeatures("a + b ::content .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("a + b ::content .c"));
expectSiblingRuleCount(0); expectSiblingRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo2) TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo2)
{ {
collectFeatures("a + ::content .b"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("a + ::content .b"));
expectSiblingRuleCount(0); expectSiblingRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, siblingRulesAfterContentPseudo) TEST_F(RuleFeatureSetTest, siblingRulesAfterContentPseudo)
{ {
collectFeatures(".a ::content .b + .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a ::content .b + .c"));
expectSiblingRuleCount(1); expectSiblingRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, siblingRulesNthBeforeContentPseudo) TEST_F(RuleFeatureSetTest, siblingRulesNthBeforeContentPseudo)
{ {
collectFeatures(":nth-child(2) ::content .a"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":nth-child(2) ::content .a"));
expectSiblingRuleCount(0); expectSiblingRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, siblingRulesNthAfterContentPseudo) TEST_F(RuleFeatureSetTest, siblingRulesNthAfterContentPseudo)
{ {
collectFeatures(".a ::content :nth-child(2)"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a ::content :nth-child(2)"));
expectSiblingRuleCount(1); expectSiblingRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, siblingRulesBeforeDeep) TEST_F(RuleFeatureSetTest, siblingRulesBeforeDeep)
{ {
collectFeatures("a + b /deep/ .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("a + b /deep/ .c"));
expectSiblingRuleCount(1); expectSiblingRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, siblingRulesAfterDeep) TEST_F(RuleFeatureSetTest, siblingRulesAfterDeep)
{ {
collectFeatures(".a /deep/ .b + .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a /deep/ .b + .c"));
expectSiblingRuleCount(1); expectSiblingRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, siblingRulesBeforeShadow) TEST_F(RuleFeatureSetTest, siblingRulesBeforeShadow)
{ {
collectFeatures(".a + .b::shadow .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a + .b::shadow .c"));
expectSiblingRuleCount(1); expectSiblingRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, siblingRulesAfterShadow) TEST_F(RuleFeatureSetTest, siblingRulesAfterShadow)
{ {
collectFeatures(".a ::shadow .b + .c"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a ::shadow .b + .c"));
expectSiblingRuleCount(1); expectSiblingRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, siblingRulesBeforeSlotted) TEST_F(RuleFeatureSetTest, siblingRulesBeforeSlotted)
{ {
collectFeatures(".a + ::slotted(.b)"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(".a + ::slotted(.b)"));
expectSiblingRuleCount(0); expectSiblingRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, siblingRulesBeforeHost) TEST_F(RuleFeatureSetTest, siblingRulesBeforeHost)
{ {
collectFeatures(".a + :host(.b)"); EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(".a + :host(.b)"));
expectSiblingRuleCount(0); expectSiblingRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, siblingRulesBeforeHostContext) TEST_F(RuleFeatureSetTest, siblingRulesBeforeHostContext)
{ {
collectFeatures(".a + :host-context(.b)"); EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(".a + :host-context(.b)"));
expectSiblingRuleCount(0); expectSiblingRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterContentPseudo) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterContentPseudo)
{ {
collectFeatures("div ::content [attr]"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("div ::content [attr]"));
expectUncommonAttributeRuleCount(1); expectUncommonAttributeRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeContentPseudo) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeContentPseudo)
{ {
collectFeatures("[attr] ::content div"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("[attr] ::content div"));
expectUncommonAttributeRuleCount(0); expectUncommonAttributeRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesSlotted) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesSlotted)
{ {
collectFeatures("::slotted([attr])"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("::slotted([attr])"));
expectUncommonAttributeRuleCount(1); expectUncommonAttributeRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeSlotted) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeSlotted)
{ {
collectFeatures("[attr]::slotted(*)"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures("[attr]::slotted(*)"));
expectUncommonAttributeRuleCount(0); expectUncommonAttributeRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHost) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHost)
{ {
collectFeatures(":host([attr])"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":host([attr])"));
expectUncommonAttributeRuleCount(1); expectUncommonAttributeRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHost) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHost)
{ {
collectFeatures("[attr] :host"); EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("[attr] :host"));
expectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHost)
{
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(":host[attr]"));
expectUncommonAttributeRuleCount(0); expectUncommonAttributeRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHost2)
{
EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":host [attr]"));
expectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostBeforePseudo)
{
EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":host([attr])::before"));
expectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostContext) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostContext)
{ {
collectFeatures(":host-context([attr])"); EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":host-context([attr])"));
expectUncommonAttributeRuleCount(1); expectUncommonAttributeRuleCount(1);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext) TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext)
{ {
collectFeatures("[attr] :host-context(div)"); EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("[attr] :host-context(div)"));
expectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext2)
{
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures("[attr]:host-context(div)"));
expectUncommonAttributeRuleCount(0); expectUncommonAttributeRuleCount(0);
} }
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContext)
{
EXPECT_EQ(RuleFeatureSet::SelectorNeverMatches, collectFeatures(":host-context(*)[attr]"));
expectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContext2)
{
EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":host-context(*) [attr]"));
expectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContextBeforePseudo)
{
EXPECT_EQ(RuleFeatureSet::SelectorMayMatch, collectFeatures(":host-context([attr])::before"));
expectUncommonAttributeRuleCount(1);
}
} // namespace blink } // namespace blink
...@@ -78,12 +78,8 @@ static bool containsUncommonAttributeSelector(const CSSSelector& selector) ...@@ -78,12 +78,8 @@ static bool containsUncommonAttributeSelector(const CSSSelector& selector)
return true; return true;
if (selectorListContainsUncommonAttributeSelector(current)) if (selectorListContainsUncommonAttributeSelector(current))
return true; return true;
if (current->relationIsAffectedByPseudoContent() if (current->relationIsAffectedByPseudoContent() || current->pseudoType() == CSSSelector::PseudoSlotted)
|| current->pseudoType() == CSSSelector::PseudoHost
|| current->pseudoType() == CSSSelector::PseudoHostContext
|| current->pseudoType() == CSSSelector::PseudoSlotted) {
return false; return false;
}
if (current->relation() != CSSSelector::SubSelector) { if (current->relation() != CSSSelector::SubSelector) {
current = current->tagHistory(); current = current->tagHistory();
break; break;
...@@ -222,7 +218,8 @@ bool RuleSet::findBestRuleSetAndAdd(const CSSSelector& component, RuleData& rule ...@@ -222,7 +218,8 @@ bool RuleSet::findBestRuleSetAndAdd(const CSSSelector& component, RuleData& rule
void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags) void RuleSet::addRule(StyleRule* rule, unsigned selectorIndex, AddRuleFlags addRuleFlags)
{ {
RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags); RuleData ruleData(rule, selectorIndex, m_ruleCount++, addRuleFlags);
m_features.collectFeaturesFromRuleData(ruleData); if (m_features.collectFeaturesFromRuleData(ruleData) == RuleFeatureSet::SelectorNeverMatches)
return;
if (!findBestRuleSetAndAdd(ruleData.selector(), ruleData)) { if (!findBestRuleSetAndAdd(ruleData.selector(), ruleData)) {
// If we didn't find a specialized map to stick it in, file under universal rules. // If we didn't find a specialized map to stick it in, file under universal rules.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment