| 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 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 { | 370 { |
| 368 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl
ock); | 371 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl
ock); |
| 369 block.consumeWhitespace(); | 372 block.consumeWhitespace(); |
| 370 if (!innerSelector || !innerSelector->isSimple() || !block.atEnd()) | 373 if (!innerSelector || !innerSelector->isSimple() || !block.atEnd()) |
| 371 return nullptr; | 374 return nullptr; |
| 372 Vector<OwnPtr<CSSParserSelector>> selectorVector; | 375 Vector<OwnPtr<CSSParserSelector>> selectorVector; |
| 373 selectorVector.append(innerSelector.release()); | 376 selectorVector.append(innerSelector.release()); |
| 374 selector->adoptSelectorVector(selectorVector); | 377 selector->adoptSelectorVector(selectorVector); |
| 375 return selector.release(); | 378 return selector.release(); |
| 376 } | 379 } |
| 380 case CSSSelector::PseudoSlotted: |
| 381 { |
| 382 DisallowPseudoElementsScope scope(this); |
| 383 |
| 384 OwnPtr<CSSParserSelector> innerSelector = consumeCompoundSelector(bl
ock); |
| 385 block.consumeWhitespace(); |
| 386 if (!innerSelector || !block.atEnd()) |
| 387 return nullptr; |
| 388 Vector<OwnPtr<CSSParserSelector>> selectorVector; |
| 389 selectorVector.append(innerSelector.release()); |
| 390 selector->adoptSelectorVector(selectorVector); |
| 391 selector->setRelationIsAffectedByPseudoSlotted(); |
| 392 return selector.release(); |
| 393 } |
| 377 case CSSSelector::PseudoLang: | 394 case CSSSelector::PseudoLang: |
| 378 { | 395 { |
| 379 // FIXME: CSS Selectors Level 4 allows :lang(*-foo) | 396 // FIXME: CSS Selectors Level 4 allows :lang(*-foo) |
| 380 const CSSParserToken& ident = block.consumeIncludingWhitespace(); | 397 const CSSParserToken& ident = block.consumeIncludingWhitespace(); |
| 381 if (ident.type() != IdentToken || !block.atEnd()) | 398 if (ident.type() != IdentToken || !block.atEnd()) |
| 382 return nullptr; | 399 return nullptr; |
| 383 selector->setArgument(ident.value()); | 400 selector->setArgument(ident.value()); |
| 384 return selector.release(); | 401 return selector.release(); |
| 385 } | 402 } |
| 386 case CSSSelector::PseudoNthChild: | 403 case CSSSelector::PseudoNthChild: |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 560 | 577 |
| 561 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& pr
efix) | 578 const AtomicString& CSSSelectorParser::determineNamespace(const AtomicString& pr
efix) |
| 562 { | 579 { |
| 563 if (!m_styleSheet) | 580 if (!m_styleSheet) |
| 564 return defaultNamespace(); | 581 return defaultNamespace(); |
| 565 return m_styleSheet->determineNamespace(prefix); | 582 return m_styleSheet->determineNamespace(prefix); |
| 566 } | 583 } |
| 567 | 584 |
| 568 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac
ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) | 585 void CSSSelectorParser::prependTypeSelectorIfNeeded(const AtomicString& namespac
ePrefix, const AtomicString& elementName, CSSParserSelector* compoundSelector) |
| 569 { | 586 { |
| 570 if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelec
tor->needsImplicitShadowCrossingCombinatorForMatching()) | 587 if (elementName.isNull() && defaultNamespace() == starAtom && !compoundSelec
tor->needsImplicitShadowCrossingCombinatorForMatching() && !compoundSelector->re
lationIsAffectedByPseudoSlotted()) |
| 571 return; | 588 return; |
| 572 | 589 |
| 573 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme
ntName; | 590 AtomicString determinedElementName = elementName.isNull() ? starAtom : eleme
ntName; |
| 574 AtomicString namespaceURI = determineNamespace(namespacePrefix); | 591 AtomicString namespaceURI = determineNamespace(namespacePrefix); |
| 575 if (namespaceURI.isNull()) | 592 if (namespaceURI.isNull()) |
| 576 return; | 593 return; |
| 577 QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, na
mespaceURI); | 594 QualifiedName tag = QualifiedName(namespacePrefix, determinedElementName, na
mespaceURI); |
| 578 | 595 |
| 579 if (compoundSelector->needsImplicitShadowCrossingCombinatorForMatching()) | 596 if (compoundSelector->needsImplicitShadowCrossingCombinatorForMatching()) |
| 580 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, compo
undSelector, elementName.isNull()); | 597 return rewriteSpecifiersWithElementNameForCustomPseudoElement(tag, compo
undSelector, elementName.isNull()); |
| 581 | 598 |
| 582 if (compoundSelector->pseudoType() == CSSSelector::PseudoContent) | 599 if (compoundSelector->pseudoType() == CSSSelector::PseudoContent || compound
Selector->pseudoType() == CSSSelector::PseudoSlotted) |
| 583 return rewriteSpecifiersWithElementNameForContentPseudoElement(tag, comp
oundSelector, elementName.isNull()); | 600 return rewriteSpecifiersWithElementNameForContentOrSlottedPseudoElement(
tag, compoundSelector, elementName.isNull()); |
| 584 | 601 |
| 585 // *:host never matches, so we can't discard the * otherwise we can't tell t
he | 602 // *:host never matches, so we can't discard the * otherwise we can't tell t
he |
| 586 // difference between *:host and just :host. | 603 // difference between *:host and just :host. |
| 587 if (tag == anyQName() && !compoundSelector->hasHostPseudoSelector()) | 604 if (tag == anyQName() && !compoundSelector->hasHostPseudoSelector()) |
| 588 return; | 605 return; |
| 589 compoundSelector->prependTagSelector(tag, elementName.isNull()); | 606 compoundSelector->prependTagSelector(tag, elementName.isNull()); |
| 590 } | 607 } |
| 591 | 608 |
| 592 void CSSSelectorParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(c
onst QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit) | 609 void CSSSelectorParser::rewriteSpecifiersWithElementNameForCustomPseudoElement(c
onst QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit) |
| 593 { | 610 { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 608 return; | 625 return; |
| 609 } | 626 } |
| 610 | 627 |
| 611 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c
ombinator has to be used. | 628 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c
ombinator has to be used. |
| 612 // We therefore create a new Selector with that combinator here in any case,
even if matching any (host) element in any namespace (i.e. '*'). | 629 // We therefore create a new Selector with that combinator here in any case,
even if matching any (host) element in any namespace (i.e. '*'). |
| 613 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta
g); | 630 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta
g); |
| 614 lastShadowPseudo->setTagHistory(elementNameSelector.release()); | 631 lastShadowPseudo->setTagHistory(elementNameSelector.release()); |
| 615 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo); | 632 lastShadowPseudo->setRelation(CSSSelector::ShadowPseudo); |
| 616 } | 633 } |
| 617 | 634 |
| 618 void CSSSelectorParser::rewriteSpecifiersWithElementNameForContentPseudoElement(
const QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImplicit) | 635 void CSSSelectorParser::rewriteSpecifiersWithElementNameForContentOrSlottedPseud
oElement(const QualifiedName& tag, CSSParserSelector* specifiers, bool tagIsImpl
icit) |
| 619 { | 636 { |
| 620 CSSParserSelector* last = specifiers; | 637 CSSParserSelector* last = specifiers; |
| 621 CSSParserSelector* history = specifiers; | 638 CSSParserSelector* history = specifiers; |
| 622 while (history->tagHistory()) { | 639 while (history->tagHistory()) { |
| 623 history = history->tagHistory(); | 640 history = history->tagHistory(); |
| 624 if (history->pseudoType() == CSSSelector::PseudoContent || history->rela
tionIsAffectedByPseudoContent()) | 641 if (history->pseudoType() == CSSSelector::PseudoContent || history->rela
tionIsAffectedByPseudoContent() |
| 642 || history->pseudoType() == CSSSelector::PseudoSlotted || history->r
elationIsAffectedByPseudoSlotted()) |
| 625 last = history; | 643 last = history; |
| 626 } | 644 } |
| 627 | 645 |
| 628 if (last->tagHistory()) { | 646 if (last->tagHistory()) { |
| 629 if (tag != anyQName()) | 647 if (tag != anyQName()) |
| 630 last->tagHistory()->prependTagSelector(tag, tagIsImplicit); | 648 last->tagHistory()->prependTagSelector(tag, tagIsImplicit); |
| 631 return; | 649 return; |
| 632 } | 650 } |
| 633 | 651 |
| 634 // For shadow-ID pseudo-elements to be correctly matched, the ShadowPseudo c
ombinator has to be used. | |
| 635 // We therefore create a new Selector with that combinator here in any case,
even if matching any (host) element in any namespace (i.e. '*'). | |
| 636 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta
g); | 652 OwnPtr<CSSParserSelector> elementNameSelector = CSSParserSelector::create(ta
g); |
| 637 last->setTagHistory(elementNameSelector.release()); | 653 last->setTagHistory(elementNameSelector.release()); |
| 654 if (last->pseudoType() == CSSSelector::PseudoSlotted) |
| 655 last->setRelation(CSSSelector::ShadowSlot); |
| 638 } | 656 } |
| 639 | 657 |
| 640 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas
sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl
eSelector) | 658 PassOwnPtr<CSSParserSelector> CSSSelectorParser::addSimpleSelectorToCompound(Pas
sOwnPtr<CSSParserSelector> compoundSelector, PassOwnPtr<CSSParserSelector> simpl
eSelector) |
| 641 { | 659 { |
| 642 // The tagHistory is a linked list that stores combinator separated compound
selectors | 660 // The tagHistory is a linked list that stores combinator separated compound
selectors |
| 643 // from right-to-left. Yet, within a single compound selector, stores the si
mple selectors | 661 // from right-to-left. Yet, within a single compound selector, stores the si
mple selectors |
| 644 // from left-to-right. | 662 // from left-to-right. |
| 645 // | 663 // |
| 646 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele
ment in the | 664 // ".a.b > div#id" is stored in a tagHistory as [div, #id, .a, .b], each ele
ment in the |
| 647 // list stored with an associated relation (combinator or SubSelector). | 665 // list stored with an associated relation (combinator or SubSelector). |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 compoundSelector->insertTagHistory(CSSSelector::SubSelector, simpleSelec
tor, relation); | 699 compoundSelector->insertTagHistory(CSSSelector::SubSelector, simpleSelec
tor, relation); |
| 682 return compoundSelector; | 700 return compoundSelector; |
| 683 } | 701 } |
| 684 | 702 |
| 685 // All other simple selectors are added to the end of the compound. | 703 // All other simple selectors are added to the end of the compound. |
| 686 compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector)
; | 704 compoundSelector->appendTagHistory(CSSSelector::SubSelector, simpleSelector)
; |
| 687 return compoundSelector; | 705 return compoundSelector; |
| 688 } | 706 } |
| 689 | 707 |
| 690 } // namespace blink | 708 } // namespace blink |
| OLD | NEW |