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