Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp

Issue 1523843004: Add support for new CSS ::slotted() pseudo element (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase / fix comments for tests (FYI) Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698