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 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
492 { | 495 { |
493 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl
ock); | 496 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl
ock); |
494 block.consumeWhitespace(); | 497 block.consumeWhitespace(); |
495 if (!innerSelector || !innerSelector->isSimple() || !block.atEnd()) | 498 if (!innerSelector || !innerSelector->isSimple() || !block.atEnd()) |
496 return nullptr; | 499 return nullptr; |
497 Vector<OwnPtr<CSSParserSelector>> selectorVector; | 500 Vector<OwnPtr<CSSParserSelector>> selectorVector; |
498 selectorVector.append(innerSelector.release()); | 501 selectorVector.append(innerSelector.release()); |
499 selector->adoptSelectorVector(selectorVector); | 502 selector->adoptSelectorVector(selectorVector); |
500 return selector.release(); | 503 return selector.release(); |
501 } | 504 } |
| 505 case CSSSelector::PseudoSlotted: |
| 506 { |
| 507 DisallowPseudoElementsScope scope(this); |
| 508 |
| 509 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl
ock); |
| 510 block.consumeWhitespace(); |
| 511 if (!innerSelector || !block.atEnd() || !RuntimeEnabledFeatures::sha
dowDOMV1Enabled()) |
| 512 return nullptr; |
| 513 Vector<OwnPtr<CSSParserSelector>> selectorVector; |
| 514 selectorVector.append(innerSelector.release()); |
| 515 selector->adoptSelectorVector(selectorVector); |
| 516 return selector.release(); |
| 517 } |
502 case CSSSelector::PseudoLang: | 518 case CSSSelector::PseudoLang: |
503 { | 519 { |
504 // FIXME: CSS Selectors Level 4 allows :lang(*-foo) | 520 // FIXME: CSS Selectors Level 4 allows :lang(*-foo) |
505 const CSSParserToken& ident = block.consumeIncludingWhitespace(); | 521 const CSSParserToken& ident = block.consumeIncludingWhitespace(); |
506 if (ident.type() != IdentToken || !block.atEnd()) | 522 if (ident.type() != IdentToken || !block.atEnd()) |
507 return nullptr; | 523 return nullptr; |
508 selector->setArgument(ident.value()); | 524 selector->setArgument(ident.value()); |
509 return selector.release(); | 525 return selector.release(); |
510 } | 526 } |
511 case CSSSelector::PseudoNthChild: | 527 case CSSSelector::PseudoNthChild: |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
685 | 701 |
686 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& pr
efix) | 702 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& pr
efix) |
687 { | 703 { |
688 if (!m_styleSheet) | 704 if (!m_styleSheet) |
689 return defaultNamespace(); | 705 return defaultNamespace(); |
690 return m_styleSheet->determineNamespace(prefix); | 706 return m_styleSheet->determineNamespace(prefix); |
691 } | 707 } |
692 | 708 |
693 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac
ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) | 709 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac
ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) |
694 { | 710 { |
695 if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelec
tor->needsImplicitShadowCrossingCombinatorForMatching()) | 711 if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelec
tor->needsImplicitShadowCombinatorForMatching()) |
696 return; | 712 return; |
697 | 713 |
698 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme
ntName; | 714 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme
ntName; |
699 AtomicString namespaceURI = determineNamespace(namespacePrefix); | 715 AtomicString namespaceURI = determineNamespace(namespacePrefix); |
700 if (namespaceURI.isNull()) { | 716 if (namespaceURI.isNull()) { |
701 m_failedParsing = true; | 717 m_failedParsing = true; |
702 return; | 718 return; |
703 } | 719 } |
704 QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, na
mespaceURI); | 720 QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, na
mespaceURI); |
705 | 721 |
706 // *:host/*:host-context never matches, so we can't discard the *, | 722 // *:host/*:host-context never matches, so we can't discard the *, |
707 // otherwise we can't tell the difference between *:host and just :host. | 723 // otherwise we can't tell the difference between *:host and just :host. |
708 // | 724 // |
709 // Also, selectors where we use a ShadowPseudo combinator between the | 725 // Also, selectors where we use a ShadowPseudo combinator between the |
710 // element and the pseudo element for matching (custom pseudo elements, | 726 // element and the pseudo element for matching (custom pseudo elements, |
711 // ::cue, ::shadow), we need a universal selector to set the combinator | 727 // ::cue, ::shadow), we need a universal selector to set the combinator |
712 // (relation) on in the cases where there are no simple selectors preceding | 728 // (relation) on in the cases where there are no simple selectors preceding |
713 // the pseudo element. | 729 // the pseudo element. |
714 if (tag != anyQName() || compoundSelector->isHostPseudoSelector() || compoun
dSelector->needsImplicitShadowCrossingCombinatorForMatching()) | 730 if (tag != anyQName() || compoundSelector->isHostPseudoSelector() || compoun
dSelector->needsImplicitShadowCombinatorForMatching()) |
715 compoundSelector->prependTagSelector(tag, elementName.isNull()); | 731 compoundSelector->prependTagSelector(tag, elementName.isNull()); |
716 } | 732 } |
717 | 733 |
718 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas
sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl
eSelector) | 734 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas
sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl
eSelector) |
719 { | 735 { |
720 compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector)
; | 736 compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector)
; |
721 return compoundSelector; | 737 return compoundSelector; |
722 } | 738 } |
723 | 739 |
724 PassOwnPtr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCr
ossingCombinator(PassOwnPtr<CSSParserSelector> compoundSelector) | 740 PassOwnPtr<CSSParserSelector> CSSSelectorParser::splitCompoundAtImplicitShadowCr
ossingCombinator(PassOwnPtr<CSSParserSelector> compoundSelector) |
725 { | 741 { |
726 // The tagHistory is a linked list that stores combinator separated compound
selectors | 742 // The tagHistory is a linked list that stores combinator separated compound
selectors |
727 // from right-to-left. Yet, within a single compound selector, stores the si
mple selectors | 743 // from right-to-left. Yet, within a single compound selector, stores the si
mple selectors |
728 // from left-to-right. | 744 // from left-to-right. |
729 // | 745 // |
730 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele
ment in the | 746 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele
ment in the |
731 // list stored with an associated relation (combinator or SubSelector). | 747 // list stored with an associated relation (combinator or SubSelector). |
732 // | 748 // |
733 // ::cue, ::shadow, and custom pseudo elements have an implicit ShadowPseudo
combinator | 749 // ::cue, ::shadow, and custom pseudo elements have an implicit ShadowPseudo
combinator |
734 // to their left, which really makes for a new compound selector, yet it's c
onsumed by | 750 // to their left, which really makes for a new compound selector, yet it's c
onsumed by |
735 // the selector parser as a single compound selector. | 751 // the selector parser as a single compound selector. |
736 // | 752 // |
737 // Example: input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input
, #x ] | 753 // Example: input#x::-webkit-clear-button -> [ ::-webkit-clear-button, input
, #x ] |
738 | 754 // |
| 755 // Likewise, ::slotted() pseudo element has an implicit ShadowSlot combinato
r to its left |
| 756 // for finding matching slot element in other TreeScope. |
| 757 // |
| 758 // Example: slot[name=foo]::slotted(div) -> [ ::slotted(div), slot, [name=fo
o] ] |
739 CSSParserSelector* splitAfter = compoundSelector.get(); | 759 CSSParserSelector* splitAfter = compoundSelector.get(); |
740 | 760 |
741 while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitS
hadowCrossingCombinatorForMatching()) | 761 while (splitAfter->tagHistory() && !splitAfter->tagHistory()->needsImplicitS
hadowCombinatorForMatching()) |
742 splitAfter = splitAfter->tagHistory(); | 762 splitAfter = splitAfter->tagHistory(); |
743 | 763 |
744 if (!splitAfter || !splitAfter->tagHistory()) | 764 if (!splitAfter || !splitAfter->tagHistory()) |
745 return compoundSelector; | 765 return compoundSelector; |
746 | 766 |
747 OwnPtr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory(); | 767 OwnPtr<CSSParserSelector> secondCompound = splitAfter->releaseTagHistory(); |
748 secondCompound->appendTagHistory(CSSSelector::ShadowPseudo, compoundSelector
); | 768 secondCompound->appendTagHistory(secondCompound->pseudoType() == CSSSelector
::PseudoSlotted ? CSSSelector::ShadowSlot : CSSSelector::ShadowPseudo, compoundS
elector); |
749 return secondCompound.release(); | 769 return secondCompound.release(); |
750 } | 770 } |
751 | 771 |
752 } // namespace blink | 772 } // namespace blink |
OLD | NEW |