| Index: third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
|
| diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
|
| index 076f85f14eb4f2913a189c91955f70fb1c273c62..438614bcf6af433b3ac38befe04f98e4f91e5ccb 100644
|
| --- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
|
| +++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
|
| @@ -135,16 +135,26 @@ PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector(CSSParse
|
| OwnPtr<CSSParserSelector> selector = consumeCompoundSelector(range);
|
| if (!selector)
|
| return nullptr;
|
| +
|
| + bool previousCompoundHasContentPseudo = false;
|
| +
|
| + for (CSSParserSelector* simple = selector.get(); simple && !previousCompoundHasContentPseudo; simple = simple->tagHistory())
|
| + previousCompoundHasContentPseudo = simple->pseudoType() == CSSSelector::PseudoContent;
|
| +
|
| while (CSSSelector::Relation combinator = consumeCombinator(range)) {
|
| OwnPtr<CSSParserSelector> nextSelector = consumeCompoundSelector(range);
|
| if (!nextSelector)
|
| return combinator == CSSSelector::Descendant ? selector.release() : nullptr;
|
| CSSParserSelector* end = nextSelector.get();
|
| - while (end->tagHistory())
|
| + bool compoundHasContentPseudo = end->pseudoType() == CSSSelector::PseudoContent;
|
| + while (end->tagHistory()) {
|
| end = end->tagHistory();
|
| + compoundHasContentPseudo |= end->pseudoType() == CSSSelector::PseudoContent;
|
| + }
|
| end->setRelation(combinator);
|
| - if (selector->pseudoType() == CSSSelector::PseudoContent)
|
| + if (previousCompoundHasContentPseudo)
|
| end->setRelationIsAffectedByPseudoContent();
|
| + previousCompoundHasContentPseudo = compoundHasContentPseudo;
|
| end->setTagHistory(selector.release());
|
|
|
| selector = nextSelector.release();
|
| @@ -181,7 +191,7 @@ PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeCompoundSelector(CSSPars
|
| return CSSParserSelector::create(QualifiedName(namespacePrefix, elementName, namespaceURI));
|
| }
|
| prependTypeSelectorIfNeeded(namespacePrefix, elementName, compoundSelector.get());
|
| - return compoundSelector.release();
|
| + return splitCompoundAtImplicitShadowCrossingCombinator(compoundSelector.release());
|
| }
|
|
|
| PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeSimpleSelector(CSSParserTokenRange& range)
|
| @@ -576,68 +586,25 @@ void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac
|
| return;
|
| QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, namespaceURI);
|
|
|
| - if (compoundSelector->needsImplicitShadowCrossingCombinatorForMatching())
|
| - return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, compoundSelector, elementName.isNull());
|
| -
|
| - if (compoundSelector->pseudoType() == CSSSelector::PseudoContent)
|
| - return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, compoundSelector, elementName.isNull());
|
| -
|
| - // *:host never matches, so we can't discard the * otherwise we can't tell the
|
| - // difference between *:host and just :host.
|
| - if (tag == anyQName() && !compoundSelector->hasHostPseudoSelector())
|
| - return;
|
| - compoundSelector->prependTagSelector(tag, elementName.isNull());
|
| -}
|
| -
|
| -void CSSSelectorParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(const QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit)
|
| -{
|
| - CSSParserSelector* lastShadowPseudo = specifiers;
|
| - CSSParserSelector* history = specifiers;
|
| - while (history->tagHistory()) {
|
| - history = history->tagHistory();
|
| - if (history->needsImplicitShadowCrossingCombinatorForMatching()
|
| - || history->hasImplicitShadowCrossingCombinatorForMatching()) {
|
| - lastShadowPseudo = history;
|
| - }
|
| - }
|
| -
|
| - if (lastShadowPseudo->tagHistory()) {
|
| - ASSERT(lastShadowPseudo->hasImplicitShadowCrossingCombinatorForMatching());
|
| - if (tag != anyQName())
|
| - lastShadowPseudo->tagHistory()->prependTagSelector(tag, tagIsImplicit);
|
| - return;
|
| - }
|
| -
|
| - // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
|
| - // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
|
| - OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(tag);
|
| - lastShadowPseudo->setTagHistory(elementNameSelector.release());
|
| - lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo);
|
| + // *:host/*:host-context never matches, so we can't discard the *,
|
| + // otherwise we can't tell the difference between *:host and just :host.
|
| + //
|
| + // Also, selectors where we use a ShadowPseudo combinator between the
|
| + // element and the pseudo element for matching (custom pseudo elements,
|
| + // ::cue, ::shadow), we need a universal selector to set the combinator
|
| + // (relation) on in the cases where there are no simple selectors preceding
|
| + // the pseudo element.
|
| + if (tag != anyQName() || compoundSelector->isHostPseudoSelector() || compoundSelector->needsImplicitShadowCrossingCombinatorForMatching())
|
| + compoundSelector->prependTagSelector(tag, elementName.isNull());
|
| }
|
|
|
| -void CSSSelectorParser::rewriteSpecifiersWithElementNameForContentPseudoElement(const QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit)
|
| +PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(PassOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpleSelector)
|
| {
|
| - CSSParserSelector* last = specifiers;
|
| - CSSParserSelector* history = specifiers;
|
| - while (history->tagHistory()) {
|
| - history = history->tagHistory();
|
| - if (history->pseudoType() == CSSSelector::PseudoContent || history->relationIsAffectedByPseudoContent())
|
| - last = history;
|
| - }
|
| -
|
| - if (last->tagHistory()) {
|
| - if (tag != anyQName())
|
| - last->tagHistory()->prependTagSelector(tag, tagIsImplicit);
|
| - return;
|
| - }
|
| -
|
| - // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo combinator has to be used.
|
| - // We therefore create a new Selector with that combinator here in any case, even if matching any (host) element in any namespace (i.e. '*').
|
| - OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(tag);
|
| - last->setTagHistory(elementNameSelector.release());
|
| + compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector);
|
| + return compoundSelector;
|
| }
|
|
|
| -PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(PassOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpleSelector)
|
| +PassOwnPtr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCrossingCombinator(PassOwnPtr<CSSParserSelector> compoundSelector)
|
| {
|
| // The tagHistory is a linked list that stores combinator separated compound selectors
|
| // from right-to-left. Yet, within a single compound selector, stores the simple selectors
|
| @@ -651,40 +618,18 @@ PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas
|
| // the selector parser as a single compound selector.
|
| //
|
| // Example: input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input, #x ]
|
| - //
|
| - // ::content is kept at the end of the compound in order easily know when to call
|
| - // setRelationIsAffectedByPseudoContent.
|
| - //
|
| - // We are currently not dropping selectors containing multiple instances of ::content,
|
| - // ::shadow, ::cue, and custom pseudo elements in arbitrary order. There are known
|
| - // issues like crbug.com/478563
|
| - //
|
| - // TODO(rune@opera.com): We should try to remove the need for the re-ordering tricks
|
| - // below and in the remaining rewrite* methods by using a more suitable storage
|
| - // structure in CSSSelectorParser.
|
| - //
|
| - // The code below is to keep ::content at the end of the compound, and to keep the
|
| - // tagHistory order correct for implicit ShadowPseudo and juggling multiple (two?)
|
| - // compounds.
|
|
|
| - CSSSelector::Relation relation = CSSSelector::SubSelector;
|
| + CSSParserSelector* splitAfter = compoundSelector.get();
|
|
|
| - if (simpleSelector->needsImplicitShadowCrossingCombinatorForMatching() || simpleSelector->pseudoType() == CSSSelector::PseudoContent) {
|
| - if (simpleSelector->needsImplicitShadowCrossingCombinatorForMatching())
|
| - relation = CSSSelector::ShadowPseudo;
|
| - simpleSelector->appendTagHistory(relation, compoundSelector);
|
| - return simpleSelector;
|
| - }
|
| - if (compoundSelector->needsImplicitShadowCrossingCombinatorForMatching() || compoundSelector->pseudoType() == CSSSelector::PseudoContent) {
|
| - if (compoundSelector->needsImplicitShadowCrossingCombinatorForMatching())
|
| - relation = CSSSelector::ShadowPseudo;
|
| - compoundSelector->insertTagHistory(CSSSelector::SubSelector, simpleSelector, relation);
|
| + while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitShadowCrossingCombinatorForMatching())
|
| + splitAfter = splitAfter->tagHistory();
|
| +
|
| + if (!splitAfter || !splitAfter->tagHistory())
|
| return compoundSelector;
|
| - }
|
|
|
| - // All other simple selectors are added to the end of the compound.
|
| - compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector);
|
| - return compoundSelector;
|
| + OwnPtr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory();
|
| + secondCompound->appendTagHistory(CSSSelector::ShadowPseudo, compoundSelector);
|
| + return secondCompound.release();
|
| }
|
|
|
| } // namespace blink
|
|
|