Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "core/css/parser/CSSSelectorParser.h" | 5 #include "core/css/parser/CSSSelectorParser.h" |
| 6 | 6 |
| 7 #include "core/css/CSSSelectorList.h" | 7 #include "core/css/CSSSelectorList.h" |
| 8 #include "core/css/StyleSheetContents.h" | 8 #include "core/css/StyleSheetContents.h" |
| 9 #include "core/frame/UseCounter.h" | 9 #include "core/frame/UseCounter.h" |
| 10 #include "platform/RuntimeEnabledFeatures.h" | 10 #include "platform/RuntimeEnabledFeatures.h" |
| 11 | 11 |
| 12 namespace blink { | 12 namespace blink { |
| 13 | 13 |
| 14 static void recordSelectorStats(const CSSParserContext& context, const CSSSelect orList& selectorList) | 14 static void recordSelectorStats(const CSSParserContext& context, const CSSSelect orList& selectorList) |
| 15 { | 15 { |
| 16 if (!context.useCounter()) | 16 if (!context.useCounter()) |
| 17 return; | 17 return; |
| 18 | 18 |
| 19 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) { | 19 for (const CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(*selector)) { |
| 20 for (const CSSSelector* current = selector; current ; current = current- >tagHistory()) { | 20 for (const CSSSelector* current = selector; current ; current = current- >tagHistory()) { |
| 21 UseCounter::Feature feature = UseCounter::NumberOfFeatures; | 21 UseCounter::Feature feature = UseCounter::NumberOfFeatures; |
| 22 switch (current->pseudoType()) { | 22 switch (current->pseudoType()) { |
| 23 case CSSSelector::PseudoUnresolved: | 23 case CSSSelector::PseudoUnresolved: |
| 24 feature = UseCounter::CSSSelectorPseudoUnresolved; | 24 feature = UseCounter::CSSSelectorPseudoUnresolved; |
| 25 break; | 25 break; |
| 26 case CSSSelector::PseudoSlotted: | |
| 27 feature = UseCounter::CSSSelectorPseudoSlotted; | |
| 28 break; | |
| 26 case CSSSelector::PseudoContent: | 29 case CSSSelector::PseudoContent: |
| 27 feature = UseCounter::CSSSelectorPseudoContent; | 30 feature = UseCounter::CSSSelectorPseudoContent; |
| 28 break; | 31 break; |
| 29 case CSSSelector::PseudoHost: | 32 case CSSSelector::PseudoHost: |
| 30 feature = UseCounter::CSSSelectorPseudoHost; | 33 feature = UseCounter::CSSSelectorPseudoHost; |
| 31 break; | 34 break; |
| 32 case CSSSelector::PseudoHostContext: | 35 case CSSSelector::PseudoHostContext: |
| 33 feature = UseCounter::CSSSelectorPseudoHostContext; | 36 feature = UseCounter::CSSSelectorPseudoHostContext; |
| 34 break; | 37 break; |
| 35 case CSSSelector::PseudoFullScreenAncestor: | 38 case CSSSelector::PseudoFullScreenAncestor: |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 464 { | 467 { |
| 465 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl ock); | 468 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl ock); |
| 466 block.consumeWhitespace(); | 469 block.consumeWhitespace(); |
| 467 if (!innerSelector || !innerSelector->isSimple() || !block.atEnd()) | 470 if (!innerSelector || !innerSelector->isSimple() || !block.atEnd()) |
| 468 return nullptr; | 471 return nullptr; |
| 469 Vector<OwnPtr<CSSParserSelector>> selectorVector; | 472 Vector<OwnPtr<CSSParserSelector>> selectorVector; |
| 470 selectorVector.append(innerSelector.release()); | 473 selectorVector.append(innerSelector.release()); |
| 471 selector->adoptSelectorVector(selectorVector); | 474 selector->adoptSelectorVector(selectorVector); |
| 472 return selector.release(); | 475 return selector.release(); |
| 473 } | 476 } |
| 477 case CSSSelector::PseudoSlotted: | |
| 478 { | |
| 479 DisallowPseudoElementsScope scope(this); | |
| 480 | |
| 481 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl ock); | |
| 482 block.consumeWhitespace(); | |
| 483 if (!innerSelector || !block.atEnd() || !RuntimeEnabledFeatures::sha dowDOMV1Enabled()) | |
| 484 return nullptr; | |
| 485 Vector<OwnPtr<CSSParserSelector>> selectorVector; | |
| 486 selectorVector.append(innerSelector.release()); | |
| 487 selector->adoptSelectorVector(selectorVector); | |
| 488 return selector.release(); | |
| 489 } | |
| 474 case CSSSelector::PseudoLang: | 490 case CSSSelector::PseudoLang: |
| 475 { | 491 { |
| 476 // FIXME: CSS Selectors Level 4 allows :lang(*-foo) | 492 // FIXME: CSS Selectors Level 4 allows :lang(*-foo) |
| 477 const CSSParserToken& ident = block.consumeIncludingWhitespace(); | 493 const CSSParserToken& ident = block.consumeIncludingWhitespace(); |
| 478 if (ident.type() != IdentToken || !block.atEnd()) | 494 if (ident.type() != IdentToken || !block.atEnd()) |
| 479 return nullptr; | 495 return nullptr; |
| 480 selector->setArgument(ident.value()); | 496 selector->setArgument(ident.value()); |
| 481 return selector.release(); | 497 return selector.release(); |
| 482 } | 498 } |
| 483 case CSSSelector::PseudoNthChild: | 499 case CSSSelector::PseudoNthChild: |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 657 | 673 |
| 658 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& pr efix) | 674 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& pr efix) |
| 659 { | 675 { |
| 660 if (!m_styleSheet) | 676 if (!m_styleSheet) |
| 661 return defaultNamespace(); | 677 return defaultNamespace(); |
| 662 return m_styleSheet->determineNamespace(prefix); | 678 return m_styleSheet->determineNamespace(prefix); |
| 663 } | 679 } |
| 664 | 680 |
| 665 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) | 681 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) |
| 666 { | 682 { |
| 667 if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelec tor->needsImplicitShadowCrossingCombinatorForMatching()) | 683 if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelec tor->needsImplicitShadowCrossingCombinatorForMatching() && compoundSelector->pse udoType() != CSSSelector::PseudoSlotted) |
| 668 return; | 684 return; |
| 669 | 685 |
| 670 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme ntName; | 686 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme ntName; |
| 671 AtomicString namespaceURI = determineNamespace(namespacePrefix); | 687 AtomicString namespaceURI = determineNamespace(namespacePrefix); |
| 672 if (namespaceURI.isNull()) { | 688 if (namespaceURI.isNull()) { |
| 673 m_failedParsing = true; | 689 m_failedParsing = true; |
| 674 return; | 690 return; |
| 675 } | 691 } |
| 676 QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, na mespaceURI); | 692 QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, na mespaceURI); |
| 677 | 693 |
| 678 // *:host/*:host-context never matches, so we can't discard the *, | 694 // *:host/*:host-context never matches, so we can't discard the *, |
| 679 // otherwise we can't tell the difference between *:host and just :host. | 695 // otherwise we can't tell the difference between *:host and just :host. |
| 680 // | 696 // |
| 681 // Also, selectors where we use a ShadowPseudo combinator between the | 697 // Also, selectors where we use a ShadowPseudo combinator between the |
| 682 // element and the pseudo element for matching (custom pseudo elements, | 698 // element and the pseudo element for matching (custom pseudo elements, |
| 683 // ::cue, ::shadow), we need a universal selector to set the combinator | 699 // ::cue, ::shadow), we need a universal selector to set the combinator |
| 684 // (relation) on in the cases where there are no simple selectors preceding | 700 // (relation) on in the cases where there are no simple selectors preceding |
| 685 // the pseudo element. | 701 // the pseudo element. |
| 686 if (tag != anyQName() || compoundSelector->isHostPseudoSelector() || compoun dSelector->needsImplicitShadowCrossingCombinatorForMatching()) | 702 if (tag != anyQName() || compoundSelector->isHostPseudoSelector() || compoun dSelector->needsImplicitShadowCrossingCombinatorForMatching() || compoundSelecto r->pseudoType() == CSSSelector::PseudoSlotted) |
| 687 compoundSelector->prependTagSelector(tag, elementName.isNull()); | 703 compoundSelector->prependTagSelector(tag, elementName.isNull()); |
| 688 } | 704 } |
| 689 | 705 |
| 690 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl eSelector) | 706 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl eSelector) |
| 691 { | 707 { |
| 692 compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector) ; | 708 compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector) ; |
| 693 return compoundSelector; | 709 return compoundSelector; |
| 694 } | 710 } |
| 695 | 711 |
| 696 PassOwnPtr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCr ossingCombinator(PassOwnPtr<CSSParserSelector> compoundSelector) | 712 PassOwnPtr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCr ossingCombinator(PassOwnPtr<CSSParserSelector> compoundSelector) |
| 697 { | 713 { |
| 698 // The tagHistory is a linked list that stores combinator separated compound selectors | 714 // The tagHistory is a linked list that stores combinator separated compound selectors |
| 699 // from right-to-left. Yet, within a single compound selector, stores the si mple selectors | 715 // from right-to-left. Yet, within a single compound selector, stores the si mple selectors |
| 700 // from left-to-right. | 716 // from left-to-right. |
| 701 // | 717 // |
| 702 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele ment in the | 718 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele ment in the |
| 703 // list stored with an associated relation (combinator or SubSelector). | 719 // list stored with an associated relation (combinator or SubSelector). |
| 704 // | 720 // |
| 705 // ::cue, ::shadow, and custom pseudo elements have an implicit ShadowPseudo combinator | 721 // ::cue, ::shadow, and custom pseudo elements have an implicit ShadowPseudo combinator |
| 706 // to their left, which really makes for a new compound selector, yet it's c onsumed by | 722 // to their left, which really makes for a new compound selector, yet it's c onsumed by |
| 707 // the selector parser as a single compound selector. | 723 // the selector parser as a single compound selector. |
| 708 // | 724 // |
| 709 // Example: input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input , #x ] | 725 // Example: input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input , #x ] |
| 710 | 726 // |
| 727 // Likewise, ::slotted() pseudo element has an implicit ShadowSlot combinato r to its left | |
| 728 // for finding matching slot element in other TreeScope. | |
| 729 // | |
| 730 // Example: slot[name=foo]::slotted(div) -> [ ::slotted(div), slot, [name=fo o] ] | |
| 711 CSSParserSelector* splitAfter = compoundSelector.get(); | 731 CSSParserSelector* splitAfter = compoundSelector.get(); |
| 712 | 732 |
| 713 while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitS hadowCrossingCombinatorForMatching()) | 733 while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitS hadowCrossingCombinatorForMatching() && splitAfter->tagHistory()->pseudoType() ! = CSSSelector::PseudoSlotted) |
|
rune
2016/01/19 09:16:09
You may move the PseudoSlotted into needsImplicitS
kochi
2016/01/19 11:09:12
Done.
| |
| 714 splitAfter = splitAfter->tagHistory(); | 734 splitAfter = splitAfter->tagHistory(); |
| 715 | 735 |
| 716 if (!splitAfter || !splitAfter->tagHistory()) | 736 if (!splitAfter || !splitAfter->tagHistory()) |
| 717 return compoundSelector; | 737 return compoundSelector; |
| 718 | 738 |
| 719 OwnPtr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory(); | 739 OwnPtr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory(); |
| 720 secondCompound->appendTagHistory(CSSSelector::ShadowPseudo, compoundSelector ); | 740 secondCompound->appendTagHistory(secondCompound->pseudoType() == CSSSelector ::PseudoSlotted ? CSSSelector::ShadowSlot : CSSSelector::ShadowPseudo, compoundS elector); |
| 721 return secondCompound.release(); | 741 return secondCompound.release(); |
| 722 } | 742 } |
| 723 | 743 |
| 724 } // namespace blink | 744 } // namespace blink |
| OLD | NEW |